blob: 085120bd30bf52685b2f3954ed950091c4ea9d1e [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 Ronacherf35e2812008-05-06 16:04:10 +0200143 """Lookup a variable or raise `KeyError`."""
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200144 if key in self.vars:
145 return self.vars[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200146 return self.parent[key]
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200147
Armin Ronacherf059ec12008-04-11 22:21:00 +0200148 def __repr__(self):
149 return '<%s %s of %r>' % (
150 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200151 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200152 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200153 )
154
155
Armin Ronacherc9705c22008-04-27 21:28:03 +0200156class TemplateReference(object):
157 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200158
Armin Ronacherc9705c22008-04-27 21:28:03 +0200159 def __init__(self, context):
160 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200161
Armin Ronacherc9705c22008-04-27 21:28:03 +0200162 def __getitem__(self, name):
163 func = self.__context.blocks[name][-1]
Armin Ronacherd1342312008-04-28 12:20:12 +0200164 wrap = self.__context.environment.autoescape and \
165 Markup or (lambda x: x)
166 render = lambda: wrap(concat(func(self.__context)))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200167 render.__name__ = render.name = name
168 return render
Armin Ronacher62f8a292008-04-13 23:18:05 +0200169
170 def __repr__(self):
171 return '<%s %r>' % (
172 self.__class__.__name__,
Armin Ronacherc9705c22008-04-27 21:28:03 +0200173 self._context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200174 )
175
176
Armin Ronacher32a910f2008-04-26 23:21:03 +0200177class LoopContext(object):
178 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200179
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200180 def __init__(self, iterable, enforce_length=False, recurse=None):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200181 self._iterable = iterable
Armin Ronacher32a910f2008-04-26 23:21:03 +0200182 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200183 self._length = None
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200184 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200185 self.index0 = -1
186 if enforce_length:
187 len(self)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200188
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200189 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200190 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200191 if not args:
192 raise TypeError('no items for cycling given')
193 return args[self.index0 % len(args)]
194
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200195 first = property(lambda x: x.index0 == 0)
196 last = property(lambda x: x.revindex0 == 0)
197 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200198 revindex = property(lambda x: x.length - x.index0)
199 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200200
201 def __len__(self):
202 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200203
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200204 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200205 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200206
Armin Ronacher66a93442008-05-11 23:42:19 +0200207 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200208 if self._recurse is None:
209 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200210 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200211 return self._recurse(iterable, self._recurse)
212
Armin Ronacher66a93442008-05-11 23:42:19 +0200213 # a nifty trick to enhance the error message if someone tried to call
214 # the the loop without or with too many arguments.
215 __call__ = loop; del loop
216
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200217 @property
218 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200219 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200220 try:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200221 # first try to get the length from the iterable (if the
222 # iterable is a sequence)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200223 length = len(self._iterable)
224 except TypeError:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200225 # if that's not possible (ie: iterating over a generator)
226 # we have to convert the iterable into a sequence and
227 # use the length of that.
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200228 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200229 self._next = iter(self._iterable).next
230 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200231 self._length = length
232 return self._length
233
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200234 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200235 return '<%s %r/%r>' % (
236 self.__class__.__name__,
237 self.index,
238 self.length
239 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200240
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200241
Armin Ronachered1e0d42008-05-18 20:25:28 +0200242class LoopContextIterator(object):
243 """The iterator for a loop context."""
244 __slots__ = ('context',)
245
246 def __init__(self, context):
247 self.context = context
248
249 def __iter__(self):
250 return self
251
252 def next(self):
253 ctx = self.context
254 ctx.index0 += 1
255 return ctx._next(), ctx
256
257
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200258class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200259 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200260
Armin Ronacher963f97d2008-04-25 11:44:59 +0200261 def __init__(self, environment, func, name, arguments, defaults,
262 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200263 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200264 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200265 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200266 self.name = name
267 self.arguments = arguments
268 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200269 self.catch_kwargs = catch_kwargs
270 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200271 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200272
273 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200274 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200275 for idx, name in enumerate(self.arguments):
276 try:
277 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200278 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200279 try:
280 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200281 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200282 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200283 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200284 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200285 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200286 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200287 arguments.append(value)
288
289 # it's important that the order of these arguments does not change
290 # if not also changed in the compiler's `function_scoping` method.
291 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200292 if self.caller:
293 caller = kwargs.pop('caller', None)
294 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200295 caller = self._environment.undefined('No caller defined',
296 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200297 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200298 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200299 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200300 elif kwargs:
301 raise TypeError('macro %r takes no keyword argument %r' %
302 (self.name, iter(kwargs).next()))
303 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200304 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200305 elif len(args) > self._argument_count:
306 raise TypeError('macro %r takes not more than %d argument(s)' %
307 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200308 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200309
310 def __repr__(self):
311 return '<%s %s>' % (
312 self.__class__.__name__,
313 self.name is None and 'anonymous' or repr(self.name)
314 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200315
316
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200317def fail_with_undefined_error(self, *args, **kwargs):
318 """Regular callback function for undefined objects that raises an
319 `UndefinedError` on call.
320 """
321 if self._undefined_hint is None:
322 if self._undefined_obj is None:
323 hint = '%r is undefined' % self._undefined_name
324 elif not isinstance(self._undefined_name, basestring):
325 hint = '%r object has no element %r' % (
326 self._undefined_obj.__class__.__name__,
327 self._undefined_name
328 )
329 else:
330 hint = '%r object has no attribute %r' % (
331 self._undefined_obj.__class__.__name__,
332 self._undefined_name
333 )
334 else:
335 hint = self._undefined_hint
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200336 raise self._undefined_exception(hint)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200337
338
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200339class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200340 """The default undefined type. This undefined type can be printed and
341 iterated over, but every other access will raise an :exc:`UndefinedError`:
342
343 >>> foo = Undefined(name='foo')
344 >>> str(foo)
345 ''
346 >>> not foo
347 True
348 >>> foo + 42
349 Traceback (most recent call last):
350 ...
351 jinja2.exceptions.UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200352 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200353 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
354 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200355
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200356 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200357 self._undefined_hint = hint
358 self._undefined_obj = obj
359 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200360 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200361
Armin Ronacherc63243e2008-04-14 22:53:58 +0200362 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
363 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
364 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200365 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
366 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200367
368 def __str__(self):
369 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200370
371 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200372 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200373
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200374 def __unicode__(self):
375 return u''
376
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200377 def __len__(self):
378 return 0
379
380 def __iter__(self):
381 if 0:
382 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200383
384 def __nonzero__(self):
385 return False
386
387
388class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200389 """An undefined that returns the debug info when printed.
390
391 >>> foo = DebugUndefined(name='foo')
392 >>> str(foo)
393 '{{ foo }}'
394 >>> not foo
395 True
396 >>> foo + 42
397 Traceback (most recent call last):
398 ...
399 jinja2.exceptions.UndefinedError: 'foo' is undefined
400 """
Armin Ronacher53042292008-04-26 18:30:19 +0200401 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200402
403 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200404 if self._undefined_hint is None:
405 if self._undefined_obj is None:
406 return u'{{ %s }}' % self._undefined_name
407 return '{{ no such element: %s[%r] }}' % (
408 self._undefined_obj.__class__.__name__,
409 self._undefined_name
410 )
411 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200412
413
414class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200415 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200416 tests and all kinds of comparisons. In other words: you can do nothing
417 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200418
419 >>> foo = StrictUndefined(name='foo')
420 >>> str(foo)
421 Traceback (most recent call last):
422 ...
423 jinja2.exceptions.UndefinedError: 'foo' is undefined
424 >>> not foo
425 Traceback (most recent call last):
426 ...
427 jinja2.exceptions.UndefinedError: 'foo' is undefined
428 >>> foo + 42
429 Traceback (most recent call last):
430 ...
431 jinja2.exceptions.UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200432 """
Armin Ronacher53042292008-04-26 18:30:19 +0200433 __slots__ = ()
434 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
435 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200436
Armin Ronacher53042292008-04-26 18:30:19 +0200437
438# remove remaining slots attributes, after the metaclass did the magic they
439# are unneeded and irritating as they contain wrong data for the subclasses.
440del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__