blob: f5639f8d5f34296212653b236bd364a037c10def [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 Ronacher24b65582008-05-26 13:35:58 +020012from types import FunctionType, MethodType
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
Armin Ronacher24b65582008-05-26 13:35:58 +020023_context_function_types = (FunctionType, MethodType)
24
Armin Ronacher0611e492008-04-25 23:44:14 +020025
Armin Ronacherdc02b642008-05-15 22:47:27 +020026def markup_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020027 """Concatenation that escapes if necessary and converts to unicode."""
28 buf = []
Armin Ronacherdc02b642008-05-15 22:47:27 +020029 iterator = imap(soft_unicode, seq)
Armin Ronacherd1342312008-04-28 12:20:12 +020030 for arg in iterator:
31 buf.append(arg)
32 if hasattr(arg, '__html__'):
33 return Markup(u'').join(chain(buf, iterator))
34 return concat(buf)
35
36
Armin Ronacherdc02b642008-05-15 22:47:27 +020037def unicode_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020038 """Simple args to unicode conversion and concatenation."""
Armin Ronacherdc02b642008-05-15 22:47:27 +020039 return concat(imap(unicode, seq))
Armin Ronacherd1342312008-04-28 12:20:12 +020040
41
Armin Ronacher19cf9c22008-05-01 12:49:53 +020042class Context(object):
Armin Ronacher7259c762008-04-30 13:03:59 +020043 """The template context holds the variables of a template. It stores the
44 values passed to the template and also the names the template exports.
45 Creating instances is neither supported nor useful as it's created
46 automatically at various stages of the template evaluation and should not
47 be created by hand.
Armin Ronacherc9705c22008-04-27 21:28:03 +020048
Armin Ronacher7259c762008-04-30 13:03:59 +020049 The context is immutable. Modifications on :attr:`parent` **must not**
50 happen and modifications on :attr:`vars` are allowed from generated
51 template code only. Template filters and global functions marked as
52 :func:`contextfunction`\s get the active context passed as first argument
53 and are allowed to access the context read-only.
54
55 The template context supports read only dict operations (`get`,
Armin Ronacherf35e2812008-05-06 16:04:10 +020056 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
57 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
58 method that doesn't fail with a `KeyError` but returns an
59 :class:`Undefined` object for missing variables.
Armin Ronacher9706fab2008-04-08 18:49:56 +020060 """
Armin Ronacher771c7502008-05-18 23:14:14 +020061 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
62 'blocks')
Armin Ronachere791c2a2008-04-07 18:39:54 +020063
Armin Ronacher203bfcb2008-04-24 21:54:44 +020064 def __init__(self, environment, parent, name, blocks):
65 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +020066 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +020067 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +020068 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020069 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +020070
Armin Ronacher203bfcb2008-04-24 21:54:44 +020071 # create the initial mapping of blocks. Whenever template inheritance
72 # takes place the runtime will update this mapping with the new blocks
73 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +020074 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020075
Armin Ronacher203bfcb2008-04-24 21:54:44 +020076 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +020077 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020078 try:
79 blocks = self.blocks[name]
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020080 block = blocks[blocks.index(current) + 1]
Armin Ronacherc9705c22008-04-27 21:28:03 +020081 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020082 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +020083 'called %r.' % name,
84 name='super')
Armin Ronacherd1342312008-04-28 12:20:12 +020085 wrap = self.environment.autoescape and Markup or (lambda x: x)
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020086 render = lambda: wrap(concat(block(self)))
Armin Ronacherc9705c22008-04-27 21:28:03 +020087 render.__name__ = render.name = name
88 return render
Armin Ronachere791c2a2008-04-07 18:39:54 +020089
Armin Ronacher53042292008-04-26 18:30:19 +020090 def get(self, key, default=None):
Armin Ronacher7259c762008-04-30 13:03:59 +020091 """Returns an item from the template context, if it doesn't exist
92 `default` is returned.
93 """
Armin Ronacherf35e2812008-05-06 16:04:10 +020094 try:
95 return self[key]
96 except KeyError:
97 return default
98
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.
102 """
Armin Ronacher53042292008-04-26 18:30:19 +0200103 if key in self.vars:
104 return self.vars[key]
105 if key in self.parent:
106 return self.parent[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200107 return self.environment.undefined(name=key)
Armin Ronacherb5124e62008-04-25 00:36:14 +0200108
Armin Ronacher9706fab2008-04-08 18:49:56 +0200109 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200110 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200111 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200112
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200113 def get_all(self):
Armin Ronacher7259c762008-04-30 13:03:59 +0200114 """Return a copy of the complete context as dict including the
Armin Ronacher5411ce72008-05-25 11:36:22 +0200115 exported variables.
Armin Ronacher7259c762008-04-30 13:03:59 +0200116 """
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200117 return dict(self.parent, **self.vars)
118
Armin Ronacherfd310492008-05-25 00:16:51 +0200119 def call(__self, __obj, *args, **kwargs):
120 """Called by the template code to inject the current context
121 or environment as first arguments. Then forwards the call to
122 the object with the arguments and keyword arguments.
123 """
Armin Ronacher24b65582008-05-26 13:35:58 +0200124 if __debug__:
125 __traceback_hide__ = True
126 if isinstance(__obj, _context_function_types):
127 if getattr(__obj, 'contextfunction', 0):
128 args = (__self,) + args
129 elif getattr(__obj, 'environmentfunction', 0):
130 args = (__self.environment,) + args
Armin Ronacherfd310492008-05-25 00:16:51 +0200131 return __obj(*args, **kwargs)
132
Armin Ronacherf35e2812008-05-06 16:04:10 +0200133 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200134 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200135 proxy.__doc__ = getattr(dict, meth).__doc__
136 proxy.__name__ = meth
137 return proxy
138
139 keys = _all('keys')
140 values = _all('values')
141 items = _all('items')
142 iterkeys = _all('iterkeys')
143 itervalues = _all('itervalues')
144 iteritems = _all('iteritems')
145 del _all
146
Armin Ronacherb5124e62008-04-25 00:36:14 +0200147 def __contains__(self, name):
148 return name in self.vars or name in self.parent
149
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200150 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200151 """Lookup a variable or raise `KeyError` if the variable is
152 undefined.
153 """
154 item = self.resolve(key)
155 if isinstance(item, Undefined):
156 raise KeyError(key)
157 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200158
Armin Ronacherf059ec12008-04-11 22:21:00 +0200159 def __repr__(self):
160 return '<%s %s of %r>' % (
161 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200162 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200163 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200164 )
165
166
Armin Ronacherc9705c22008-04-27 21:28:03 +0200167class TemplateReference(object):
168 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200169
Armin Ronacherc9705c22008-04-27 21:28:03 +0200170 def __init__(self, context):
171 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200172
Armin Ronacherc9705c22008-04-27 21:28:03 +0200173 def __getitem__(self, name):
Armin Ronacher6df604e2008-05-23 22:18:38 +0200174 func = self.__context.blocks[name][0]
Armin Ronacherd1342312008-04-28 12:20:12 +0200175 wrap = self.__context.environment.autoescape and \
176 Markup or (lambda x: x)
177 render = lambda: wrap(concat(func(self.__context)))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200178 render.__name__ = render.name = name
179 return render
Armin Ronacher62f8a292008-04-13 23:18:05 +0200180
181 def __repr__(self):
182 return '<%s %r>' % (
183 self.__class__.__name__,
Armin Ronacherc9705c22008-04-27 21:28:03 +0200184 self._context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200185 )
186
187
Armin Ronacher32a910f2008-04-26 23:21:03 +0200188class LoopContext(object):
189 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200190
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200191 def __init__(self, iterable, enforce_length=False, recurse=None):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200192 self._iterable = iterable
Armin Ronacher32a910f2008-04-26 23:21:03 +0200193 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200194 self._length = None
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200195 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200196 self.index0 = -1
197 if enforce_length:
198 len(self)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200199
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200200 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200201 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200202 if not args:
203 raise TypeError('no items for cycling given')
204 return args[self.index0 % len(args)]
205
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200206 first = property(lambda x: x.index0 == 0)
207 last = property(lambda x: x.revindex0 == 0)
208 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200209 revindex = property(lambda x: x.length - x.index0)
210 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200211
212 def __len__(self):
213 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200214
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200215 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200216 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200217
Armin Ronacher66a93442008-05-11 23:42:19 +0200218 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200219 if self._recurse is None:
220 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200221 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200222 return self._recurse(iterable, self._recurse)
223
Armin Ronacher66a93442008-05-11 23:42:19 +0200224 # a nifty trick to enhance the error message if someone tried to call
225 # the the loop without or with too many arguments.
226 __call__ = loop; del loop
227
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200228 @property
229 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200230 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200231 try:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200232 # first try to get the length from the iterable (if the
233 # iterable is a sequence)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200234 length = len(self._iterable)
235 except TypeError:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200236 # if that's not possible (ie: iterating over a generator)
237 # we have to convert the iterable into a sequence and
238 # use the length of that.
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200239 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200240 self._next = iter(self._iterable).next
241 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200242 self._length = length
243 return self._length
244
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200245 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200246 return '<%s %r/%r>' % (
247 self.__class__.__name__,
248 self.index,
249 self.length
250 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200251
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200252
Armin Ronachered1e0d42008-05-18 20:25:28 +0200253class LoopContextIterator(object):
254 """The iterator for a loop context."""
255 __slots__ = ('context',)
256
257 def __init__(self, context):
258 self.context = context
259
260 def __iter__(self):
261 return self
262
263 def next(self):
264 ctx = self.context
265 ctx.index0 += 1
266 return ctx._next(), ctx
267
268
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200269class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200270 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200271
Armin Ronacher963f97d2008-04-25 11:44:59 +0200272 def __init__(self, environment, func, name, arguments, defaults,
273 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200274 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200275 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200276 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200277 self.name = name
278 self.arguments = arguments
279 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200280 self.catch_kwargs = catch_kwargs
281 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200282 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200283
284 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200285 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200286 for idx, name in enumerate(self.arguments):
287 try:
288 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200289 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200290 try:
291 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200292 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200293 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200294 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200295 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200296 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200297 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200298 arguments.append(value)
299
300 # it's important that the order of these arguments does not change
301 # if not also changed in the compiler's `function_scoping` method.
302 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200303 if self.caller:
304 caller = kwargs.pop('caller', None)
305 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200306 caller = self._environment.undefined('No caller defined',
307 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200308 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200309 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200310 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200311 elif kwargs:
312 raise TypeError('macro %r takes no keyword argument %r' %
313 (self.name, iter(kwargs).next()))
314 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200315 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200316 elif len(args) > self._argument_count:
317 raise TypeError('macro %r takes not more than %d argument(s)' %
318 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200319 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200320
321 def __repr__(self):
322 return '<%s %s>' % (
323 self.__class__.__name__,
324 self.name is None and 'anonymous' or repr(self.name)
325 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200326
327
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200328def fail_with_undefined_error(self, *args, **kwargs):
329 """Regular callback function for undefined objects that raises an
330 `UndefinedError` on call.
331 """
332 if self._undefined_hint is None:
333 if self._undefined_obj is None:
334 hint = '%r is undefined' % self._undefined_name
335 elif not isinstance(self._undefined_name, basestring):
336 hint = '%r object has no element %r' % (
337 self._undefined_obj.__class__.__name__,
338 self._undefined_name
339 )
340 else:
341 hint = '%r object has no attribute %r' % (
342 self._undefined_obj.__class__.__name__,
343 self._undefined_name
344 )
345 else:
346 hint = self._undefined_hint
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200347 raise self._undefined_exception(hint)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200348
349
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200350class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200351 """The default undefined type. This undefined type can be printed and
352 iterated over, but every other access will raise an :exc:`UndefinedError`:
353
354 >>> foo = Undefined(name='foo')
355 >>> str(foo)
356 ''
357 >>> not foo
358 True
359 >>> foo + 42
360 Traceback (most recent call last):
361 ...
362 jinja2.exceptions.UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200363 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200364 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
365 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200366
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200367 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200368 self._undefined_hint = hint
369 self._undefined_obj = obj
370 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200371 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200372
Armin Ronacherc63243e2008-04-14 22:53:58 +0200373 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
374 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
375 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200376 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
377 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200378
379 def __str__(self):
380 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200381
382 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200383 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200384
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200385 def __unicode__(self):
386 return u''
387
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200388 def __len__(self):
389 return 0
390
391 def __iter__(self):
392 if 0:
393 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200394
395 def __nonzero__(self):
396 return False
397
398
399class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200400 """An undefined that returns the debug info when printed.
401
402 >>> foo = DebugUndefined(name='foo')
403 >>> str(foo)
404 '{{ foo }}'
405 >>> not foo
406 True
407 >>> foo + 42
408 Traceback (most recent call last):
409 ...
410 jinja2.exceptions.UndefinedError: 'foo' is undefined
411 """
Armin Ronacher53042292008-04-26 18:30:19 +0200412 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200413
414 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200415 if self._undefined_hint is None:
416 if self._undefined_obj is None:
417 return u'{{ %s }}' % self._undefined_name
418 return '{{ no such element: %s[%r] }}' % (
419 self._undefined_obj.__class__.__name__,
420 self._undefined_name
421 )
422 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200423
424
425class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200426 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200427 tests and all kinds of comparisons. In other words: you can do nothing
428 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200429
430 >>> foo = StrictUndefined(name='foo')
431 >>> str(foo)
432 Traceback (most recent call last):
433 ...
434 jinja2.exceptions.UndefinedError: 'foo' is undefined
435 >>> not foo
436 Traceback (most recent call last):
437 ...
438 jinja2.exceptions.UndefinedError: 'foo' is undefined
439 >>> foo + 42
440 Traceback (most recent call last):
441 ...
442 jinja2.exceptions.UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200443 """
Armin Ronacher53042292008-04-26 18:30:19 +0200444 __slots__ = ()
445 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
446 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200447
Armin Ronacher53042292008-04-26 18:30:19 +0200448
449# remove remaining slots attributes, after the metaclass did the magic they
450# are unneeded and irritating as they contain wrong data for the subclasses.
451del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__