1 # -*- coding: utf-8 -*-
8 :copyright: (c) 2010 by the Jinja Team.
12 from itertools import chain, imap
13 from jinja2.nodes import EvalContext, _context_function_types
14 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
15 concat, internalcode, next, object_type_repr
16 from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
20 # these variables are exported to the template runtime
21 __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
22 'TemplateRuntimeError', 'missing', 'concat', 'escape',
23 'markup_join', 'unicode_join', 'to_string', 'identity',
26 #: the name of the function that is used to convert something into
27 #: a string. 2to3 will adopt that automatically and the generated
28 #: code can take advantage of it.
31 #: the identity function. Useful for certain things in the environment
32 identity = lambda x: x
36 """Concatenation that escapes if necessary and converts to unicode."""
38 iterator = imap(soft_unicode, seq)
41 if hasattr(arg, '__html__'):
42 return Markup(u'').join(chain(buf, iterator))
46 def unicode_join(seq):
47 """Simple args to unicode conversion and concatenation."""
48 return concat(imap(unicode, seq))
51 def new_context(environment, template_name, blocks, vars=None,
52 shared=None, globals=None, locals=None):
53 """Internal helper to for context creation."""
59 parent = dict(globals or (), **vars)
61 # if the parent is shared a copy should be created because
62 # we don't want to modify the dict passed
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)
71 class TemplateReference(object):
72 """The `self` in templates."""
74 def __init__(self, context):
75 self.__context = context
77 def __getitem__(self, name):
78 blocks = self.__context.blocks[name]
79 wrap = self.__context.eval_ctx.autoescape and \
80 Markup or (lambda x: x)
81 return BlockReference(name, self.__context, blocks, 0)
85 self.__class__.__name__,
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
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.
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.
109 __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
110 'name', 'blocks', '__weakref__')
112 def __init__(self, environment, parent, name, blocks):
115 self.environment = environment
116 self.eval_ctx = EvalContext(self.environment, name)
117 self.exported_vars = set()
120 # create the initial mapping of blocks. Whenever template inheritance
121 # takes place the runtime will update this mapping with the new blocks
123 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
125 def super(self, name, current):
126 """Render a parent block."""
128 blocks = self.blocks[name]
129 index = blocks.index(current) + 1
132 return self.environment.undefined('there is no parent block '
135 return BlockReference(name, self, blocks, index)
137 def get(self, key, default=None):
138 """Returns an item from the template context, if it doesn't exist
139 `default` is returned.
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.
151 return self.vars[key]
152 if key in self.parent:
153 return self.parent[key]
154 return self.environment.undefined(name=key)
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)
161 """Return a copy of the complete context as dict including the
164 return dict(self.parent, **self.vars)
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`.
174 __traceback_hide__ = True
175 if isinstance(__obj, _context_function_types):
176 if getattr(__obj, 'contextfunction', 0):
177 args = (__self,) + args
178 elif getattr(__obj, 'evalcontextfunction', 0):
179 args = (__self.eval_ctx,) + args
180 elif getattr(__obj, 'environmentfunction', 0):
181 args = (__self.environment,) + args
182 return __obj(*args, **kwargs)
184 def derived(self, locals=None):
185 """Internal helper function to create a derived context."""
186 context = new_context(self.environment, self.name, {},
187 self.parent, True, None, locals)
188 context.eval_ctx = self.eval_ctx
189 context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems())
193 proxy = lambda self: getattr(self.get_all(), meth)()
194 proxy.__doc__ = getattr(dict, meth).__doc__
195 proxy.__name__ = meth
199 values = _all('values')
200 items = _all('items')
202 # not available on python 3
203 if hasattr(dict, 'iterkeys'):
204 iterkeys = _all('iterkeys')
205 itervalues = _all('itervalues')
206 iteritems = _all('iteritems')
209 def __contains__(self, name):
210 return name in self.vars or name in self.parent
212 def __getitem__(self, key):
213 """Lookup a variable or raise `KeyError` if the variable is
216 item = self.resolve(key)
217 if isinstance(item, Undefined):
222 return '<%s %s of %r>' % (
223 self.__class__.__name__,
224 repr(self.get_all()),
229 # register the context as mapping if possible
231 from collections import Mapping
232 Mapping.register(Context)
237 class BlockReference(object):
238 """One block on a template reference."""
240 def __init__(self, name, context, stack, depth):
242 self._context = context
248 """Super the block."""
249 if self._depth + 1 >= len(self._stack):
250 return self._context.environment. \
251 undefined('there is no parent block called %r.' %
252 self.name, name='super')
253 return BlockReference(self.name, self._context, self._stack,
258 rv = concat(self._stack[self._depth](self._context))
259 if self._context.eval_ctx.autoescape:
264 class LoopContext(object):
265 """A loop context for dynamic iteration."""
267 def __init__(self, iterable, recurse=None):
268 self._iterator = iter(iterable)
269 self._recurse = recurse
272 # try to get the length of the iterable early. This must be done
273 # here because there are some broken iterators around where there
274 # __len__ is the number of iterations left (i'm looking at your
275 # listreverseiterator!).
277 self._length = len(iterable)
278 except (TypeError, AttributeError):
281 def cycle(self, *args):
282 """Cycles among the arguments with the current loop index."""
284 raise TypeError('no items for cycling given')
285 return args[self.index0 % len(args)]
287 first = property(lambda x: x.index0 == 0)
288 last = property(lambda x: x.index0 + 1 == x.length)
289 index = property(lambda x: x.index0 + 1)
290 revindex = property(lambda x: x.length - x.index0)
291 revindex0 = property(lambda x: x.length - x.index)
297 return LoopContextIterator(self)
300 def loop(self, iterable):
301 if self._recurse is None:
302 raise TypeError('Tried to call non recursive loop. Maybe you '
303 "forgot the 'recursive' modifier.")
304 return self._recurse(iterable, self._recurse)
306 # a nifty trick to enhance the error message if someone tried to call
307 # the the loop without or with too many arguments.
313 if self._length is None:
314 # if was not possible to get the length of the iterator when
315 # the loop context was created (ie: iterating over a generator)
316 # we have to convert the iterable into a sequence and use the
318 iterable = tuple(self._iterator)
319 self._iterator = iter(iterable)
320 self._length = len(iterable) + self.index0 + 1
324 return '<%s %r/%r>' % (
325 self.__class__.__name__,
331 class LoopContextIterator(object):
332 """The iterator for a loop context."""
333 __slots__ = ('context',)
335 def __init__(self, context):
336 self.context = context
344 return next(ctx._iterator), ctx
350 def __init__(self, environment, func, name, arguments, defaults,
351 catch_kwargs, catch_varargs, caller):
352 self._environment = environment
354 self._argument_count = len(arguments)
356 self.arguments = arguments
357 self.defaults = defaults
358 self.catch_kwargs = catch_kwargs
359 self.catch_varargs = catch_varargs
363 def __call__(self, *args, **kwargs):
365 for idx, name in enumerate(self.arguments):
370 value = kwargs.pop(name)
373 value = self.defaults[idx - self._argument_count]
375 value = self._environment.undefined(
376 'parameter %r was not provided' % name, name=name)
377 arguments.append(value)
379 # it's important that the order of these arguments does not change
380 # if not also changed in the compiler's `function_scoping` method.
381 # the order is caller, keyword arguments, positional arguments!
383 caller = kwargs.pop('caller', None)
385 caller = self._environment.undefined('No caller defined',
387 arguments.append(caller)
388 if self.catch_kwargs:
389 arguments.append(kwargs)
391 raise TypeError('macro %r takes no keyword argument %r' %
392 (self.name, next(iter(kwargs))))
393 if self.catch_varargs:
394 arguments.append(args[self._argument_count:])
395 elif len(args) > self._argument_count:
396 raise TypeError('macro %r takes not more than %d argument(s)' %
397 (self.name, len(self.arguments)))
398 return self._func(*arguments)
402 self.__class__.__name__,
403 self.name is None and 'anonymous' or repr(self.name)
407 class Undefined(object):
408 """The default undefined type. This undefined type can be printed and
409 iterated over, but every other access will raise an :exc:`UndefinedError`:
411 >>> foo = Undefined(name='foo')
417 Traceback (most recent call last):
419 UndefinedError: 'foo' is undefined
421 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
422 '_undefined_exception')
424 def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
425 self._undefined_hint = hint
426 self._undefined_obj = obj
427 self._undefined_name = name
428 self._undefined_exception = exc
431 def _fail_with_undefined_error(self, *args, **kwargs):
432 """Regular callback function for undefined objects that raises an
433 `UndefinedError` on call.
435 if self._undefined_hint is None:
436 if self._undefined_obj is missing:
437 hint = '%r is undefined' % self._undefined_name
438 elif not isinstance(self._undefined_name, basestring):
439 hint = '%s has no element %r' % (
440 object_type_repr(self._undefined_obj),
444 hint = '%r has no attribute %r' % (
445 object_type_repr(self._undefined_obj),
449 hint = self._undefined_hint
450 raise self._undefined_exception(hint)
452 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
453 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
454 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
455 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
456 __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
457 _fail_with_undefined_error
460 return unicode(self).encode('utf-8')
462 # unicode goes after __str__ because we configured 2to3 to rename
463 # __unicode__ to __str__. because the 2to3 tree is not designed to
464 # remove nodes from it, we leave the above __str__ around and let
465 # it override at runtime.
466 def __unicode__(self):
476 def __nonzero__(self):
483 class DebugUndefined(Undefined):
484 """An undefined that returns the debug info when printed.
486 >>> foo = DebugUndefined(name='foo')
492 Traceback (most recent call last):
494 UndefinedError: 'foo' is undefined
498 def __unicode__(self):
499 if self._undefined_hint is None:
500 if self._undefined_obj is missing:
501 return u'{{ %s }}' % self._undefined_name
502 return '{{ no such element: %s[%r] }}' % (
503 object_type_repr(self._undefined_obj),
506 return u'{{ undefined value printed: %s }}' % self._undefined_hint
509 class StrictUndefined(Undefined):
510 """An undefined that barks on print and iteration as well as boolean
511 tests and all kinds of comparisons. In other words: you can do nothing
512 with it except checking if it's defined using the `defined` test.
514 >>> foo = StrictUndefined(name='foo')
516 Traceback (most recent call last):
518 UndefinedError: 'foo' is undefined
520 Traceback (most recent call last):
522 UndefinedError: 'foo' is undefined
524 Traceback (most recent call last):
526 UndefinedError: 'foo' is undefined
529 __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \
530 __ne__ = __bool__ = Undefined._fail_with_undefined_error
533 # remove remaining slots attributes, after the metaclass did the magic they
534 # are unneeded and irritating as they contain wrong data for the subclasses.
535 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__