1 # -*- coding: utf-8 -*-
8 :copyright: Copyright 2008 by Armin Ronacher.
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
18 # these variables are exported to the template runtime
19 __all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
20 'TemplateRuntimeError', 'missing', 'concat', 'escape',
21 'markup_join', 'unicode_join']
24 #: the types we support for context functions
25 _context_function_types = (FunctionType, MethodType)
29 """Concatenation that escapes if necessary and converts to unicode."""
31 iterator = imap(soft_unicode, seq)
34 if hasattr(arg, '__html__'):
35 return Markup(u'').join(chain(buf, iterator))
39 def unicode_join(seq):
40 """Simple args to unicode conversion and concatenation."""
41 return concat(imap(unicode, seq))
44 class Context(object):
45 """The template context holds the variables of a template. It stores the
46 values passed to the template and also the names the template exports.
47 Creating instances is neither supported nor useful as it's created
48 automatically at various stages of the template evaluation and should not
51 The context is immutable. Modifications on :attr:`parent` **must not**
52 happen and modifications on :attr:`vars` are allowed from generated
53 template code only. Template filters and global functions marked as
54 :func:`contextfunction`\s get the active context passed as first argument
55 and are allowed to access the context read-only.
57 The template context supports read only dict operations (`get`,
58 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
59 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
60 method that doesn't fail with a `KeyError` but returns an
61 :class:`Undefined` object for missing variables.
63 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
64 'blocks', '__weakref__')
66 def __init__(self, environment, parent, name, blocks):
69 self.environment = environment
70 self.exported_vars = set()
73 # create the initial mapping of blocks. Whenever template inheritance
74 # takes place the runtime will update this mapping with the new blocks
76 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
78 def super(self, name, current):
79 """Render a parent block."""
81 blocks = self.blocks[name]
82 index = blocks.index(current) + 1
85 return self.environment.undefined('there is no parent block '
88 return BlockReference(name, self, blocks, index)
90 def get(self, key, default=None):
91 """Returns an item from the template context, if it doesn't exist
92 `default` is returned.
99 def resolve(self, key):
100 """Looks up a variable like `__getitem__` or `get` but returns an
101 :class:`Undefined` object with the name of the name looked up.
104 return self.vars[key]
105 if key in self.parent:
106 return self.parent[key]
107 return self.environment.undefined(name=key)
109 def get_exported(self):
110 """Get a new dict with the exported variables."""
111 return dict((k, self.vars[k]) for k in self.exported_vars)
114 """Return a copy of the complete context as dict including the
117 return dict(self.parent, **self.vars)
119 def call(__self, __obj, *args, **kwargs):
120 """Call the callable with the arguments and keyword arguments
121 provided but inject the active context or environment as first
122 argument if the callable is a :func:`contextfunction` or
123 :func:`environmentfunction`.
126 __traceback_hide__ = True
127 if isinstance(__obj, _context_function_types):
128 if getattr(__obj, 'contextfunction', 0):
129 args = (__self,) + args
130 elif getattr(__obj, 'environmentfunction', 0):
131 args = (__self.environment,) + args
132 return __obj(*args, **kwargs)
135 proxy = lambda self: getattr(self.get_all(), meth)()
136 proxy.__doc__ = getattr(dict, meth).__doc__
137 proxy.__name__ = meth
141 values = _all('values')
142 items = _all('items')
143 iterkeys = _all('iterkeys')
144 itervalues = _all('itervalues')
145 iteritems = _all('iteritems')
148 def __contains__(self, name):
149 return name in self.vars or name in self.parent
151 def __getitem__(self, key):
152 """Lookup a variable or raise `KeyError` if the variable is
155 item = self.resolve(key)
156 if isinstance(item, Undefined):
161 return '<%s %s of %r>' % (
162 self.__class__.__name__,
163 repr(self.get_all()),
168 # register the context as mapping if possible
170 from collections import Mapping
171 Mapping.register(Context)
176 class TemplateReference(object):
177 """The `self` in templates."""
179 def __init__(self, context):
180 self.__context = context
182 def __getitem__(self, name):
183 blocks = self.__context.blocks[name]
184 wrap = self.__context.environment.autoescape and \
185 Markup or (lambda x: x)
186 return BlockReference(name, self.__context, blocks, 0)
190 self.__class__.__name__,
195 class BlockReference(object):
196 """One block on a template reference."""
198 def __init__(self, name, context, stack, depth):
200 self._context = context
206 """Super the block."""
207 if self._depth + 1 >= len(self._stack):
208 return self._context.environment. \
209 undefined('there is no parent block called %r.' %
210 self.name, name='super')
211 return BlockReference(self.name, self._context, self._stack,
215 rv = concat(self._stack[self._depth](self._context))
216 if self._context.environment.autoescape:
221 class LoopContext(object):
222 """A loop context for dynamic iteration."""
224 def __init__(self, iterable, recurse=None):
225 self._iterator = iter(iterable)
226 self._recurse = recurse
229 # try to get the length of the iterable early. This must be done
230 # here because there are some broken iterators around where there
231 # __len__ is the number of iterations left (i'm looking at your
232 # listreverseiterator!).
234 self._length = len(iterable)
235 except (TypeError, AttributeError):
238 def cycle(self, *args):
239 """Cycles among the arguments with the current loop index."""
241 raise TypeError('no items for cycling given')
242 return args[self.index0 % len(args)]
244 first = property(lambda x: x.index0 == 0)
245 last = property(lambda x: x.index0 + 1 == x.length)
246 index = property(lambda x: x.index0 + 1)
247 revindex = property(lambda x: x.length - x.index0)
248 revindex0 = property(lambda x: x.length - x.index)
254 return LoopContextIterator(self)
256 def loop(self, iterable):
257 if self._recurse is None:
258 raise TypeError('Tried to call non recursive loop. Maybe you '
259 "forgot the 'recursive' modifier.")
260 return self._recurse(iterable, self._recurse)
262 # a nifty trick to enhance the error message if someone tried to call
263 # the the loop without or with too many arguments.
264 __call__ = loop; del loop
268 if self._length is None:
269 # if was not possible to get the length of the iterator when
270 # the loop context was created (ie: iterating over a generator)
271 # we have to convert the iterable into a sequence and use the
273 iterable = tuple(self._iterator)
274 self._iterator = iter(iterable)
275 self._length = len(iterable) + self.index0 + 1
279 return '<%s %r/%r>' % (
280 self.__class__.__name__,
286 class LoopContextIterator(object):
287 """The iterator for a loop context."""
288 __slots__ = ('context',)
290 def __init__(self, context):
291 self.context = context
299 return ctx._iterator.next(), ctx
305 def __init__(self, environment, func, name, arguments, defaults,
306 catch_kwargs, catch_varargs, caller):
307 self._environment = environment
309 self._argument_count = len(arguments)
311 self.arguments = arguments
312 self.defaults = defaults
313 self.catch_kwargs = catch_kwargs
314 self.catch_varargs = catch_varargs
317 def __call__(self, *args, **kwargs):
319 for idx, name in enumerate(self.arguments):
324 value = kwargs.pop(name)
327 value = self.defaults[idx - self._argument_count]
329 value = self._environment.undefined(
330 'parameter %r was not provided' % name, name=name)
331 arguments.append(value)
333 # it's important that the order of these arguments does not change
334 # if not also changed in the compiler's `function_scoping` method.
335 # the order is caller, keyword arguments, positional arguments!
337 caller = kwargs.pop('caller', None)
339 caller = self._environment.undefined('No caller defined',
341 arguments.append(caller)
342 if self.catch_kwargs:
343 arguments.append(kwargs)
345 raise TypeError('macro %r takes no keyword argument %r' %
346 (self.name, iter(kwargs).next()))
347 if self.catch_varargs:
348 arguments.append(args[self._argument_count:])
349 elif len(args) > self._argument_count:
350 raise TypeError('macro %r takes not more than %d argument(s)' %
351 (self.name, len(self.arguments)))
352 return self._func(*arguments)
356 self.__class__.__name__,
357 self.name is None and 'anonymous' or repr(self.name)
361 class Undefined(object):
362 """The default undefined type. This undefined type can be printed and
363 iterated over, but every other access will raise an :exc:`UndefinedError`:
365 >>> foo = Undefined(name='foo')
371 Traceback (most recent call last):
373 UndefinedError: 'foo' is undefined
375 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
376 '_undefined_exception')
378 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
379 self._undefined_hint = hint
380 self._undefined_obj = obj
381 self._undefined_name = name
382 self._undefined_exception = exc
384 def _fail_with_undefined_error(self, *args, **kwargs):
385 """Regular callback function for undefined objects that raises an
386 `UndefinedError` on call.
388 if self._undefined_hint is None:
389 if self._undefined_obj is None:
390 hint = '%r is undefined' % self._undefined_name
391 elif not isinstance(self._undefined_name, basestring):
392 hint = '%r object has no element %r' % (
393 self._undefined_obj.__class__.__name__,
397 hint = '%r object has no attribute %r' % (
398 self._undefined_obj.__class__.__name__,
402 hint = self._undefined_hint
403 raise self._undefined_exception(hint)
405 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
406 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
407 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
408 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
409 __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
410 _fail_with_undefined_error
413 return unicode(self).encode('utf-8')
415 def __unicode__(self):
425 def __nonzero__(self):
432 class DebugUndefined(Undefined):
433 """An undefined that returns the debug info when printed.
435 >>> foo = DebugUndefined(name='foo')
441 Traceback (most recent call last):
443 UndefinedError: 'foo' is undefined
447 def __unicode__(self):
448 if self._undefined_hint is None:
449 if self._undefined_obj is None:
450 return u'{{ %s }}' % self._undefined_name
451 return '{{ no such element: %s[%r] }}' % (
452 self._undefined_obj.__class__.__name__,
455 return u'{{ undefined value printed: %s }}' % self._undefined_hint
458 class StrictUndefined(Undefined):
459 """An undefined that barks on print and iteration as well as boolean
460 tests and all kinds of comparisons. In other words: you can do nothing
461 with it except checking if it's defined using the `defined` test.
463 >>> foo = StrictUndefined(name='foo')
465 Traceback (most recent call last):
467 UndefinedError: 'foo' is undefined
469 Traceback (most recent call last):
471 UndefinedError: 'foo' is undefined
473 Traceback (most recent call last):
475 UndefinedError: 'foo' is undefined
478 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
479 Undefined._fail_with_undefined_error
482 # remove remaining slots attributes, after the metaclass did the magic they
483 # are unneeded and irritating as they contain wrong data for the subclasses.
484 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__