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