blob: 5b705e40c65af30213334fb4778c3d7387975cf1 [file] [log] [blame]
Armin Ronacher07bc6842008-03-31 14:18:49 +02001# -*- coding: utf-8 -*-
2"""
Armin Ronacher82b3f3d2008-03-31 20:01:08 +02003 jinja2.environment
4 ~~~~~~~~~~~~~~~~~~
Armin Ronacher07bc6842008-03-31 14:18:49 +02005
6 Provides a class that holds runtime and parsing time options.
7
8 :copyright: 2007 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
10"""
Armin Ronacherba3757b2008-04-16 19:43:16 +020011import sys
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020012from jinja2.lexer import Lexer
Armin Ronacher05530932008-04-20 13:27:49 +020013from jinja2.parser import Parser
Armin Ronacherbcb7c532008-04-11 16:30:34 +020014from jinja2.optimizer import optimize
15from jinja2.compiler import generate
Armin Ronacherc63243e2008-04-14 22:53:58 +020016from jinja2.runtime import Undefined
Armin Ronacherba3757b2008-04-16 19:43:16 +020017from jinja2.debug import translate_exception
Armin Ronacherf59bac22008-04-20 13:11:43 +020018from jinja2.utils import import_string
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020019from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
Armin Ronacher07bc6842008-03-31 14:18:49 +020020
21
22class Environment(object):
Armin Ronacher8edbe492008-04-10 20:43:43 +020023 """The Jinja environment.
Armin Ronacher07bc6842008-03-31 14:18:49 +020024
25 The core component of Jinja is the `Environment`. It contains
26 important shared variables like configuration, filters, tests,
27 globals and others.
28 """
29
Armin Ronacherc63243e2008-04-14 22:53:58 +020030 #: if this environment is sandboxed. Modifying this variable won't make
31 #: the environment sandboxed though. For a real sandboxed environment
32 #: have a look at jinja2.sandbox
33 sandboxed = False
34
Armin Ronacher07bc6842008-03-31 14:18:49 +020035 def __init__(self,
36 block_start_string='{%',
37 block_end_string='%}',
38 variable_start_string='{{',
39 variable_end_string='}}',
40 comment_start_string='{#',
41 comment_end_string='#}',
Armin Ronacherbf7c4ad2008-04-12 12:02:36 +020042 line_statement_prefix=None,
Armin Ronacher07bc6842008-03-31 14:18:49 +020043 trim_blocks=False,
Armin Ronacherfed44b52008-04-13 19:42:53 +020044 optimized=True,
Armin Ronacherc63243e2008-04-14 22:53:58 +020045 undefined=Undefined,
Armin Ronacher18c6ca02008-04-17 10:03:29 +020046 loader=None,
Armin Ronacher05530932008-04-20 13:27:49 +020047 extensions=(),
Armin Ronacher18c6ca02008-04-17 10:03:29 +020048 finalize=unicode):
Armin Ronacher8edbe492008-04-10 20:43:43 +020049 """Here the possible initialization parameters:
Armin Ronacher07bc6842008-03-31 14:18:49 +020050
51 ========================= ============================================
52 `block_start_string` the string marking the begin of a block.
53 this defaults to ``'{%'``.
54 `block_end_string` the string marking the end of a block.
55 defaults to ``'%}'``.
56 `variable_start_string` the string marking the begin of a print
57 statement. defaults to ``'{{'``.
58 `comment_start_string` the string marking the begin of a
59 comment. defaults to ``'{#'``.
60 `comment_end_string` the string marking the end of a comment.
61 defaults to ``'#}'``.
Armin Ronacherbf7c4ad2008-04-12 12:02:36 +020062 `line_statement_prefix` If given and a string, this will be used as
63 prefix for line based statements. See the
64 documentation for more details.
Armin Ronacher07bc6842008-03-31 14:18:49 +020065 `trim_blocks` If this is set to ``True`` the first newline
66 after a block is removed (block, not
67 variable tag!). Defaults to ``False``.
Armin Ronacherfed44b52008-04-13 19:42:53 +020068 `optimized` should the optimizer be enabled? Default is
69 ``True``.
Armin Ronacherc63243e2008-04-14 22:53:58 +020070 `undefined` a subclass of `Undefined` that is used to
71 represent undefined variables.
Armin Ronacherbcb7c532008-04-11 16:30:34 +020072 `loader` the loader which should be used.
Armin Ronacher05530932008-04-20 13:27:49 +020073 `extensions` List of Jinja extensions to use.
Armin Ronacherf59bac22008-04-20 13:11:43 +020074 `finalize` A callable that finalizes the variable. Per
75 default this is `unicode`, other useful
76 builtin finalizers are `escape`.
Armin Ronacher07bc6842008-03-31 14:18:49 +020077 ========================= ============================================
78 """
Armin Ronacher2e9396b2008-04-16 14:21:57 +020079
80 # santity checks
Armin Ronacherc63243e2008-04-14 22:53:58 +020081 assert issubclass(undefined, Undefined), 'undefined must be ' \
82 'a subclass of undefined because filters depend on it.'
Armin Ronacher2e9396b2008-04-16 14:21:57 +020083 assert block_start_string != variable_start_string != \
84 comment_start_string, 'block, variable and comment ' \
85 'start strings must be different'
Armin Ronacher07bc6842008-03-31 14:18:49 +020086
87 # lexer / parser information
88 self.block_start_string = block_start_string
89 self.block_end_string = block_end_string
90 self.variable_start_string = variable_start_string
91 self.variable_end_string = variable_end_string
92 self.comment_start_string = comment_start_string
93 self.comment_end_string = comment_end_string
Armin Ronacherbf7c4ad2008-04-12 12:02:36 +020094 self.line_statement_prefix = line_statement_prefix
Armin Ronacher07bc6842008-03-31 14:18:49 +020095 self.trim_blocks = trim_blocks
Armin Ronacher05530932008-04-20 13:27:49 +020096 self.extensions = []
97 for extension in extensions:
Armin Ronacherf59bac22008-04-20 13:11:43 +020098 if isinstance(extension, basestring):
99 extension = import_string(extension)
Armin Ronacher05530932008-04-20 13:27:49 +0200100 self.extensions.append(extension(self))
Armin Ronacherf59bac22008-04-20 13:11:43 +0200101
102 # runtime information
Armin Ronacherc63243e2008-04-14 22:53:58 +0200103 self.undefined = undefined
Armin Ronacherfed44b52008-04-13 19:42:53 +0200104 self.optimized = optimized
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200105 self.finalize = finalize
Armin Ronacher07bc6842008-03-31 14:18:49 +0200106
107 # defaults
108 self.filters = DEFAULT_FILTERS.copy()
109 self.tests = DEFAULT_TESTS.copy()
110 self.globals = DEFAULT_NAMESPACE.copy()
Armin Ronacher05530932008-04-20 13:27:49 +0200111 for extension in self.extensions:
112 extension.update_globals(self.globals)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200113
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200114 # set the loader provided
115 self.loader = loader
116
Armin Ronacher07bc6842008-03-31 14:18:49 +0200117 # create lexer
118 self.lexer = Lexer(self)
119
Armin Ronacherc63243e2008-04-14 22:53:58 +0200120 def subscribe(self, obj, argument):
121 """Get an item or attribute of an object."""
122 try:
123 return getattr(obj, str(argument))
124 except (AttributeError, UnicodeError):
125 try:
126 return obj[argument]
127 except (TypeError, LookupError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200128 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200129
Armin Ronacherba3757b2008-04-16 19:43:16 +0200130 def parse(self, source, name=None):
Armin Ronacher8edbe492008-04-10 20:43:43 +0200131 """Parse the sourcecode and return the abstract syntax tree. This tree
132 of nodes is used by the compiler to convert the template into
Armin Ronacher07bc6842008-03-31 14:18:49 +0200133 executable source- or bytecode.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200134 """
Armin Ronacher9a822052008-04-17 18:44:07 +0200135 return Parser(self, source, name).parse()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200136
Armin Ronacherba3757b2008-04-16 19:43:16 +0200137 def lex(self, source, name=None):
Armin Ronacher8edbe492008-04-10 20:43:43 +0200138 """Lex the given sourcecode and return a generator that yields tokens.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200139 The stream returned is not usable for Jinja but can be used if
140 Jinja templates should be processed by other tools (for example
141 syntax highlighting etc)
142
143 The tuples are returned in the form ``(lineno, token, value)``.
144 """
Armin Ronacherba3757b2008-04-16 19:43:16 +0200145 return self.lexer.tokeniter(source, name)
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200146
Armin Ronacher814f6c22008-04-17 15:52:23 +0200147 def compile(self, source, name=None, filename=None, globals=None,
148 raw=False):
Armin Ronacher68f77672008-04-17 11:50:39 +0200149 """Compile a node or source. The name is the load name of the
150 template after it was joined using `join_path` if necessary,
151 filename is the estimated filename of the template on the file
152 system. If the template came from a database or memory this
153 can be omitted.
154 """
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200155 if isinstance(source, basestring):
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200156 source = self.parse(source, name)
Armin Ronacherfed44b52008-04-13 19:42:53 +0200157 if self.optimized:
158 node = optimize(source, self, globals or {})
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200159 source = generate(node, self, name, filename)
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200160 if raw:
161 return source
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200162 if filename is None:
Armin Ronacher68f77672008-04-17 11:50:39 +0200163 filename = '<template>'
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200164 elif isinstance(filename, unicode):
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200165 filename = filename.encode('utf-8')
166 return compile(source, filename, 'exec')
167
168 def join_path(self, template, parent):
169 """Join a template with the parent. By default all the lookups are
170 relative to the loader root, but if the paths should be relative this
171 function can be used to calculate the real filename."""
172 return template
173
Armin Ronacherfed44b52008-04-13 19:42:53 +0200174 def get_template(self, name, parent=None, globals=None):
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200175 """Load a template."""
176 if self.loader is None:
177 raise TypeError('no loader for this environment specified')
178 if parent is not None:
179 name = self.join_path(name, parent)
Armin Ronacherfed44b52008-04-13 19:42:53 +0200180 globals = self.make_globals(globals)
181 return self.loader.load(self, name, globals)
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200182
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200183 def from_string(self, source, globals=None):
Armin Ronacher46f5f982008-04-11 16:40:09 +0200184 """Load a template from a string."""
Armin Ronacherfed44b52008-04-13 19:42:53 +0200185 globals = self.make_globals(globals)
Armin Ronacher8e8d0712008-04-16 23:10:49 +0200186 return Template(self, self.compile(source, globals=globals),
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200187 globals)
Armin Ronacherfed44b52008-04-13 19:42:53 +0200188
189 def make_globals(self, d):
190 """Return a dict for the globals."""
191 if d is None:
192 return self.globals
193 return dict(self.globals, **d)
Armin Ronacher46f5f982008-04-11 16:40:09 +0200194
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200195
196class Template(object):
197 """Represents a template."""
198
Armin Ronacher814f6c22008-04-17 15:52:23 +0200199 def __init__(self, environment, code, globals, uptodate=None):
Armin Ronacherf41d1392008-04-18 16:41:52 +0200200 namespace = {
201 'environment': environment,
202 '__jinja_template__': self
203 }
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200204 exec code in namespace
205 self.environment = environment
Armin Ronacherba3757b2008-04-16 19:43:16 +0200206 self.name = namespace['name']
207 self.filename = code.co_filename
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200208 self.root_render_func = namespace['root']
209 self.blocks = namespace['blocks']
Armin Ronacherfed44b52008-04-13 19:42:53 +0200210 self.globals = globals
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200211
Armin Ronacherf41d1392008-04-18 16:41:52 +0200212 # debug and loader helpers
Armin Ronacherba3757b2008-04-16 19:43:16 +0200213 self._get_debug_info = namespace['get_debug_info']
Armin Ronacher814f6c22008-04-17 15:52:23 +0200214 self._uptodate = uptodate
Armin Ronacherba3757b2008-04-16 19:43:16 +0200215
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200216 def render(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200217 """Render the template into a string."""
Armin Ronacherf41d1392008-04-18 16:41:52 +0200218 try:
219 return u''.join(self.generate(*args, **kwargs))
220 except:
221 # hide the `generate` frame
222 exc_type, exc_value, tb = sys.exc_info()
223 raise exc_type, exc_value, tb.tb_next
Armin Ronacherbcb7c532008-04-11 16:30:34 +0200224
225 def stream(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200226 """Return a `TemplateStream` that generates the template."""
Armin Ronacherf41d1392008-04-18 16:41:52 +0200227 try:
228 return TemplateStream(self.generate(*args, **kwargs))
229 except:
230 # hide the `generate` frame
231 exc_type, exc_value, tb = sys.exc_info()
232 raise exc_type, exc_value, tb.tb_next
Armin Ronacherfed44b52008-04-13 19:42:53 +0200233
234 def generate(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200235 """Return a generator that generates the template."""
Armin Ronacherfed44b52008-04-13 19:42:53 +0200236 # assemble the context
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200237 context = dict(*args, **kwargs)
Armin Ronacherfed44b52008-04-13 19:42:53 +0200238
239 # if the environment is using the optimizer locals may never
240 # override globals as optimizations might have happened
241 # depending on values of certain globals. This assertion goes
242 # away if the python interpreter is started with -O
243 if __debug__ and self.environment.optimized:
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200244 overrides = set(context) & set(self.globals)
Armin Ronacherfed44b52008-04-13 19:42:53 +0200245 if overrides:
246 plural = len(overrides) != 1 and 's' or ''
247 raise AssertionError('the per template variable%s %s '
248 'override%s global variable%s. '
249 'With an enabled optimizer this '
250 'will lead to unexpected results.' %
251 (plural, ', '.join(overrides), plural or ' a', plural))
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200252 gen = self.root_render_func(dict(self.globals, **context))
253 # skip the first item which is a reference to the context
Armin Ronacherf059ec12008-04-11 22:21:00 +0200254 gen.next()
Armin Ronacherba3757b2008-04-16 19:43:16 +0200255
256 try:
257 for event in gen:
258 yield event
259 except:
260 exc_info = translate_exception(sys.exc_info())
261 raise exc_info[0], exc_info[1], exc_info[2]
262
263 def get_corresponding_lineno(self, lineno):
264 """Return the source line number of a line number in the
265 generated bytecode as they are not in sync.
266 """
267 for template_line, code_line in reversed(self._get_debug_info()):
268 if code_line <= lineno:
269 return template_line
270 return 1
Armin Ronacherc63243e2008-04-14 22:53:58 +0200271
Armin Ronacher9a822052008-04-17 18:44:07 +0200272 @property
Armin Ronacher814f6c22008-04-17 15:52:23 +0200273 def is_up_to_date(self):
274 """Check if the template is still up to date."""
275 if self._uptodate is None:
276 return True
277 return self._uptodate()
278
Armin Ronacherc63243e2008-04-14 22:53:58 +0200279 def __repr__(self):
280 return '<%s %r>' % (
281 self.__class__.__name__,
282 self.name
283 )
284
285
286class TemplateStream(object):
287 """Wraps a genererator for outputing template streams."""
288
289 def __init__(self, gen):
290 self._gen = gen
291 self._next = gen.next
292 self.buffered = False
293
294 def disable_buffering(self):
295 """Disable the output buffering."""
296 self._next = self._gen.next
297 self.buffered = False
298
299 def enable_buffering(self, size=5):
300 """Enable buffering. Buffer `size` items before yielding them."""
301 if size <= 1:
302 raise ValueError('buffer size too small')
303 self.buffered = True
304
305 def buffering_next():
306 buf = []
307 c_size = 0
308 push = buf.append
309 next = self._gen.next
310
311 try:
312 while 1:
313 item = next()
314 if item:
315 push(item)
316 c_size += 1
317 if c_size >= size:
318 raise StopIteration()
319 except StopIteration:
320 if not c_size:
321 raise
322 return u''.join(buf)
323
324 self._next = buffering_next
325
326 def __iter__(self):
327 return self
328
329 def next(self):
330 return self._next()