1 # -*- coding: utf-8 -*-
6 Provides a class that holds runtime and parsing time options.
8 :copyright: 2007 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
11 from jinja2.lexer import Lexer
12 from jinja2.parser import Parser
13 from jinja2.optimizer import optimize
14 from jinja2.compiler import generate
15 from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
18 class Environment(object):
19 """The Jinja environment.
21 The core component of Jinja is the `Environment`. It contains
22 important shared variables like configuration, filters, tests,
27 block_start_string='{%',
28 block_end_string='%}',
29 variable_start_string='{{',
30 variable_end_string='}}',
31 comment_start_string='{#',
32 comment_end_string='#}',
33 line_statement_prefix=None,
37 """Here the possible initialization parameters:
39 ========================= ============================================
40 `block_start_string` the string marking the begin of a block.
41 this defaults to ``'{%'``.
42 `block_end_string` the string marking the end of a block.
44 `variable_start_string` the string marking the begin of a print
45 statement. defaults to ``'{{'``.
46 `comment_start_string` the string marking the begin of a
47 comment. defaults to ``'{#'``.
48 `comment_end_string` the string marking the end of a comment.
50 `line_statement_prefix` If given and a string, this will be used as
51 prefix for line based statements. See the
52 documentation for more details.
53 `trim_blocks` If this is set to ``True`` the first newline
54 after a block is removed (block, not
55 variable tag!). Defaults to ``False``.
56 `optimized` should the optimizer be enabled? Default is
58 `loader` the loader which should be used.
59 ========================= ============================================
62 # lexer / parser information
63 self.block_start_string = block_start_string
64 self.block_end_string = block_end_string
65 self.variable_start_string = variable_start_string
66 self.variable_end_string = variable_end_string
67 self.comment_start_string = comment_start_string
68 self.comment_end_string = comment_end_string
69 self.line_statement_prefix = line_statement_prefix
70 self.trim_blocks = trim_blocks
71 self.optimized = optimized
74 self.filters = DEFAULT_FILTERS.copy()
75 self.tests = DEFAULT_TESTS.copy()
76 self.globals = DEFAULT_NAMESPACE.copy()
78 # if no finalize function/method exists we default to unicode. The
79 # compiler check if the finalize attribute *is* unicode, if yes no
80 # finalizaion is written where it can be avoided.
81 if not hasattr(self, 'finalize'):
82 self.finalize = unicode
84 # set the loader provided
88 self.lexer = Lexer(self)
90 def parse(self, source, filename=None):
91 """Parse the sourcecode and return the abstract syntax tree. This tree
92 of nodes is used by the compiler to convert the template into
93 executable source- or bytecode.
95 parser = Parser(self, source, filename)
98 def lex(self, source, filename=None):
99 """Lex the given sourcecode and return a generator that yields tokens.
100 The stream returned is not usable for Jinja but can be used if
101 Jinja templates should be processed by other tools (for example
102 syntax highlighting etc)
104 The tuples are returned in the form ``(lineno, token, value)``.
106 return self.lexer.tokeniter(source, filename)
108 def compile(self, source, filename=None, raw=False, globals=None):
109 """Compile a node or source."""
110 if isinstance(source, basestring):
111 source = self.parse(source, filename)
113 node = optimize(source, self, globals or {})
114 source = generate(node, self, filename)
117 if isinstance(filename, unicode):
118 filename = filename.encode('utf-8')
119 return compile(source, filename, 'exec')
121 def join_path(self, template, parent):
122 """Join a template with the parent. By default all the lookups are
123 relative to the loader root, but if the paths should be relative this
124 function can be used to calculate the real filename."""
127 def get_template(self, name, parent=None, globals=None):
128 """Load a template."""
129 if self.loader is None:
130 raise TypeError('no loader for this environment specified')
131 if parent is not None:
132 name = self.join_path(name, parent)
133 globals = self.make_globals(globals)
134 return self.loader.load(self, name, globals)
136 def from_string(self, source, filename='<string>', globals=None):
137 """Load a template from a string."""
138 globals = self.make_globals(globals)
139 return Template(self, self.compile(source, filename), globals)
141 def make_globals(self, d):
142 """Return a dict for the globals."""
145 return dict(self.globals, **d)
148 class Template(object):
149 """Represents a template."""
151 def __init__(self, environment, code, globals):
152 namespace = {'environment': environment}
153 exec code in namespace
154 self.environment = environment
155 self.name = namespace['filename']
156 self.root_render_func = namespace['root']
157 self.blocks = namespace['blocks']
158 self.globals = globals
160 def render(self, *args, **kwargs):
161 return u''.join(self.generate(*args, **kwargs))
163 def stream(self, *args, **kwargs):
164 return TemplateStream(self.generate(*args, **kwargs))
166 def generate(self, *args, **kwargs):
167 # assemble the context
168 context = self.globals.copy()
169 context.update(*args, **kwargs)
171 # if the environment is using the optimizer locals may never
172 # override globals as optimizations might have happened
173 # depending on values of certain globals. This assertion goes
174 # away if the python interpreter is started with -O
175 if __debug__ and self.environment.optimized:
176 overrides = set(context) & set(self.globals)
178 plural = len(overrides) != 1 and 's' or ''
179 raise AssertionError('the per template variable%s %s '
180 'override%s global variable%s. '
181 'With an enabled optimizer this '
182 'will lead to unexpected results.' %
183 (plural, ', '.join(overrides), plural or ' a', plural))
184 gen = self.root_render_func(context)
185 # skip the first item which is a reference to the stream