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.
12 from jinja2.lexer import Lexer
13 from jinja2.parser import Parser
14 from jinja2.optimizer import optimize
15 from jinja2.compiler import generate
16 from jinja2.runtime import Undefined
17 from jinja2.debug import translate_exception
18 from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
21 class Environment(object):
22 """The Jinja environment.
24 The core component of Jinja is the `Environment`. It contains
25 important shared variables like configuration, filters, tests,
29 #: if this environment is sandboxed. Modifying this variable won't make
30 #: the environment sandboxed though. For a real sandboxed environment
31 #: have a look at jinja2.sandbox
35 block_start_string='{%',
36 block_end_string='%}',
37 variable_start_string='{{',
38 variable_end_string='}}',
39 comment_start_string='{#',
40 comment_end_string='#}',
41 line_statement_prefix=None,
47 """Here the possible initialization parameters:
49 ========================= ============================================
50 `block_start_string` the string marking the begin of a block.
51 this defaults to ``'{%'``.
52 `block_end_string` the string marking the end of a block.
54 `variable_start_string` the string marking the begin of a print
55 statement. defaults to ``'{{'``.
56 `comment_start_string` the string marking the begin of a
57 comment. defaults to ``'{#'``.
58 `comment_end_string` the string marking the end of a comment.
60 `line_statement_prefix` If given and a string, this will be used as
61 prefix for line based statements. See the
62 documentation for more details.
63 `trim_blocks` If this is set to ``True`` the first newline
64 after a block is removed (block, not
65 variable tag!). Defaults to ``False``.
66 `optimized` should the optimizer be enabled? Default is
68 `undefined` a subclass of `Undefined` that is used to
69 represent undefined variables.
70 `loader` the loader which should be used.
71 ========================= ============================================
75 assert issubclass(undefined, Undefined), 'undefined must be ' \
76 'a subclass of undefined because filters depend on it.'
77 assert block_start_string != variable_start_string != \
78 comment_start_string, 'block, variable and comment ' \
79 'start strings must be different'
81 # lexer / parser information
82 self.block_start_string = block_start_string
83 self.block_end_string = block_end_string
84 self.variable_start_string = variable_start_string
85 self.variable_end_string = variable_end_string
86 self.comment_start_string = comment_start_string
87 self.comment_end_string = comment_end_string
88 self.line_statement_prefix = line_statement_prefix
89 self.trim_blocks = trim_blocks
90 self.undefined = undefined
91 self.optimized = optimized
92 self.finalize = finalize
95 self.filters = DEFAULT_FILTERS.copy()
96 self.tests = DEFAULT_TESTS.copy()
97 self.globals = DEFAULT_NAMESPACE.copy()
99 # set the loader provided
103 self.lexer = Lexer(self)
105 def subscribe(self, obj, argument):
106 """Get an item or attribute of an object."""
108 return getattr(obj, str(argument))
109 except (AttributeError, UnicodeError):
112 except (TypeError, LookupError):
113 return self.undefined(obj=obj, name=argument)
115 def parse(self, source, name=None):
116 """Parse the sourcecode and return the abstract syntax tree. This tree
117 of nodes is used by the compiler to convert the template into
118 executable source- or bytecode.
120 return Parser(self, source, name).parse()
122 def lex(self, source, name=None):
123 """Lex the given sourcecode and return a generator that yields tokens.
124 The stream returned is not usable for Jinja but can be used if
125 Jinja templates should be processed by other tools (for example
126 syntax highlighting etc)
128 The tuples are returned in the form ``(lineno, token, value)``.
130 return self.lexer.tokeniter(source, name)
132 def compile(self, source, name=None, filename=None, globals=None,
134 """Compile a node or source. The name is the load name of the
135 template after it was joined using `join_path` if necessary,
136 filename is the estimated filename of the template on the file
137 system. If the template came from a database or memory this
140 if isinstance(source, basestring):
141 source = self.parse(source, name)
143 node = optimize(source, self, globals or {})
144 source = generate(node, self, name, filename)
148 filename = '<template>'
149 elif isinstance(filename, unicode):
150 filename = filename.encode('utf-8')
151 return compile(source, filename, 'exec')
153 def join_path(self, template, parent):
154 """Join a template with the parent. By default all the lookups are
155 relative to the loader root, but if the paths should be relative this
156 function can be used to calculate the real filename."""
159 def get_template(self, name, parent=None, globals=None):
160 """Load a template."""
161 if self.loader is None:
162 raise TypeError('no loader for this environment specified')
163 if parent is not None:
164 name = self.join_path(name, parent)
165 globals = self.make_globals(globals)
166 return self.loader.load(self, name, globals)
168 def from_string(self, source, globals=None):
169 """Load a template from a string."""
170 globals = self.make_globals(globals)
171 return Template(self, self.compile(source, globals=globals),
174 def make_globals(self, d):
175 """Return a dict for the globals."""
178 return dict(self.globals, **d)
181 class Template(object):
182 """Represents a template."""
184 def __init__(self, environment, code, globals, uptodate=None):
185 namespace = {'environment': environment}
186 exec code in namespace
187 self.environment = environment
188 self.name = namespace['name']
189 self.filename = code.co_filename
190 self.root_render_func = namespace['root']
191 self.blocks = namespace['blocks']
192 self.globals = globals
195 self._get_debug_info = namespace['get_debug_info']
196 self._uptodate = uptodate
197 namespace['__jinja_template__'] = self
199 def render(self, *args, **kwargs):
200 """Render the template into a string."""
201 return u''.join(self.generate(*args, **kwargs))
203 def stream(self, *args, **kwargs):
204 """Return a `TemplateStream` that generates the template."""
205 return TemplateStream(self.generate(*args, **kwargs))
207 def generate(self, *args, **kwargs):
208 """Return a generator that generates the template."""
209 # assemble the context
210 context = dict(*args, **kwargs)
212 # if the environment is using the optimizer locals may never
213 # override globals as optimizations might have happened
214 # depending on values of certain globals. This assertion goes
215 # away if the python interpreter is started with -O
216 if __debug__ and self.environment.optimized:
217 overrides = set(context) & set(self.globals)
219 plural = len(overrides) != 1 and 's' or ''
220 raise AssertionError('the per template variable%s %s '
221 'override%s global variable%s. '
222 'With an enabled optimizer this '
223 'will lead to unexpected results.' %
224 (plural, ', '.join(overrides), plural or ' a', plural))
225 gen = self.root_render_func(dict(self.globals, **context))
226 # skip the first item which is a reference to the context
233 exc_info = translate_exception(sys.exc_info())
234 raise exc_info[0], exc_info[1], exc_info[2]
236 def get_corresponding_lineno(self, lineno):
237 """Return the source line number of a line number in the
238 generated bytecode as they are not in sync.
240 for template_line, code_line in reversed(self._get_debug_info()):
241 if code_line <= lineno:
246 def is_up_to_date(self):
247 """Check if the template is still up to date."""
248 if self._uptodate is None:
250 return self._uptodate()
254 self.__class__.__name__,
259 class TemplateStream(object):
260 """Wraps a genererator for outputing template streams."""
262 def __init__(self, gen):
264 self._next = gen.next
265 self.buffered = False
267 def disable_buffering(self):
268 """Disable the output buffering."""
269 self._next = self._gen.next
270 self.buffered = False
272 def enable_buffering(self, size=5):
273 """Enable buffering. Buffer `size` items before yielding them."""
275 raise ValueError('buffer size too small')
278 def buffering_next():
282 next = self._gen.next
291 raise StopIteration()
292 except StopIteration:
297 self._next = buffering_next