87c2354606bfb316494a2ac53c86ea93ea126866
[jinja2.git] / jinja2 / runtime.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.runtime
4     ~~~~~~~~~~~~~~
5
6     Runtime helpers.
7
8     :copyright: Copyright 2008 by Armin Ronacher.
9     :license: BSD.
10 """
11 import sys
12 from itertools import chain, imap
13 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
14      concat, MethodType, FunctionType
15 from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
16      TemplateNotFound
17
18
19 # these variables are exported to the template runtime
20 __all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
21            'TemplateRuntimeError', 'missing', 'concat', 'escape',
22            'markup_join', 'unicode_join', 'TemplateNotFound']
23
24
25 #: the types we support for context functions
26 _context_function_types = (FunctionType, MethodType)
27
28
29 def markup_join(seq):
30     """Concatenation that escapes if necessary and converts to unicode."""
31     buf = []
32     iterator = imap(soft_unicode, seq)
33     for arg in iterator:
34         buf.append(arg)
35         if hasattr(arg, '__html__'):
36             return Markup(u'').join(chain(buf, iterator))
37     return concat(buf)
38
39
40 def unicode_join(seq):
41     """Simple args to unicode conversion and concatenation."""
42     return concat(imap(unicode, seq))
43
44
45 class Context(object):
46     """The template context holds the variables of a template.  It stores the
47     values passed to the template and also the names the template exports.
48     Creating instances is neither supported nor useful as it's created
49     automatically at various stages of the template evaluation and should not
50     be created by hand.
51
52     The context is immutable.  Modifications on :attr:`parent` **must not**
53     happen and modifications on :attr:`vars` are allowed from generated
54     template code only.  Template filters and global functions marked as
55     :func:`contextfunction`\s get the active context passed as first argument
56     and are allowed to access the context read-only.
57
58     The template context supports read only dict operations (`get`,
59     `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
60     `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
61     method that doesn't fail with a `KeyError` but returns an
62     :class:`Undefined` object for missing variables.
63     """
64     __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
65                  'blocks', '__weakref__')
66
67     def __init__(self, environment, parent, name, blocks):
68         self.parent = parent
69         self.vars = vars = {}
70         self.environment = environment
71         self.exported_vars = set()
72         self.name = name
73
74         # create the initial mapping of blocks.  Whenever template inheritance
75         # takes place the runtime will update this mapping with the new blocks
76         # from the template.
77         self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
78
79     def super(self, name, current):
80         """Render a parent block."""
81         try:
82             blocks = self.blocks[name]
83             index = blocks.index(current) + 1
84             blocks[index]
85         except LookupError:
86             return self.environment.undefined('there is no parent block '
87                                               'called %r.' % name,
88                                               name='super')
89         return BlockReference(name, self, blocks, index)
90
91     def get(self, key, default=None):
92         """Returns an item from the template context, if it doesn't exist
93         `default` is returned.
94         """
95         try:
96             return self[key]
97         except KeyError:
98             return default
99
100     def resolve(self, key):
101         """Looks up a variable like `__getitem__` or `get` but returns an
102         :class:`Undefined` object with the name of the name looked up.
103         """
104         if key in self.vars:
105             return self.vars[key]
106         if key in self.parent:
107             return self.parent[key]
108         return self.environment.undefined(name=key)
109
110     def get_exported(self):
111         """Get a new dict with the exported variables."""
112         return dict((k, self.vars[k]) for k in self.exported_vars)
113
114     def get_all(self):
115         """Return a copy of the complete context as dict including the
116         exported variables.
117         """
118         return dict(self.parent, **self.vars)
119
120     def call(__self, __obj, *args, **kwargs):
121         """Call the callable with the arguments and keyword arguments
122         provided but inject the active context or environment as first
123         argument if the callable is a :func:`contextfunction` or
124         :func:`environmentfunction`.
125         """
126         if __debug__:
127             __traceback_hide__ = True
128         if isinstance(__obj, _context_function_types):
129             if getattr(__obj, 'contextfunction', 0):
130                 args = (__self,) + args
131             elif getattr(__obj, 'environmentfunction', 0):
132                 args = (__self.environment,) + args
133         return __obj(*args, **kwargs)
134
135     def _all(meth):
136         proxy = lambda self: getattr(self.get_all(), meth)()
137         proxy.__doc__ = getattr(dict, meth).__doc__
138         proxy.__name__ = meth
139         return proxy
140
141     keys = _all('keys')
142     values = _all('values')
143     items = _all('items')
144     iterkeys = _all('iterkeys')
145     itervalues = _all('itervalues')
146     iteritems = _all('iteritems')
147     del _all
148
149     def __contains__(self, name):
150         return name in self.vars or name in self.parent
151
152     def __getitem__(self, key):
153         """Lookup a variable or raise `KeyError` if the variable is
154         undefined.
155         """
156         item = self.resolve(key)
157         if isinstance(item, Undefined):
158             raise KeyError(key)
159         return item
160
161     def __repr__(self):
162         return '<%s %s of %r>' % (
163             self.__class__.__name__,
164             repr(self.get_all()),
165             self.name
166         )
167
168
169 # register the context as mapping if possible
170 try:
171     from collections import Mapping
172     Mapping.register(Context)
173 except ImportError:
174     pass
175
176
177 class TemplateReference(object):
178     """The `self` in templates."""
179
180     def __init__(self, context):
181         self.__context = context
182
183     def __getitem__(self, name):
184         blocks = self.__context.blocks[name]
185         wrap = self.__context.environment.autoescape and \
186                Markup or (lambda x: x)
187         return BlockReference(name, self.__context, blocks, 0)
188
189     def __repr__(self):
190         return '<%s %r>' % (
191             self.__class__.__name__,
192             self.__context.name
193         )
194
195
196 class BlockReference(object):
197     """One block on a template reference."""
198
199     def __init__(self, name, context, stack, depth):
200         self.name = name
201         self._context = context
202         self._stack = stack
203         self._depth = depth
204
205     @property
206     def super(self):
207         """Super the block."""
208         if self._depth + 1 >= len(self._stack):
209             return self._context.environment. \
210                 undefined('there is no parent block called %r.' %
211                           self.name, name='super')
212         return BlockReference(self.name, self._context, self._stack,
213                               self._depth + 1)
214
215     def __call__(self):
216         rv = concat(self._stack[self._depth](self._context))
217         if self._context.environment.autoescape:
218             rv = Markup(rv)
219         return rv
220
221
222 class LoopContext(object):
223     """A loop context for dynamic iteration."""
224
225     def __init__(self, iterable, recurse=None):
226         self._iterator = iter(iterable)
227         self._recurse = recurse
228         self.index0 = -1
229
230         # try to get the length of the iterable early.  This must be done
231         # here because there are some broken iterators around where there
232         # __len__ is the number of iterations left (i'm looking at your
233         # listreverseiterator!).
234         try:
235             self._length = len(iterable)
236         except (TypeError, AttributeError):
237             self._length = None
238
239     def cycle(self, *args):
240         """Cycles among the arguments with the current loop index."""
241         if not args:
242             raise TypeError('no items for cycling given')
243         return args[self.index0 % len(args)]
244
245     first = property(lambda x: x.index0 == 0)
246     last = property(lambda x: x.index0 + 1 == x.length)
247     index = property(lambda x: x.index0 + 1)
248     revindex = property(lambda x: x.length - x.index0)
249     revindex0 = property(lambda x: x.length - x.index)
250
251     def __len__(self):
252         return self.length
253
254     def __iter__(self):
255         return LoopContextIterator(self)
256
257     def loop(self, iterable):
258         if self._recurse is None:
259             raise TypeError('Tried to call non recursive loop.  Maybe you '
260                             "forgot the 'recursive' modifier.")
261         return self._recurse(iterable, self._recurse)
262
263     # a nifty trick to enhance the error message if someone tried to call
264     # the the loop without or with too many arguments.
265     __call__ = loop; del loop
266
267     @property
268     def length(self):
269         if self._length is None:
270             # if was not possible to get the length of the iterator when
271             # the loop context was created (ie: iterating over a generator)
272             # we have to convert the iterable into a sequence and use the
273             # length of that.
274             iterable = tuple(self._iterator)
275             self._iterator = iter(iterable)
276             self._length = len(iterable) + self.index0 + 1
277         return self._length
278
279     def __repr__(self):
280         return '<%s %r/%r>' % (
281             self.__class__.__name__,
282             self.index,
283             self.length
284         )
285
286
287 class LoopContextIterator(object):
288     """The iterator for a loop context."""
289     __slots__ = ('context',)
290
291     def __init__(self, context):
292         self.context = context
293
294     def __iter__(self):
295         return self
296
297     def next(self):
298         ctx = self.context
299         ctx.index0 += 1
300         return ctx._iterator.next(), ctx
301
302
303 class Macro(object):
304     """Wraps a macro."""
305
306     def __init__(self, environment, func, name, arguments, defaults,
307                  catch_kwargs, catch_varargs, caller):
308         self._environment = environment
309         self._func = func
310         self._argument_count = len(arguments)
311         self.name = name
312         self.arguments = arguments
313         self.defaults = defaults
314         self.catch_kwargs = catch_kwargs
315         self.catch_varargs = catch_varargs
316         self.caller = caller
317
318     def __call__(self, *args, **kwargs):
319         arguments = []
320         for idx, name in enumerate(self.arguments):
321             try:
322                 value = args[idx]
323             except:
324                 try:
325                     value = kwargs.pop(name)
326                 except:
327                     try:
328                         value = self.defaults[idx - self._argument_count]
329                     except:
330                         value = self._environment.undefined(
331                             'parameter %r was not provided' % name, name=name)
332             arguments.append(value)
333
334         # it's important that the order of these arguments does not change
335         # if not also changed in the compiler's `function_scoping` method.
336         # the order is caller, keyword arguments, positional arguments!
337         if self.caller:
338             caller = kwargs.pop('caller', None)
339             if caller is None:
340                 caller = self._environment.undefined('No caller defined',
341                                                      name='caller')
342             arguments.append(caller)
343         if self.catch_kwargs:
344             arguments.append(kwargs)
345         elif kwargs:
346             raise TypeError('macro %r takes no keyword argument %r' %
347                             (self.name, iter(kwargs).next()))
348         if self.catch_varargs:
349             arguments.append(args[self._argument_count:])
350         elif len(args) > self._argument_count:
351             raise TypeError('macro %r takes not more than %d argument(s)' %
352                             (self.name, len(self.arguments)))
353         return self._func(*arguments)
354
355     def __repr__(self):
356         return '<%s %s>' % (
357             self.__class__.__name__,
358             self.name is None and 'anonymous' or repr(self.name)
359         )
360
361
362 class Undefined(object):
363     """The default undefined type.  This undefined type can be printed and
364     iterated over, but every other access will raise an :exc:`UndefinedError`:
365
366     >>> foo = Undefined(name='foo')
367     >>> str(foo)
368     ''
369     >>> not foo
370     True
371     >>> foo + 42
372     Traceback (most recent call last):
373       ...
374     UndefinedError: 'foo' is undefined
375     """
376     __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
377                  '_undefined_exception')
378
379     def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
380         self._undefined_hint = hint
381         self._undefined_obj = obj
382         self._undefined_name = name
383         self._undefined_exception = exc
384
385     def _fail_with_undefined_error(self, *args, **kwargs):
386         """Regular callback function for undefined objects that raises an
387         `UndefinedError` on call.
388         """
389         if self._undefined_hint is None:
390             if self._undefined_obj is None:
391                 hint = '%r is undefined' % self._undefined_name
392             elif not isinstance(self._undefined_name, basestring):
393                 hint = '%r object has no element %r' % (
394                     self._undefined_obj.__class__.__name__,
395                     self._undefined_name
396                 )
397             else:
398                 hint = '%r object has no attribute %r' % (
399                     self._undefined_obj.__class__.__name__,
400                     self._undefined_name
401                 )
402         else:
403             hint = self._undefined_hint
404         raise self._undefined_exception(hint)
405
406     __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
407     __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
408     __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
409     __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
410     __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
411         _fail_with_undefined_error
412
413     def __str__(self):
414         return unicode(self).encode('utf-8')
415
416     def __unicode__(self):
417         return u''
418
419     def __len__(self):
420         return 0
421
422     def __iter__(self):
423         if 0:
424             yield None
425
426     def __nonzero__(self):
427         return False
428
429     def __repr__(self):
430         return 'Undefined'
431
432
433 class DebugUndefined(Undefined):
434     """An undefined that returns the debug info when printed.
435
436     >>> foo = DebugUndefined(name='foo')
437     >>> str(foo)
438     '{{ foo }}'
439     >>> not foo
440     True
441     >>> foo + 42
442     Traceback (most recent call last):
443       ...
444     UndefinedError: 'foo' is undefined
445     """
446     __slots__ = ()
447
448     def __unicode__(self):
449         if self._undefined_hint is None:
450             if self._undefined_obj is None:
451                 return u'{{ %s }}' % self._undefined_name
452             return '{{ no such element: %s[%r] }}' % (
453                 self._undefined_obj.__class__.__name__,
454                 self._undefined_name
455             )
456         return u'{{ undefined value printed: %s }}' % self._undefined_hint
457
458
459 class StrictUndefined(Undefined):
460     """An undefined that barks on print and iteration as well as boolean
461     tests and all kinds of comparisons.  In other words: you can do nothing
462     with it except checking if it's defined using the `defined` test.
463
464     >>> foo = StrictUndefined(name='foo')
465     >>> str(foo)
466     Traceback (most recent call last):
467       ...
468     UndefinedError: 'foo' is undefined
469     >>> not foo
470     Traceback (most recent call last):
471       ...
472     UndefinedError: 'foo' is undefined
473     >>> foo + 42
474     Traceback (most recent call last):
475       ...
476     UndefinedError: 'foo' is undefined
477     """
478     __slots__ = ()
479     __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
480         Undefined._fail_with_undefined_error
481
482
483 # remove remaining slots attributes, after the metaclass did the magic they
484 # are unneeded and irritating as they contain wrong data for the subclasses.
485 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__