1 # -*- coding: utf-8 -*-
8 :copyright: Copyright 2008 by Armin Ronacher.
12 from types import FunctionType
13 from itertools import chain, imap
14 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, concat
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 def markup_join(*args):
25 """Concatenation that escapes if necessary and converts to unicode."""
27 iterator = imap(soft_unicode, args)
30 if hasattr(arg, '__html__'):
31 return Markup(u'').join(chain(buf, iterator))
35 def unicode_join(*args):
36 """Simple args to unicode conversion and concatenation."""
37 return concat(imap(unicode, args))
40 class Context(object):
41 """The template context holds the variables of a template. It stores the
42 values passed to the template and also the names the template exports.
43 Creating instances is neither supported nor useful as it's created
44 automatically at various stages of the template evaluation and should not
47 The context is immutable. Modifications on :attr:`parent` **must not**
48 happen and modifications on :attr:`vars` are allowed from generated
49 template code only. Template filters and global functions marked as
50 :func:`contextfunction`\s get the active context passed as first argument
51 and are allowed to access the context read-only.
53 The template context supports read only dict operations (`get`,
54 `__getitem__`, `__contains__`) however `__getitem__` doesn't fail with
55 a `KeyError` but returns an :attr:`Undefined` object.
58 def __init__(self, environment, parent, name, blocks):
61 self.environment = environment
62 self.exported_vars = set()
65 # bind functions to the context of environment if required
66 for name, obj in parent.iteritems():
67 if type(obj) is FunctionType:
68 if getattr(obj, 'contextfunction', 0):
69 vars[name] = partial(obj, self)
70 elif getattr(obj, 'environmentfunction', 0):
71 vars[name] = partial(obj, environment)
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 pos = blocks.index(current) - 1
86 return self.environment.undefined('there is no parent block '
89 wrap = self.environment.autoescape and Markup or (lambda x: x)
90 render = lambda: wrap(concat(blocks[pos](self)))
91 render.__name__ = render.name = name
94 def get(self, key, default=None):
95 """Returns an item from the template context, if it doesn't exist
96 `default` is returned.
100 if key in self.parent:
101 return self.parent[key]
104 def get_exported(self):
105 """Get a new dict with the exported variables."""
106 return dict((k, self.vars[k]) for k in self.exported_vars)
109 """Return a copy of the complete context as dict including the
112 return dict(self.parent, **self.vars)
114 def __contains__(self, name):
115 return name in self.vars or name in self.parent
117 def __getitem__(self, key):
119 return self.vars[key]
120 if key in self.parent:
121 return self.parent[key]
122 return self.environment.undefined(name=key)
125 return '<%s %s of %r>' % (
126 self.__class__.__name__,
127 repr(self.get_all()),
132 class TemplateReference(object):
133 """The `self` in templates."""
135 def __init__(self, context):
136 self.__context = context
138 def __getitem__(self, name):
139 func = self.__context.blocks[name][-1]
140 wrap = self.__context.environment.autoescape and \
141 Markup or (lambda x: x)
142 render = lambda: wrap(concat(func(self.__context)))
143 render.__name__ = render.name = name
148 self.__class__.__name__,
153 class LoopContext(object):
154 """A loop context for dynamic iteration."""
156 def __init__(self, iterable, enforce_length=False):
157 self._iterable = iterable
158 self._next = iter(iterable).next
164 def cycle(self, *args):
165 """A replacement for the old ``{% cycle %}`` tag."""
167 raise TypeError('no items for cycling given')
168 return args[self.index0 % len(args)]
170 first = property(lambda x: x.index0 == 0)
171 last = property(lambda x: x.revindex0 == 0)
172 index = property(lambda x: x.index0 + 1)
173 revindex = property(lambda x: x.length - x.index0)
174 revindex0 = property(lambda x: x.length - x.index)
184 return self._next(), self
188 if self._length is None:
190 length = len(self._iterable)
192 self._iterable = tuple(self._iterable)
193 self._next = iter(self._iterable).next
194 length = len(tuple(self._iterable)) + self.index0 + 1
195 self._length = length
199 return '<%s %r/%r>' % (
200 self.__class__.__name__,
209 def __init__(self, environment, func, name, arguments, defaults,
210 catch_kwargs, catch_varargs, caller):
211 self._environment = environment
213 self._argument_count = len(arguments)
215 self.arguments = arguments
216 self.defaults = defaults
217 self.catch_kwargs = catch_kwargs
218 self.catch_varargs = catch_varargs
221 def __call__(self, *args, **kwargs):
223 for idx, name in enumerate(self.arguments):
228 value = kwargs.pop(name)
231 value = self.defaults[idx - self._argument_count]
233 value = self._environment.undefined(
234 'parameter %r was not provided' % name, name=name)
235 arguments.append(value)
237 # it's important that the order of these arguments does not change
238 # if not also changed in the compiler's `function_scoping` method.
239 # the order is caller, keyword arguments, positional arguments!
241 caller = kwargs.pop('caller', None)
243 caller = self._environment.undefined('No caller defined',
245 arguments.append(caller)
246 if self.catch_kwargs:
247 arguments.append(kwargs)
249 raise TypeError('macro %r takes no keyword argument %r' %
250 (self.name, iter(kwargs).next()))
251 if self.catch_varargs:
252 arguments.append(args[self._argument_count:])
253 elif len(args) > self._argument_count:
254 raise TypeError('macro %r takes not more than %d argument(s)' %
255 (self.name, len(self.arguments)))
256 return self._func(*arguments)
260 self.__class__.__name__,
261 self.name is None and 'anonymous' or repr(self.name)
265 def fail_with_undefined_error(self, *args, **kwargs):
266 """Regular callback function for undefined objects that raises an
267 `UndefinedError` on call.
269 if self._undefined_hint is None:
270 if self._undefined_obj is None:
271 hint = '%r is undefined' % self._undefined_name
272 elif not isinstance(self._undefined_name, basestring):
273 hint = '%r object has no element %r' % (
274 self._undefined_obj.__class__.__name__,
278 hint = '%r object has no attribute %r' % (
279 self._undefined_obj.__class__.__name__,
283 hint = self._undefined_hint
284 raise UndefinedError(hint)
287 class Undefined(object):
288 """The default undefined type. This undefined type can be printed and
289 iterated over, but every other access will raise an :exc:`UndefinedError`:
291 >>> foo = Undefined(name='foo')
297 Traceback (most recent call last):
299 jinja2.exceptions.UndefinedError: 'foo' is undefined
301 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name')
303 def __init__(self, hint=None, obj=None, name=None):
304 self._undefined_hint = hint
305 self._undefined_obj = obj
306 self._undefined_name = name
308 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
309 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
310 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
311 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
312 fail_with_undefined_error
315 return self.__unicode__().encode('utf-8')
320 def __unicode__(self):
330 def __nonzero__(self):
334 class DebugUndefined(Undefined):
335 """An undefined that returns the debug info when printed.
337 >>> foo = DebugUndefined(name='foo')
343 Traceback (most recent call last):
345 jinja2.exceptions.UndefinedError: 'foo' is undefined
349 def __unicode__(self):
350 if self._undefined_hint is None:
351 if self._undefined_obj is None:
352 return u'{{ %s }}' % self._undefined_name
353 return '{{ no such element: %s[%r] }}' % (
354 self._undefined_obj.__class__.__name__,
357 return u'{{ undefined value printed: %s }}' % self._undefined_hint
360 class StrictUndefined(Undefined):
361 """An undefined that barks on print and iteration as well as boolean
362 tests and all kinds of comparisons. In other words: you can do nothing
363 with it except checking if it's defined using the `defined` test.
365 >>> foo = StrictUndefined(name='foo')
367 Traceback (most recent call last):
369 jinja2.exceptions.UndefinedError: 'foo' is undefined
371 Traceback (most recent call last):
373 jinja2.exceptions.UndefinedError: 'foo' is undefined
375 Traceback (most recent call last):
377 jinja2.exceptions.UndefinedError: 'foo' is undefined
380 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
381 fail_with_undefined_error
384 # remove remaining slots attributes, after the metaclass did the magic they
385 # are unneeded and irritating as they contain wrong data for the subclasses.
386 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__