all unittests pass, the special and dependency lookups have their own visitors now...
[jinja2.git] / jinja2 / environment.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.environment
4     ~~~~~~~~~~~~~~~~~~
5
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 """
11 import sys
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, TemplateContext, concat
17 from jinja2.debug import translate_exception
18 from jinja2.utils import import_string, LRUCache, Markup
19 from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
20
21
22 # for direct template usage we have up to ten living environments
23 _spontaneous_environments = LRUCache(10)
24
25
26 def get_spontaneous_environment(*args):
27     """Return a new spontaneus environment.  A spontaneus environment is an
28     unnamed and unaccessable (in theory) environment that is used for
29     template generated from a string and not from the file system.
30     """
31     try:
32         env = _spontaneous_environments.get(args)
33     except TypeError:
34         return Environment(*args)
35     if env is not None:
36         return env
37     _spontaneous_environments[args] = env = Environment(*args)
38     env.shared = True
39     return env
40
41
42 def template_from_code(environment, code, globals, uptodate=None,
43                        template_class=None):
44     """Generate a new template object from code.  It's used in the
45     template constructor and the loader `load` implementation.
46     """
47     t = object.__new__(template_class or environment.template_class)
48     namespace = {
49         'environment':          environment,
50         '__jinja_template__':   t
51     }
52     exec code in namespace
53     t.environment = environment
54     t.name = namespace['name']
55     t.filename = code.co_filename
56     t.root_render_func = namespace['root']
57     t.blocks = namespace['blocks']
58     t.globals = globals
59
60     # debug and loader helpers
61     t._debug_info = namespace['debug_info']
62     t._uptodate = uptodate
63
64     return t
65
66
67 class Environment(object):
68     """The Jinja environment.
69
70     The core component of Jinja is the `Environment`. It contains
71     important shared variables like configuration, filters, tests,
72     globals and others.
73     """
74
75     #: if this environment is sandboxed.  Modifying this variable won't make
76     #: the environment sandboxed though.  For a real sandboxed environment
77     #: have a look at jinja2.sandbox
78     sandboxed = False
79
80     #: shared environments have this set to `True`.  A shared environment
81     #: must not be modified
82     shared = False
83
84     def __init__(self,
85                  block_start_string='{%',
86                  block_end_string='%}',
87                  variable_start_string='{{',
88                  variable_end_string='}}',
89                  comment_start_string='{#',
90                  comment_end_string='#}',
91                  line_statement_prefix=None,
92                  trim_blocks=False,
93                  extensions=(),
94                  optimized=True,
95                  undefined=Undefined,
96                  finalize=unicode,
97                  loader=None):
98         # !!Important notice!!
99         #   The constructor accepts quite a few arguments that should be
100         #   passed by keyword rather than position.  However it's important to
101         #   not change the order of arguments because it's used at least
102         #   internally in those cases:
103         #       -   spontaneus environments (i18n extension and Template)
104         #       -   unittests
105         #   If parameter changes are required only add parameters at the end
106         #   and don't change the arguments (or the defaults!) of the arguments
107         #   up to (but excluding) loader.
108         """Here the possible initialization parameters:
109
110         ========================= ============================================
111         `block_start_string`      the string marking the begin of a block.
112                                   this defaults to ``'{%'``.
113         `block_end_string`        the string marking the end of a block.
114                                   defaults to ``'%}'``.
115         `variable_start_string`   the string marking the begin of a print
116                                   statement. defaults to ``'{{'``.
117         `comment_start_string`    the string marking the begin of a
118                                   comment. defaults to ``'{#'``.
119         `comment_end_string`      the string marking the end of a comment.
120                                   defaults to ``'#}'``.
121         `line_statement_prefix`   If given and a string, this will be used as
122                                   prefix for line based statements.  See the
123                                   documentation for more details.
124         `trim_blocks`             If this is set to ``True`` the first newline
125                                   after a block is removed (block, not
126                                   variable tag!). Defaults to ``False``.
127         `extensions`              List of Jinja extensions to use.
128         `optimized`               should the optimizer be enabled?  Default is
129                                   ``True``.
130         `undefined`               a subclass of `Undefined` that is used to
131                                   represent undefined variables.
132         `finalize`                A callable that finalizes the variable.  Per
133                                   default this is `unicode`, other useful
134                                   builtin finalizers are `escape`.
135         `loader`                  the loader which should be used.
136         ========================= ============================================
137         """
138
139         # santity checks
140         assert issubclass(undefined, Undefined), 'undefined must be ' \
141                'a subclass of undefined because filters depend on it.'
142         assert block_start_string != variable_start_string != \
143                comment_start_string, 'block, variable and comment ' \
144                'start strings must be different'
145
146         # lexer / parser information
147         self.block_start_string = block_start_string
148         self.block_end_string = block_end_string
149         self.variable_start_string = variable_start_string
150         self.variable_end_string = variable_end_string
151         self.comment_start_string = comment_start_string
152         self.comment_end_string = comment_end_string
153         self.line_statement_prefix = line_statement_prefix
154         self.trim_blocks = trim_blocks
155
156         # runtime information
157         self.undefined = undefined
158         self.optimized = optimized
159         self.finalize = finalize
160
161         # defaults
162         self.filters = DEFAULT_FILTERS.copy()
163         self.tests = DEFAULT_TESTS.copy()
164         self.globals = DEFAULT_NAMESPACE.copy()
165
166         # set the loader provided
167         self.loader = loader
168
169         # create lexer
170         self.lexer = Lexer(self)
171
172         # load extensions
173         self.extensions = []
174         for extension in extensions:
175             if isinstance(extension, basestring):
176                 extension = import_string(extension)
177             self.extensions.append(extension(self))
178
179     def subscribe(self, obj, argument):
180         """Get an item or attribute of an object."""
181         try:
182             return getattr(obj, str(argument))
183         except (AttributeError, UnicodeError):
184             try:
185                 return obj[argument]
186             except (TypeError, LookupError):
187                 return self.undefined(obj=obj, name=argument)
188
189     def parse(self, source, name=None):
190         """Parse the sourcecode and return the abstract syntax tree. This tree
191         of nodes is used by the compiler to convert the template into
192         executable source- or bytecode.
193         """
194         return Parser(self, source, name).parse()
195
196     def lex(self, source, name=None):
197         """Lex the given sourcecode and return a generator that yields tokens.
198         The stream returned is not usable for Jinja but can be used if
199         Jinja templates should be processed by other tools (for example
200         syntax highlighting etc)
201
202         The tuples are returned in the form ``(lineno, token, value)``.
203         """
204         return self.lexer.tokeniter(source, name)
205
206     def compile(self, source, name=None, filename=None, globals=None,
207                 raw=False):
208         """Compile a node or source.  The name is the load name of the
209         template after it was joined using `join_path` if necessary,
210         filename is the estimated filename of the template on the file
211         system.  If the template came from a database or memory this
212         can be omitted.
213         """
214         if isinstance(source, basestring):
215             source = self.parse(source, name)
216         if self.optimized:
217             node = optimize(source, self, globals or {})
218         source = generate(node, self, name, filename)
219         if raw:
220             return source
221         if filename is None:
222             filename = '<template>'
223         elif isinstance(filename, unicode):
224             filename = filename.encode('utf-8')
225         return compile(source, filename, 'exec')
226
227     def join_path(self, template, parent):
228         """Join a template with the parent.  By default all the lookups are
229         relative to the loader root, but if the paths should be relative this
230         function can be used to calculate the real filename."""
231         return template
232
233     def get_template(self, name, parent=None, globals=None):
234         """Load a template."""
235         if self.loader is None:
236             raise TypeError('no loader for this environment specified')
237         if parent is not None:
238             name = self.join_path(name, parent)
239         return self.loader.load(self, name, self.make_globals(globals))
240
241     def from_string(self, source, globals=None, template_class=None):
242         """Load a template from a string."""
243         globals = self.make_globals(globals)
244         return template_from_code(self, self.compile(source, globals=globals),
245                                   globals, None, template_class)
246
247     def make_globals(self, d):
248         """Return a dict for the globals."""
249         if d is None:
250             return self.globals
251         return dict(self.globals, **d)
252
253
254 class Template(object):
255     """The central template object.  This class represents a compiled template
256     and is used to evaluate it.
257
258     Normally the template object is generated from an `Environment` but it
259     also has a constructor that makes it possible to create a template
260     instance directly using the constructor.  It takes the same arguments as
261     the environment constructor but it's not possible to specify a loader.
262
263     Every template object has a few methods and members that are guaranteed
264     to exist.  However it's important that a template object should be
265     considered immutable.  Modifications on the object are not supported.
266
267     Template objects created from the constructor rather than an environment
268     do have an `environment` attribute that points to a temporary environment
269     that is probably shared with other templates created with the constructor
270     and compatible settings.
271
272     >>> template = Template('Hello {{ name }}!')
273     >>> template.render(name='John Doe')
274     u'Hello John Doe!'
275
276     >>> stream = template.stream(name='John Doe')
277     >>> stream.next()
278     u'Hello John Doe!'
279     >>> stream.next()
280     Traceback (most recent call last):
281         ...
282     StopIteration
283     """
284
285     def __new__(cls, source,
286                 block_start_string='{%',
287                 block_end_string='%}',
288                 variable_start_string='{{',
289                 variable_end_string='}}',
290                 comment_start_string='{#',
291                 comment_end_string='#}',
292                 line_statement_prefix=None,
293                 trim_blocks=False,
294                 extensions=(),
295                 optimized=True,
296                 undefined=Undefined,
297                 finalize=unicode):
298         env = get_spontaneous_environment(
299             block_start_string, block_end_string, variable_start_string,
300             variable_end_string, comment_start_string, comment_end_string,
301             line_statement_prefix, trim_blocks, tuple(extensions), optimized,
302             undefined, finalize)
303         return env.from_string(source, template_class=cls)
304
305     def render(self, *args, **kwargs):
306         """Render the template into a string."""
307         try:
308             return concat(self.generate(*args, **kwargs))
309         except:
310             # hide the `generate` frame
311             exc_type, exc_value, tb = sys.exc_info()
312             raise exc_type, exc_value, tb.tb_next
313
314     def stream(self, *args, **kwargs):
315         """Return a `TemplateStream` that generates the template."""
316         try:
317             return TemplateStream(self.generate(*args, **kwargs))
318         except:
319             # hide the `generate` frame
320             exc_type, exc_value, tb = sys.exc_info()
321             raise exc_type, exc_value, tb.tb_next
322
323     def generate(self, *args, **kwargs):
324         """Return a generator that generates the template."""
325         # assemble the context
326         context = dict(*args, **kwargs)
327
328         # if the environment is using the optimizer locals may never
329         # override globals as optimizations might have happened
330         # depending on values of certain globals.  This assertion goes
331         # away if the python interpreter is started with -O
332         if __debug__ and self.environment.optimized:
333             overrides = set(context) & set(self.globals)
334             if overrides:
335                 plural = len(overrides) != 1 and 's' or ''
336                 raise AssertionError('the per template variable%s %s '
337                                      'override%s global variable%s. '
338                                      'With an enabled optimizer this '
339                                      'will lead to unexpected results.' %
340                     (plural, ', '.join(overrides), plural or ' a', plural))
341
342         try:
343             for event in self.root_render_func(self.new_context(context)):
344                 yield event
345         except:
346             exc_type, exc_value, tb = translate_exception(sys.exc_info())
347             raise exc_type, exc_value, tb
348
349     def new_context(self, vars=None, shared=False):
350         """Create a new template context for this template.  The vars
351         provided will be passed to the template.  Per default the globals
352         are added to the context, if shared is set to `True` the data
353         provided is used as parent namespace.  This is used to share the
354         same globals in multiple contexts without consuming more memory.
355         (This works because the context does not modify the parent dict)
356         """
357         if vars is None:
358             vars = {}
359         if shared:
360             parent = vars
361         else:
362             parent = dict(self.globals, **vars)
363         return TemplateContext(self.environment, parent, self.name,
364                                self.blocks)
365
366     def include(self, vars=None):
367         """Include this template.  When passed a template context or dict
368         the template is evaluated in that context and an `IncludedTemplate`
369         object is returned.  This object then exposes all the exported
370         variables as attributes and renders the contents of the template
371         when converted to unicode.
372         """
373         if isinstance(vars, TemplateContext):
374             context = TemplateContext(self.environment, vars.parent,
375                                       self.name, self.blocks)
376         else:
377             context = self.new_context(vars)
378         return IncludedTemplate(self, context)
379
380     def get_corresponding_lineno(self, lineno):
381         """Return the source line number of a line number in the
382         generated bytecode as they are not in sync.
383         """
384         for template_line, code_line in reversed(self.debug_info):
385             if code_line <= lineno:
386                 return template_line
387         return 1
388
389     @property
390     def is_up_to_date(self):
391         """If this variable is `False` there is a newer version available."""
392         if self._uptodate is None:
393             return True
394         return self._uptodate()
395
396     @property
397     def debug_info(self):
398         """The debug info mapping."""
399         return [tuple(map(int, x.split('='))) for x in
400                 self._debug_info.split('&')]
401
402     def __repr__(self):
403         if self.name is None:
404             name = 'memory:%x' % id(self)
405         else:
406             name = repr(self.name)
407         return '<%s %s>' % (self.__class__.__name__, name)
408
409
410 class IncludedTemplate(object):
411     """Represents an included template.  All the exported names of the
412     template are available as attributes on this object.  Additionally
413     converting it into an unicode- or bytestrings renders the contents.
414     """
415
416     def __init__(self, template, context):
417         self.__body_stream = tuple(template.root_render_func(context))
418         self.__dict__.update(context.get_exported())
419         self.__name__ = template.name
420
421     __html__ = lambda x: Markup(concat(x.__body_stream))
422     __unicode__ = lambda x: unicode(concat(x.__body_stream))
423
424     def __str__(self):
425         return unicode(self).encode('utf-8')
426
427     def __repr__(self):
428         if self.__name__ is None:
429             name = 'memory:%x' % id(self)
430         else:
431             name = repr(self.name)
432         return '<%s %s>' % (self.__class__.__name__, name)
433
434
435 class TemplateStream(object):
436     """This class wraps a generator returned from `Template.generate` so that
437     it's possible to buffer multiple elements so that it's possible to return
438     them from a WSGI application which flushes after each iteration.
439     """
440
441     def __init__(self, gen):
442         self._gen = gen
443         self._next = gen.next
444         self.buffered = False
445
446     def disable_buffering(self):
447         """Disable the output buffering."""
448         self._next = self._gen.next
449         self.buffered = False
450
451     def enable_buffering(self, size=5):
452         """Enable buffering. Buffer `size` items before yielding them."""
453         if size <= 1:
454             raise ValueError('buffer size too small')
455
456         def generator():
457             buf = []
458             c_size = 0
459             push = buf.append
460             next = self._gen.next
461
462             while 1:
463                 try:
464                     while c_size < size:
465                         push(next())
466                         c_size += 1
467                 except StopIteration:
468                     if not c_size:
469                         raise
470                 yield concat(buf)
471                 del buf[:]
472                 c_size = 0
473
474         self.buffered = True
475         self._next = generator().next
476
477     def __iter__(self):
478         return self
479
480     def next(self):
481         return self._next()
482
483
484 # hook in default template class.  if anyone reads this comment: ignore that
485 # it's possible to use custom templates ;-)
486 Environment.template_class = Template