blob: 590bed98cee1dbe9f14435a168ee322adfaf601e [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
Armin Ronacher203bfcb2008-04-24 21:54:44 +020069 # create the initial mapping of blocks. Whenever template inheritance
70 # takes place the runtime will update this mapping with the new blocks
71 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +020072 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020073
Armin Ronacher203bfcb2008-04-24 21:54:44 +020074 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +020075 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020076 try:
77 blocks = self.blocks[name]
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020078 block = blocks[blocks.index(current) + 1]
Armin Ronacherc9705c22008-04-27 21:28:03 +020079 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020080 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +020081 'called %r.' % name,
82 name='super')
Armin Ronacherd1342312008-04-28 12:20:12 +020083 wrap = self.environment.autoescape and Markup or (lambda x: x)
Armin Ronacher83fbc0f2008-05-15 12:22:28 +020084 render = lambda: wrap(concat(block(self)))
Armin Ronacherc9705c22008-04-27 21:28:03 +020085 render.__name__ = render.name = name
86 return render
Armin Ronachere791c2a2008-04-07 18:39:54 +020087
Armin Ronacher53042292008-04-26 18:30:19 +020088 def get(self, key, default=None):
Armin Ronacher7259c762008-04-30 13:03:59 +020089 """Returns an item from the template context, if it doesn't exist
90 `default` is returned.
91 """
Armin Ronacherf35e2812008-05-06 16:04:10 +020092 try:
93 return self[key]
94 except KeyError:
95 return default
96
97 def resolve(self, key):
98 """Looks up a variable like `__getitem__` or `get` but returns an
99 :class:`Undefined` object with the name of the name looked up.
100 """
Armin Ronacher53042292008-04-26 18:30:19 +0200101 if key in self.vars:
102 return self.vars[key]
103 if key in self.parent:
104 return self.parent[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200105 return self.environment.undefined(name=key)
Armin Ronacherb5124e62008-04-25 00:36:14 +0200106
Armin Ronacher9706fab2008-04-08 18:49:56 +0200107 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200108 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200109 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200110
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200111 def get_all(self):
Armin Ronacher7259c762008-04-30 13:03:59 +0200112 """Return a copy of the complete context as dict including the
Armin Ronacher5411ce72008-05-25 11:36:22 +0200113 exported variables.
Armin Ronacher7259c762008-04-30 13:03:59 +0200114 """
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200115 return dict(self.parent, **self.vars)
116
Armin Ronacherfd310492008-05-25 00:16:51 +0200117 def call(__self, __obj, *args, **kwargs):
118 """Called by the template code to inject the current context
119 or environment as first arguments. Then forwards the call to
120 the object with the arguments and keyword arguments.
121 """
122 if getattr(__obj, 'contextfunction', 0):
123 args = (__self,) + args
124 elif getattr(__obj, 'environmentfunction', 0):
125 args = (__self.environment,) + args
126 return __obj(*args, **kwargs)
127
Armin Ronacherf35e2812008-05-06 16:04:10 +0200128 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200129 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200130 proxy.__doc__ = getattr(dict, meth).__doc__
131 proxy.__name__ = meth
132 return proxy
133
134 keys = _all('keys')
135 values = _all('values')
136 items = _all('items')
137 iterkeys = _all('iterkeys')
138 itervalues = _all('itervalues')
139 iteritems = _all('iteritems')
140 del _all
141
Armin Ronacherb5124e62008-04-25 00:36:14 +0200142 def __contains__(self, name):
143 return name in self.vars or name in self.parent
144
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200145 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200146 """Lookup a variable or raise `KeyError` if the variable is
147 undefined.
148 """
149 item = self.resolve(key)
150 if isinstance(item, Undefined):
151 raise KeyError(key)
152 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200153
Armin Ronacherf059ec12008-04-11 22:21:00 +0200154 def __repr__(self):
155 return '<%s %s of %r>' % (
156 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200157 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200158 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200159 )
160
161
Armin Ronacherc9705c22008-04-27 21:28:03 +0200162class TemplateReference(object):
163 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200164
Armin Ronacherc9705c22008-04-27 21:28:03 +0200165 def __init__(self, context):
166 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200167
Armin Ronacherc9705c22008-04-27 21:28:03 +0200168 def __getitem__(self, name):
Armin Ronacher6df604e2008-05-23 22:18:38 +0200169 func = self.__context.blocks[name][0]
Armin Ronacherd1342312008-04-28 12:20:12 +0200170 wrap = self.__context.environment.autoescape and \
171 Markup or (lambda x: x)
172 render = lambda: wrap(concat(func(self.__context)))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200173 render.__name__ = render.name = name
174 return render
Armin Ronacher62f8a292008-04-13 23:18:05 +0200175
176 def __repr__(self):
177 return '<%s %r>' % (
178 self.__class__.__name__,
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 self._context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200180 )
181
182
Armin Ronacher32a910f2008-04-26 23:21:03 +0200183class LoopContext(object):
184 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200185
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200186 def __init__(self, iterable, enforce_length=False, recurse=None):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200187 self._iterable = iterable
Armin Ronacher32a910f2008-04-26 23:21:03 +0200188 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200189 self._length = None
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200190 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200191 self.index0 = -1
192 if enforce_length:
193 len(self)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200194
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200195 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200196 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200197 if not args:
198 raise TypeError('no items for cycling given')
199 return args[self.index0 % len(args)]
200
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200201 first = property(lambda x: x.index0 == 0)
202 last = property(lambda x: x.revindex0 == 0)
203 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200204 revindex = property(lambda x: x.length - x.index0)
205 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200206
207 def __len__(self):
208 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200209
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200210 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200211 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200212
Armin Ronacher66a93442008-05-11 23:42:19 +0200213 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200214 if self._recurse is None:
215 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200216 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200217 return self._recurse(iterable, self._recurse)
218
Armin Ronacher66a93442008-05-11 23:42:19 +0200219 # a nifty trick to enhance the error message if someone tried to call
220 # the the loop without or with too many arguments.
221 __call__ = loop; del loop
222
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200223 @property
224 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200225 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200226 try:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200227 # first try to get the length from the iterable (if the
228 # iterable is a sequence)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200229 length = len(self._iterable)
230 except TypeError:
Armin Ronachered1e0d42008-05-18 20:25:28 +0200231 # if that's not possible (ie: iterating over a generator)
232 # we have to convert the iterable into a sequence and
233 # use the length of that.
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200234 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200235 self._next = iter(self._iterable).next
236 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200237 self._length = length
238 return self._length
239
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200240 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200241 return '<%s %r/%r>' % (
242 self.__class__.__name__,
243 self.index,
244 self.length
245 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200246
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200247
Armin Ronachered1e0d42008-05-18 20:25:28 +0200248class LoopContextIterator(object):
249 """The iterator for a loop context."""
250 __slots__ = ('context',)
251
252 def __init__(self, context):
253 self.context = context
254
255 def __iter__(self):
256 return self
257
258 def next(self):
259 ctx = self.context
260 ctx.index0 += 1
261 return ctx._next(), ctx
262
263
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200264class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200265 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200266
Armin Ronacher963f97d2008-04-25 11:44:59 +0200267 def __init__(self, environment, func, name, arguments, defaults,
268 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200269 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200270 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200271 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200272 self.name = name
273 self.arguments = arguments
274 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200275 self.catch_kwargs = catch_kwargs
276 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200277 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200278
279 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200280 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200281 for idx, name in enumerate(self.arguments):
282 try:
283 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200284 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200285 try:
286 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200287 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200288 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200289 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200290 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200291 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200292 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200293 arguments.append(value)
294
295 # it's important that the order of these arguments does not change
296 # if not also changed in the compiler's `function_scoping` method.
297 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200298 if self.caller:
299 caller = kwargs.pop('caller', None)
300 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200301 caller = self._environment.undefined('No caller defined',
302 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200303 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200304 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200305 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200306 elif kwargs:
307 raise TypeError('macro %r takes no keyword argument %r' %
308 (self.name, iter(kwargs).next()))
309 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200310 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200311 elif len(args) > self._argument_count:
312 raise TypeError('macro %r takes not more than %d argument(s)' %
313 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200314 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200315
316 def __repr__(self):
317 return '<%s %s>' % (
318 self.__class__.__name__,
319 self.name is None and 'anonymous' or repr(self.name)
320 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200321
322
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200323def fail_with_undefined_error(self, *args, **kwargs):
324 """Regular callback function for undefined objects that raises an
325 `UndefinedError` on call.
326 """
327 if self._undefined_hint is None:
328 if self._undefined_obj is None:
329 hint = '%r is undefined' % self._undefined_name
330 elif not isinstance(self._undefined_name, basestring):
331 hint = '%r object has no element %r' % (
332 self._undefined_obj.__class__.__name__,
333 self._undefined_name
334 )
335 else:
336 hint = '%r object has no attribute %r' % (
337 self._undefined_obj.__class__.__name__,
338 self._undefined_name
339 )
340 else:
341 hint = self._undefined_hint
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200342 raise self._undefined_exception(hint)
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200343
344
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200345class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200346 """The default undefined type. This undefined type can be printed and
347 iterated over, but every other access will raise an :exc:`UndefinedError`:
348
349 >>> foo = Undefined(name='foo')
350 >>> str(foo)
351 ''
352 >>> not foo
353 True
354 >>> foo + 42
355 Traceback (most recent call last):
356 ...
357 jinja2.exceptions.UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200358 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200359 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
360 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200361
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200362 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200363 self._undefined_hint = hint
364 self._undefined_obj = obj
365 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200366 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200367
Armin Ronacherc63243e2008-04-14 22:53:58 +0200368 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
369 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
370 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200371 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
372 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200373
374 def __str__(self):
375 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200376
377 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200378 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200379
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200380 def __unicode__(self):
381 return u''
382
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200383 def __len__(self):
384 return 0
385
386 def __iter__(self):
387 if 0:
388 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200389
390 def __nonzero__(self):
391 return False
392
393
394class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200395 """An undefined that returns the debug info when printed.
396
397 >>> foo = DebugUndefined(name='foo')
398 >>> str(foo)
399 '{{ foo }}'
400 >>> not foo
401 True
402 >>> foo + 42
403 Traceback (most recent call last):
404 ...
405 jinja2.exceptions.UndefinedError: 'foo' is undefined
406 """
Armin Ronacher53042292008-04-26 18:30:19 +0200407 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200408
409 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200410 if self._undefined_hint is None:
411 if self._undefined_obj is None:
412 return u'{{ %s }}' % self._undefined_name
413 return '{{ no such element: %s[%r] }}' % (
414 self._undefined_obj.__class__.__name__,
415 self._undefined_name
416 )
417 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200418
419
420class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200421 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200422 tests and all kinds of comparisons. In other words: you can do nothing
423 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200424
425 >>> foo = StrictUndefined(name='foo')
426 >>> str(foo)
427 Traceback (most recent call last):
428 ...
429 jinja2.exceptions.UndefinedError: 'foo' is undefined
430 >>> not foo
431 Traceback (most recent call last):
432 ...
433 jinja2.exceptions.UndefinedError: 'foo' is undefined
434 >>> foo + 42
435 Traceback (most recent call last):
436 ...
437 jinja2.exceptions.UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200438 """
Armin Ronacher53042292008-04-26 18:30:19 +0200439 __slots__ = ()
440 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
441 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200442
Armin Ronacher53042292008-04-26 18:30:19 +0200443
444# remove remaining slots attributes, after the metaclass did the magic they
445# are unneeded and irritating as they contain wrong data for the subclasses.
446del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__