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