blob: fb72ed4ec38fbad67df360857e6878983d2c6e9c [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.runtime
4 ~~~~~~~~~~~~~~
5
6 Runtime helpers.
7
8 :copyright: Copyright 2008 by Armin Ronacher.
9 :license: GNU GPL.
10"""
Armin Ronacher1ae4fdf2008-04-28 20:49:51 +020011import sys
Armin Ronacher4f7d2d52008-04-22 10:40:26 +020012from types import FunctionType
Armin Ronacherd1342312008-04-28 12:20:12 +020013from itertools import chain, imap
Armin Ronacher7ceced52008-05-03 10:15:31 +020014from jinja2.utils import Markup, partial, soft_unicode, escape, missing, concat
Armin Ronacherd1342312008-04-28 12:20:12 +020015from jinja2.exceptions import UndefinedError, TemplateRuntimeError
Armin Ronachere791c2a2008-04-07 18:39:54 +020016
17
Armin Ronacher2feed1d2008-04-26 16:26:52 +020018# these variables are exported to the template runtime
Armin Ronacher19cf9c22008-05-01 12:49:53 +020019__all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
20 'TemplateRuntimeError', 'missing', 'concat', 'escape',
Armin Ronacherd1342312008-04-28 12:20:12 +020021 'markup_join', 'unicode_join']
Armin Ronacher0611e492008-04-25 23:44:14 +020022
23
Armin Ronacherdc02b642008-05-15 22:47:27 +020024def markup_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020025 """Concatenation that escapes if necessary and converts to unicode."""
26 buf = []
Armin Ronacherdc02b642008-05-15 22:47:27 +020027 iterator = imap(soft_unicode, seq)
Armin Ronacherd1342312008-04-28 12:20:12 +020028 for arg in iterator:
29 buf.append(arg)
30 if hasattr(arg, '__html__'):
31 return Markup(u'').join(chain(buf, iterator))
32 return concat(buf)
33
34
Armin Ronacherdc02b642008-05-15 22:47:27 +020035def unicode_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020036 """Simple args to unicode conversion and concatenation."""
Armin Ronacherdc02b642008-05-15 22:47:27 +020037 return concat(imap(unicode, seq))
Armin Ronacherd1342312008-04-28 12:20:12 +020038
39
Armin Ronacher19cf9c22008-05-01 12:49:53 +020040class Context(object):
Armin Ronacher7259c762008-04-30 13:03:59 +020041 """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
45 be created by hand.
Armin Ronacherc9705c22008-04-27 21:28:03 +020046
Armin Ronacher7259c762008-04-30 13:03:59 +020047 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.
52
53 The template context supports read only dict operations (`get`,
Armin Ronacherf35e2812008-05-06 16:04:10 +020054 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
55 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
56 method that doesn't fail with a `KeyError` but returns an
57 :class:`Undefined` object for missing variables.
Armin Ronacher9706fab2008-04-08 18:49:56 +020058 """
Armin Ronacher771c7502008-05-18 23:14:14 +020059 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
60 'blocks')
Armin Ronachere791c2a2008-04-07 18:39:54 +020061
Armin Ronacher203bfcb2008-04-24 21:54:44 +020062 def __init__(self, environment, parent, name, blocks):
63 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +020064 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +020065 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +020066 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020067 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +020068
69 # bind functions to the context of environment if required
Armin Ronacher2feed1d2008-04-26 16:26:52 +020070 for name, obj in parent.iteritems():
Armin Ronacher203bfcb2008-04-24 21:54:44 +020071 if type(obj) is FunctionType:
72 if getattr(obj, 'contextfunction', 0):
Armin Ronacher2feed1d2008-04-26 16:26:52 +020073 vars[name] = partial(obj, self)
Armin Ronacher203bfcb2008-04-24 21:54:44 +020074 elif getattr(obj, 'environmentfunction', 0):
Armin Ronacher2feed1d2008-04-26 16:26:52 +020075 vars[name] = partial(obj, environment)
Armin Ronacher203bfcb2008-04-24 21:54:44 +020076
77 # create the initial mapping of blocks. Whenever template inheritance
78 # takes place the runtime will update this mapping with the new blocks
79 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +020080 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020081
Armin Ronacher203bfcb2008-04-24 21:54:44 +020082 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +020083 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020084 try:
85 blocks = self.blocks[name]
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020086 block = blocks[blocks.index(current) + 1]
Armin Ronacherc9705c22008-04-27 21:28:03 +020087 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020088 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +020089 'called %r.' % name,
90 name='super')
Armin Ronacherd1342312008-04-28 12:20:12 +020091 wrap = self.environment.autoescape and Markup or (lambda x: x)
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020092 render = lambda: wrap(concat(block(self)))
Armin Ronacherc9705c22008-04-27 21:28:03 +020093 render.__name__ = render.name = name
94 return render
Armin Ronachere791c2a2008-04-07 18:39:54 +020095
Armin Ronacher53042292008-04-26 18:30:19 +020096 def get(self, key, default=None):
Armin Ronacher7259c762008-04-30 13:03:59 +020097 """Returns an item from the template context, if it doesn't exist
98 `default` is returned.
99 """
Armin Ronacherf35e2812008-05-06 16:04:10 +0200100 try:
101 return self[key]
102 except KeyError:
103 return default
104
105 def resolve(self, key):
106 """Looks up a variable like `__getitem__` or `get` but returns an
107 :class:`Undefined` object with the name of the name looked up.
108 """
Armin Ronacher53042292008-04-26 18:30:19 +0200109 if key in self.vars:
110 return self.vars[key]
111 if key in self.parent:
112 return self.parent[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200113 return self.environment.undefined(name=key)
Armin Ronacherb5124e62008-04-25 00:36:14 +0200114
Armin Ronacher9706fab2008-04-08 18:49:56 +0200115 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200116 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200117 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200118
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200119 def get_all(self):
Armin Ronacher7259c762008-04-30 13:03:59 +0200120 """Return a copy of the complete context as dict including the
121 global variables.
122 """
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200123 return dict(self.parent, **self.vars)
124
Armin Ronacherf35e2812008-05-06 16:04:10 +0200125 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200126 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200127 proxy.__doc__ = getattr(dict, meth).__doc__
128 proxy.__name__ = meth
129 return proxy
130
131 keys = _all('keys')
132 values = _all('values')
133 items = _all('items')
134 iterkeys = _all('iterkeys')
135 itervalues = _all('itervalues')
136 iteritems = _all('iteritems')
137 del _all
138
Armin Ronacherb5124e62008-04-25 00:36:14 +0200139 def __contains__(self, name):
140 return name in self.vars or name in self.parent
141
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200142 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200143 """Lookup a variable or raise `KeyError` if the variable is
144 undefined.
145 """
146 item = self.resolve(key)
147 if isinstance(item, Undefined):
148 raise KeyError(key)
149 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200150
Armin Ronacherf059ec12008-04-11 22:21:00 +0200151 def __repr__(self):
152 return '<%s %s of %r>' % (
153 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200154 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200155 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200156 )
157
158
Armin Ronacherc9705c22008-04-27 21:28:03 +0200159class TemplateReference(object):
160 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200161
Armin Ronacherc9705c22008-04-27 21:28:03 +0200162 def __init__(self, context):
163 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200164
Armin Ronacherc9705c22008-04-27 21:28:03 +0200165 def __getitem__(self, name):
Armin Ronacher6df604e2008-05-23 22:18:38 +0200166 func = self.__context.blocks[name][0]
Armin Ronacherd1342312008-04-28 12:20:12 +0200167 wrap = self.__context.environment.autoescape and \
168 Markup or (lambda x: x)
169 render = lambda: wrap(concat(func(self.__context)))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200170 render.__name__ = render.name = name
171 return render
Armin Ronacher62f8a292008-04-13 23:18:05 +0200172
173 def __repr__(self):
174 return '<%s %r>' % (
175 self.__class__.__name__,
Armin Ronacherc9705c22008-04-27 21:28:03 +0200176 self._context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200177 )
178
179
Armin Ronacher32a910f2008-04-26 23:21:03 +0200180class LoopContext(object):
181 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200182
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200183 def __init__(self, iterable, enforce_length=False, recurse=None):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200184 self._iterable = iterable
Armin Ronacher32a910f2008-04-26 23:21:03 +0200185 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200186 self._length = None
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200187 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200188 self.index0 = -1
189 if enforce_length:
190 len(self)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200191
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200192 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200193 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200194 if not args:
195 raise TypeError('no items for cycling given')
196 return args[self.index0 % len(args)]
197
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200198 first = property(lambda x: x.index0 == 0)
199 last = property(lambda x: x.revindex0 == 0)
200 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200201 revindex = property(lambda x: x.length - x.index0)
202 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200203
204 def __len__(self):
205 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200206
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200207 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200208 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200209
Armin Ronacher66a93442008-05-11 23:42:19 +0200210 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200211 if self._recurse is None:
212 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200213 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200214 return self._recurse(iterable, self._recurse)
215
Armin Ronacher66a93442008-05-11 23:42:19 +0200216 # a nifty trick to enhance the error message if someone tried to call
217 # the the loop without or with too many arguments.
218 __call__ = loop; del loop
219
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200220 @property
221 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200222 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200223 try:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200224 # first try to get the length from the iterable (if the
225 # iterable is a sequence)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200226 length = len(self._iterable)
227 except TypeError:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200228 # if that's not possible (ie: iterating over a generator)
229 # we have to convert the iterable into a sequence and
230 # use the length of that.
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200231 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200232 self._next = iter(self._iterable).next
233 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200234 self._length = length
235 return self._length
236
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200237 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200238 return '<%s %r/%r>' % (
239 self.__class__.__name__,
240 self.index,
241 self.length
242 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200243
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200244
Armin Ronachered1e0d42008-05-18 20:25:28 +0200245class LoopContextIterator(object):
246 """The iterator for a loop context."""
247 __slots__ = ('context',)
248
249 def __init__(self, context):
250 self.context = context
251
252 def __iter__(self):
253 return self
254
255 def next(self):
256 ctx = self.context
257 ctx.index0 += 1
258 return ctx._next(), ctx
259
260
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200261class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200262 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200263
Armin Ronacher963f97d2008-04-25 11:44:59 +0200264 def __init__(self, environment, func, name, arguments, defaults,
265 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200266 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200267 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200268 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200269 self.name = name
270 self.arguments = arguments
271 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200272 self.catch_kwargs = catch_kwargs
273 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200274 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200275
276 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200277 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200278 for idx, name in enumerate(self.arguments):
279 try:
280 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200281 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200282 try:
283 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200284 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200285 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200286 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200287 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200288 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200289 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200290 arguments.append(value)
291
292 # it's important that the order of these arguments does not change
293 # if not also changed in the compiler's `function_scoping` method.
294 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200295 if self.caller:
296 caller = kwargs.pop('caller', None)
297 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200298 caller = self._environment.undefined('No caller defined',
299 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200300 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200301 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200302 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200303 elif kwargs:
304 raise TypeError('macro %r takes no keyword argument %r' %
305 (self.name, iter(kwargs).next()))
306 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200307 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200308 elif len(args) > self._argument_count:
309 raise TypeError('macro %r takes not more than %d argument(s)' %
310 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200311 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200312
313 def __repr__(self):
314 return '<%s %s>' % (
315 self.__class__.__name__,
316 self.name is None and 'anonymous' or repr(self.name)
317 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200318
319
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200320def fail_with_undefined_error(self, *args, **kwargs):
321 """Regular callback function for undefined objects that raises an
322 `UndefinedError` on call.
323 """
324 if self._undefined_hint is None:
325 if self._undefined_obj is None:
326 hint = '%r is undefined' % self._undefined_name
327 elif not isinstance(self._undefined_name, basestring):
328 hint = '%r object has no element %r' % (
329 self._undefined_obj.__class__.__name__,
330 self._undefined_name
331 )
332 else:
333 hint = '%r object has no attribute %r' % (
334 self._undefined_obj.__class__.__name__,
335 self._undefined_name
336 )
337 else:
338 hint = self._undefined_hint
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200339 raise self._undefined_exception(hint)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200340
341
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200342class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200343 """The default undefined type. This undefined type can be printed and
344 iterated over, but every other access will raise an :exc:`UndefinedError`:
345
346 >>> foo = Undefined(name='foo')
347 >>> str(foo)
348 ''
349 >>> not foo
350 True
351 >>> foo + 42
352 Traceback (most recent call last):
353 ...
354 jinja2.exceptions.UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200355 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200356 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
357 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200358
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200359 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200360 self._undefined_hint = hint
361 self._undefined_obj = obj
362 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200363 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200364
Armin Ronacherc63243e2008-04-14 22:53:58 +0200365 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
366 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
367 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200368 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
369 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200370
371 def __str__(self):
372 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200373
374 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200375 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200376
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200377 def __unicode__(self):
378 return u''
379
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200380 def __len__(self):
381 return 0
382
383 def __iter__(self):
384 if 0:
385 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200386
387 def __nonzero__(self):
388 return False
389
390
391class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200392 """An undefined that returns the debug info when printed.
393
394 >>> foo = DebugUndefined(name='foo')
395 >>> str(foo)
396 '{{ foo }}'
397 >>> not foo
398 True
399 >>> foo + 42
400 Traceback (most recent call last):
401 ...
402 jinja2.exceptions.UndefinedError: 'foo' is undefined
403 """
Armin Ronacher53042292008-04-26 18:30:19 +0200404 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200405
406 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200407 if self._undefined_hint is None:
408 if self._undefined_obj is None:
409 return u'{{ %s }}' % self._undefined_name
410 return '{{ no such element: %s[%r] }}' % (
411 self._undefined_obj.__class__.__name__,
412 self._undefined_name
413 )
414 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200415
416
417class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200418 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200419 tests and all kinds of comparisons. In other words: you can do nothing
420 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200421
422 >>> foo = StrictUndefined(name='foo')
423 >>> str(foo)
424 Traceback (most recent call last):
425 ...
426 jinja2.exceptions.UndefinedError: 'foo' is undefined
427 >>> not foo
428 Traceback (most recent call last):
429 ...
430 jinja2.exceptions.UndefinedError: 'foo' is undefined
431 >>> foo + 42
432 Traceback (most recent call last):
433 ...
434 jinja2.exceptions.UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200435 """
Armin Ronacher53042292008-04-26 18:30:19 +0200436 __slots__ = ()
437 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
438 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200439
Armin Ronacher53042292008-04-26 18:30:19 +0200440
441# remove remaining slots attributes, after the metaclass did the magic they
442# are unneeded and irritating as they contain wrong data for the subclasses.
443del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__