1 # -*- coding: utf-8 -*-
8 :copyright: (c) 2010 by the Jinja Team.
11 from itertools import chain, imap
12 from jinja2.nodes import EvalContext, _context_function_types
13 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
14 concat, internalcode, next, object_type_repr
15 from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
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', 'identity',
25 #: the name of the function that is used to convert something into
26 #: a string. 2to3 will adopt that automatically and the generated
27 #: code can take advantage of it.
30 #: the identity function. Useful for certain things in the environment
31 identity = lambda x: x
33 _last_iteration = object()
37 """Concatenation that escapes if necessary and converts to unicode."""
39 iterator = imap(soft_unicode, seq)
42 if hasattr(arg, '__html__'):
43 return Markup(u'').join(chain(buf, iterator))
47 def unicode_join(seq):
48 """Simple args to unicode conversion and concatenation."""
49 return concat(imap(unicode, seq))
52 def new_context(environment, template_name, blocks, vars=None,
53 shared=None, globals=None, locals=None):
54 """Internal helper to for context creation."""
60 parent = dict(globals or (), **vars)
62 # if the parent is shared a copy should be created because
63 # we don't want to modify the dict passed
66 for key, value in locals.iteritems():
67 if key[:2] == 'l_' and value is not missing:
68 parent[key[2:]] = value
69 return Context(environment, parent, template_name, blocks)
72 class TemplateReference(object):
73 """The `self` in templates."""
75 def __init__(self, context):
76 self.__context = context
78 def __getitem__(self, name):
79 blocks = self.__context.blocks[name]
80 return BlockReference(name, self.__context, blocks, 0)
84 self.__class__.__name__,
89 class Context(object):
90 """The template context holds the variables of a template. It stores the
91 values passed to the template and also the names the template exports.
92 Creating instances is neither supported nor useful as it's created
93 automatically at various stages of the template evaluation and should not
96 The context is immutable. Modifications on :attr:`parent` **must not**
97 happen and modifications on :attr:`vars` are allowed from generated
98 template code only. Template filters and global functions marked as
99 :func:`contextfunction`\s get the active context passed as first argument
100 and are allowed to access the context read-only.
102 The template context supports read only dict operations (`get`,
103 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
104 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
105 method that doesn't fail with a `KeyError` but returns an
106 :class:`Undefined` object for missing variables.
108 __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
109 'name', 'blocks', '__weakref__')
111 def __init__(self, environment, parent, name, blocks):
114 self.environment = environment
115 self.eval_ctx = EvalContext(self.environment, name)
116 self.exported_vars = set()
119 # create the initial mapping of blocks. Whenever template inheritance
120 # takes place the runtime will update this mapping with the new blocks
122 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
124 def super(self, name, current):
125 """Render a parent block."""
127 blocks = self.blocks[name]
128 index = blocks.index(current) + 1
131 return self.environment.undefined('there is no parent block '
134 return BlockReference(name, self, blocks, index)
136 def get(self, key, default=None):
137 """Returns an item from the template context, if it doesn't exist
138 `default` is returned.
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.
150 return self.vars[key]
151 if key in self.parent:
152 return self.parent[key]
153 return self.environment.undefined(name=key)
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)
160 """Return a copy of the complete context as dict including the
163 return dict(self.parent, **self.vars)
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`.
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, 'evalcontextfunction', 0):
178 args = (__self.eval_ctx,) + args
179 elif getattr(__obj, 'environmentfunction', 0):
180 args = (__self.environment,) + args
182 return __obj(*args, **kwargs)
183 except StopIteration:
184 return __self.environment.undefined('value was undefined because '
185 'a callable raised a '
186 'StopIteration exception')
188 def derived(self, locals=None):
189 """Internal helper function to create a derived context."""
190 context = new_context(self.environment, self.name, {},
191 self.parent, True, None, locals)
192 context.vars.update(self.vars)
193 context.eval_ctx = self.eval_ctx
194 context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems())
198 proxy = lambda self: getattr(self.get_all(), meth)()
199 proxy.__doc__ = getattr(dict, meth).__doc__
200 proxy.__name__ = meth
204 values = _all('values')
205 items = _all('items')
207 # not available on python 3
208 if hasattr(dict, 'iterkeys'):
209 iterkeys = _all('iterkeys')
210 itervalues = _all('itervalues')
211 iteritems = _all('iteritems')
214 def __contains__(self, name):
215 return name in self.vars or name in self.parent
217 def __getitem__(self, key):
218 """Lookup a variable or raise `KeyError` if the variable is
221 item = self.resolve(key)
222 if isinstance(item, Undefined):
227 return '<%s %s of %r>' % (
228 self.__class__.__name__,
229 repr(self.get_all()),
234 # register the context as mapping if possible
236 from collections import Mapping
237 Mapping.register(Context)
242 class BlockReference(object):
243 """One block on a template reference."""
245 def __init__(self, name, context, stack, depth):
247 self._context = context
253 """Super the block."""
254 if self._depth + 1 >= len(self._stack):
255 return self._context.environment. \
256 undefined('there is no parent block called %r.' %
257 self.name, name='super')
258 return BlockReference(self.name, self._context, self._stack,
263 rv = concat(self._stack[self._depth](self._context))
264 if self._context.eval_ctx.autoescape:
269 class LoopContext(object):
270 """A loop context for dynamic iteration."""
272 def __init__(self, iterable, recurse=None):
273 self._iterator = iter(iterable)
274 self._recurse = recurse
275 self._after = self._safe_next()
278 # try to get the length of the iterable early. This must be done
279 # here because there are some broken iterators around where there
280 # __len__ is the number of iterations left (i'm looking at your
281 # listreverseiterator!).
283 self._length = len(iterable)
284 except (TypeError, AttributeError):
287 def cycle(self, *args):
288 """Cycles among the arguments with the current loop index."""
290 raise TypeError('no items for cycling given')
291 return args[self.index0 % len(args)]
293 first = property(lambda x: x.index0 == 0)
294 last = property(lambda x: x._after is _last_iteration)
295 index = property(lambda x: x.index0 + 1)
296 revindex = property(lambda x: x.length - x.index0)
297 revindex0 = property(lambda x: x.length - x.index)
303 return LoopContextIterator(self)
305 def _safe_next(self):
307 return next(self._iterator)
308 except StopIteration:
309 return _last_iteration
312 def loop(self, iterable):
313 if self._recurse is None:
314 raise TypeError('Tried to call non recursive loop. Maybe you '
315 "forgot the 'recursive' modifier.")
316 return self._recurse(iterable, self._recurse)
318 # a nifty trick to enhance the error message if someone tried to call
319 # the the loop without or with too many arguments.
325 if self._length is None:
326 # if was not possible to get the length of the iterator when
327 # the loop context was created (ie: iterating over a generator)
328 # we have to convert the iterable into a sequence and use the
330 iterable = tuple(self._iterator)
331 self._iterator = iter(iterable)
332 self._length = len(iterable) + self.index0 + 1
336 return '<%s %r/%r>' % (
337 self.__class__.__name__,
343 class LoopContextIterator(object):
344 """The iterator for a loop context."""
345 __slots__ = ('context',)
347 def __init__(self, context):
348 self.context = context
356 if ctx._after is _last_iteration:
357 raise StopIteration()
358 next_elem = ctx._after
359 ctx._after = ctx._safe_next()
360 return next_elem, ctx
364 """Wraps a macro function."""
366 def __init__(self, environment, func, name, arguments, defaults,
367 catch_kwargs, catch_varargs, caller):
368 self._environment = environment
370 self._argument_count = len(arguments)
372 self.arguments = arguments
373 self.defaults = defaults
374 self.catch_kwargs = catch_kwargs
375 self.catch_varargs = catch_varargs
379 def __call__(self, *args, **kwargs):
380 # try to consume the positional arguments
381 arguments = list(args[:self._argument_count])
384 # if the number of arguments consumed is not the number of
385 # arguments expected we start filling in keyword arguments
387 if off != self._argument_count:
388 for idx, name in enumerate(self.arguments[len(arguments):]):
390 value = kwargs.pop(name)
393 value = self.defaults[idx - self._argument_count + off]
395 value = self._environment.undefined(
396 'parameter %r was not provided' % name, name=name)
397 arguments.append(value)
399 # it's important that the order of these arguments does not change
400 # if not also changed in the compiler's `function_scoping` method.
401 # the order is caller, keyword arguments, positional arguments!
403 caller = kwargs.pop('caller', None)
405 caller = self._environment.undefined('No caller defined',
407 arguments.append(caller)
408 if self.catch_kwargs:
409 arguments.append(kwargs)
411 raise TypeError('macro %r takes no keyword argument %r' %
412 (self.name, next(iter(kwargs))))
413 if self.catch_varargs:
414 arguments.append(args[self._argument_count:])
415 elif len(args) > self._argument_count:
416 raise TypeError('macro %r takes not more than %d argument(s)' %
417 (self.name, len(self.arguments)))
418 return self._func(*arguments)
422 self.__class__.__name__,
423 self.name is None and 'anonymous' or repr(self.name)
427 class Undefined(object):
428 """The default undefined type. This undefined type can be printed and
429 iterated over, but every other access will raise an :exc:`UndefinedError`:
431 >>> foo = Undefined(name='foo')
437 Traceback (most recent call last):
439 UndefinedError: 'foo' is undefined
441 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
442 '_undefined_exception')
444 def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
445 self._undefined_hint = hint
446 self._undefined_obj = obj
447 self._undefined_name = name
448 self._undefined_exception = exc
451 def _fail_with_undefined_error(self, *args, **kwargs):
452 """Regular callback function for undefined objects that raises an
453 `UndefinedError` on call.
455 if self._undefined_hint is None:
456 if self._undefined_obj is missing:
457 hint = '%r is undefined' % self._undefined_name
458 elif not isinstance(self._undefined_name, basestring):
459 hint = '%s has no element %r' % (
460 object_type_repr(self._undefined_obj),
464 hint = '%r has no attribute %r' % (
465 object_type_repr(self._undefined_obj),
469 hint = self._undefined_hint
470 raise self._undefined_exception(hint)
473 def __getattr__(self, name):
475 raise AttributeError(name)
476 return self._fail_with_undefined_error()
478 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
479 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
480 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
481 __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
482 __float__ = __complex__ = __pow__ = __rpow__ = \
483 _fail_with_undefined_error
486 return unicode(self).encode('utf-8')
488 # unicode goes after __str__ because we configured 2to3 to rename
489 # __unicode__ to __str__. because the 2to3 tree is not designed to
490 # remove nodes from it, we leave the above __str__ around and let
491 # it override at runtime.
492 def __unicode__(self):
502 def __nonzero__(self):
509 class DebugUndefined(Undefined):
510 """An undefined that returns the debug info when printed.
512 >>> foo = DebugUndefined(name='foo')
518 Traceback (most recent call last):
520 UndefinedError: 'foo' is undefined
524 def __unicode__(self):
525 if self._undefined_hint is None:
526 if self._undefined_obj is missing:
527 return u'{{ %s }}' % self._undefined_name
528 return '{{ no such element: %s[%r] }}' % (
529 object_type_repr(self._undefined_obj),
532 return u'{{ undefined value printed: %s }}' % self._undefined_hint
535 class StrictUndefined(Undefined):
536 """An undefined that barks on print and iteration as well as boolean
537 tests and all kinds of comparisons. In other words: you can do nothing
538 with it except checking if it's defined using the `defined` test.
540 >>> foo = StrictUndefined(name='foo')
542 Traceback (most recent call last):
544 UndefinedError: 'foo' is undefined
546 Traceback (most recent call last):
548 UndefinedError: 'foo' is undefined
550 Traceback (most recent call last):
552 UndefinedError: 'foo' is undefined
555 __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \
556 __ne__ = __bool__ = Undefined._fail_with_undefined_error
559 # remove remaining slots attributes, after the metaclass did the magic they
560 # are unneeded and irritating as they contain wrong data for the subclasses.
561 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__