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