blob: 013d98721dcfafadc0c2cfac6c3550de27e15529 [file] [log] [blame]
Armin Ronachere791c2a2008-04-07 18:39:54 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.runtime
4 ~~~~~~~~~~~~~~
5
6 Runtime helpers.
7
Armin Ronacher62ccd1b2009-01-04 14:26:19 +01008 :copyright: (c) 2009 by the Jinja Team.
Armin Ronacherd7764372008-07-15 00:11:14 +02009 :license: BSD.
Armin Ronachere791c2a2008-04-07 18:39:54 +020010"""
Armin Ronacher1ae4fdf2008-04-28 20:49:51 +020011import sys
Armin Ronacherd1342312008-04-28 12:20:12 +020012from itertools import chain, imap
Armin Ronacherce677102008-08-17 19:43:22 +020013from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
14 concat, MethodType, FunctionType
Armin Ronacher37f58ce2008-12-27 13:10:38 +010015from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
16 TemplateNotFound
Armin Ronachere791c2a2008-04-07 18:39:54 +020017
18
Armin Ronacher2feed1d2008-04-26 16:26:52 +020019# these variables are exported to the template runtime
Armin Ronacher74a0cd92009-02-19 15:56:53 +010020__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
Armin Ronacher19cf9c22008-05-01 12:49:53 +020021 'TemplateRuntimeError', 'missing', 'concat', 'escape',
Armin Ronacher37f58ce2008-12-27 13:10:38 +010022 'markup_join', 'unicode_join', 'TemplateNotFound']
Armin Ronacher0611e492008-04-25 23:44:14 +020023
Armin Ronacher9a0078d2008-08-13 18:24:17 +020024
Armin Ronacherce677102008-08-17 19:43:22 +020025#: the types we support for context functions
26_context_function_types = (FunctionType, MethodType)
Armin Ronacher24b65582008-05-26 13:35:58 +020027
Armin Ronacher0611e492008-04-25 23:44:14 +020028
Armin Ronacherdc02b642008-05-15 22:47:27 +020029def markup_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020030 """Concatenation that escapes if necessary and converts to unicode."""
31 buf = []
Armin Ronacherdc02b642008-05-15 22:47:27 +020032 iterator = imap(soft_unicode, seq)
Armin Ronacherd1342312008-04-28 12:20:12 +020033 for arg in iterator:
34 buf.append(arg)
35 if hasattr(arg, '__html__'):
36 return Markup(u'').join(chain(buf, iterator))
37 return concat(buf)
38
39
Armin Ronacherdc02b642008-05-15 22:47:27 +020040def unicode_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020041 """Simple args to unicode conversion and concatenation."""
Armin Ronacherdc02b642008-05-15 22:47:27 +020042 return concat(imap(unicode, seq))
Armin Ronacherd1342312008-04-28 12:20:12 +020043
44
Armin Ronacher74a0cd92009-02-19 15:56:53 +010045def new_context(environment, template_name, blocks, vars=None,
46 shared=None, globals=None, locals=None):
47 """Internal helper to for context creation."""
48 if vars is None:
49 vars = {}
50 if shared:
51 parent = vars
52 else:
53 parent = dict(globals or (), **vars)
54 if locals:
55 # if the parent is shared a copy should be created because
56 # we don't want to modify the dict passed
57 if shared:
58 parent = dict(parent)
59 for key, value in locals.iteritems():
60 if key[:2] == 'l_' and value is not missing:
61 parent[key[2:]] = value
62 return Context(environment, parent, template_name, blocks)
63
64
65class TemplateReference(object):
66 """The `self` in templates."""
67
68 def __init__(self, context):
69 self.__context = context
70
71 def __getitem__(self, name):
72 blocks = self.__context.blocks[name]
73 wrap = self.__context.environment.autoescape and \
74 Markup or (lambda x: x)
75 return BlockReference(name, self.__context, blocks, 0)
76
77 def __repr__(self):
78 return '<%s %r>' % (
79 self.__class__.__name__,
80 self.__context.name
81 )
82
83
Armin Ronacher19cf9c22008-05-01 12:49:53 +020084class Context(object):
Armin Ronacher7259c762008-04-30 13:03:59 +020085 """The template context holds the variables of a template. It stores the
86 values passed to the template and also the names the template exports.
87 Creating instances is neither supported nor useful as it's created
88 automatically at various stages of the template evaluation and should not
89 be created by hand.
Armin Ronacherc9705c22008-04-27 21:28:03 +020090
Armin Ronacher7259c762008-04-30 13:03:59 +020091 The context is immutable. Modifications on :attr:`parent` **must not**
92 happen and modifications on :attr:`vars` are allowed from generated
93 template code only. Template filters and global functions marked as
94 :func:`contextfunction`\s get the active context passed as first argument
95 and are allowed to access the context read-only.
96
97 The template context supports read only dict operations (`get`,
Armin Ronacherf35e2812008-05-06 16:04:10 +020098 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
99 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
100 method that doesn't fail with a `KeyError` but returns an
101 :class:`Undefined` object for missing variables.
Armin Ronacher9706fab2008-04-08 18:49:56 +0200102 """
Armin Ronacher771c7502008-05-18 23:14:14 +0200103 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
Armin Ronacherdcc217c2008-09-18 18:38:58 +0200104 'blocks', '__weakref__')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200105
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200106 def __init__(self, environment, parent, name, blocks):
107 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200108 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +0200109 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200110 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +0200111 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200112
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200113 # create the initial mapping of blocks. Whenever template inheritance
114 # takes place the runtime will update this mapping with the new blocks
115 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +0200116 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +0200117
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200118 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +0200119 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200120 try:
121 blocks = self.blocks[name]
Armin Ronacherc347ed02008-09-20 12:04:53 +0200122 index = blocks.index(current) + 1
123 blocks[index]
Armin Ronacherc9705c22008-04-27 21:28:03 +0200124 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +0200125 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200126 'called %r.' % name,
127 name='super')
Armin Ronacherc347ed02008-09-20 12:04:53 +0200128 return BlockReference(name, self, blocks, index)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129
Armin Ronacher53042292008-04-26 18:30:19 +0200130 def get(self, key, default=None):
Armin Ronacher7259c762008-04-30 13:03:59 +0200131 """Returns an item from the template context, if it doesn't exist
132 `default` is returned.
133 """
Armin Ronacherf35e2812008-05-06 16:04:10 +0200134 try:
135 return self[key]
136 except KeyError:
137 return default
138
139 def resolve(self, key):
140 """Looks up a variable like `__getitem__` or `get` but returns an
141 :class:`Undefined` object with the name of the name looked up.
142 """
Armin Ronacher53042292008-04-26 18:30:19 +0200143 if key in self.vars:
144 return self.vars[key]
145 if key in self.parent:
146 return self.parent[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200147 return self.environment.undefined(name=key)
Armin Ronacherb5124e62008-04-25 00:36:14 +0200148
Armin Ronacher9706fab2008-04-08 18:49:56 +0200149 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200150 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200151 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200152
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200153 def get_all(self):
Armin Ronacher7259c762008-04-30 13:03:59 +0200154 """Return a copy of the complete context as dict including the
Armin Ronacher5411ce72008-05-25 11:36:22 +0200155 exported variables.
Armin Ronacher7259c762008-04-30 13:03:59 +0200156 """
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200157 return dict(self.parent, **self.vars)
158
Armin Ronacherfd310492008-05-25 00:16:51 +0200159 def call(__self, __obj, *args, **kwargs):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200160 """Call the callable with the arguments and keyword arguments
161 provided but inject the active context or environment as first
162 argument if the callable is a :func:`contextfunction` or
163 :func:`environmentfunction`.
164 """
Armin Ronacher24b65582008-05-26 13:35:58 +0200165 if __debug__:
166 __traceback_hide__ = True
167 if isinstance(__obj, _context_function_types):
168 if getattr(__obj, 'contextfunction', 0):
169 args = (__self,) + args
170 elif getattr(__obj, 'environmentfunction', 0):
171 args = (__self.environment,) + args
Armin Ronacherfd310492008-05-25 00:16:51 +0200172 return __obj(*args, **kwargs)
173
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100174 def derived(self, locals=None):
175 """Internal helper function to create a derived context."""
176 return new_context(self.environment, self.name, self.blocks,
177 self.parent, True, None, locals)
178
Armin Ronacherf35e2812008-05-06 16:04:10 +0200179 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200180 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200181 proxy.__doc__ = getattr(dict, meth).__doc__
182 proxy.__name__ = meth
183 return proxy
184
185 keys = _all('keys')
186 values = _all('values')
187 items = _all('items')
188 iterkeys = _all('iterkeys')
189 itervalues = _all('itervalues')
190 iteritems = _all('iteritems')
191 del _all
192
Armin Ronacherb5124e62008-04-25 00:36:14 +0200193 def __contains__(self, name):
194 return name in self.vars or name in self.parent
195
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200196 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200197 """Lookup a variable or raise `KeyError` if the variable is
198 undefined.
199 """
200 item = self.resolve(key)
201 if isinstance(item, Undefined):
202 raise KeyError(key)
203 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200204
Armin Ronacherf059ec12008-04-11 22:21:00 +0200205 def __repr__(self):
206 return '<%s %s of %r>' % (
207 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200208 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200209 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200210 )
211
212
Armin Ronacherccae0552008-10-05 23:08:58 +0200213# register the context as mapping if possible
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200214try:
Armin Ronacherccae0552008-10-05 23:08:58 +0200215 from collections import Mapping
216 Mapping.register(Context)
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200217except ImportError:
218 pass
219
220
Armin Ronacherc347ed02008-09-20 12:04:53 +0200221class BlockReference(object):
222 """One block on a template reference."""
223
224 def __init__(self, name, context, stack, depth):
225 self.name = name
226 self._context = context
227 self._stack = stack
228 self._depth = depth
229
230 @property
231 def super(self):
232 """Super the block."""
233 if self._depth + 1 >= len(self._stack):
234 return self._context.environment. \
235 undefined('there is no parent block called %r.' %
236 self.name, name='super')
237 return BlockReference(self.name, self._context, self._stack,
238 self._depth + 1)
239
240 def __call__(self):
241 rv = concat(self._stack[self._depth](self._context))
242 if self._context.environment.autoescape:
243 rv = Markup(rv)
244 return rv
245
246
Armin Ronacher32a910f2008-04-26 23:21:03 +0200247class LoopContext(object):
248 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200249
Armin Ronacher547d0b62008-07-04 16:35:10 +0200250 def __init__(self, iterable, recurse=None):
251 self._iterator = iter(iterable)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200252 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200253 self.index0 = -1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200254
255 # try to get the length of the iterable early. This must be done
256 # here because there are some broken iterators around where there
257 # __len__ is the number of iterations left (i'm looking at your
258 # listreverseiterator!).
259 try:
260 self._length = len(iterable)
261 except (TypeError, AttributeError):
262 self._length = None
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200263
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200264 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200265 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200266 if not args:
267 raise TypeError('no items for cycling given')
268 return args[self.index0 % len(args)]
269
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200270 first = property(lambda x: x.index0 == 0)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200271 last = property(lambda x: x.index0 + 1 == x.length)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200272 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200273 revindex = property(lambda x: x.length - x.index0)
274 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200275
276 def __len__(self):
277 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200278
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200279 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200280 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200281
Armin Ronacher66a93442008-05-11 23:42:19 +0200282 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200283 if self._recurse is None:
284 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200285 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200286 return self._recurse(iterable, self._recurse)
287
Armin Ronacher66a93442008-05-11 23:42:19 +0200288 # a nifty trick to enhance the error message if someone tried to call
289 # the the loop without or with too many arguments.
290 __call__ = loop; del loop
291
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200292 @property
293 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200294 if self._length is None:
Armin Ronacher547d0b62008-07-04 16:35:10 +0200295 # if was not possible to get the length of the iterator when
296 # the loop context was created (ie: iterating over a generator)
297 # we have to convert the iterable into a sequence and use the
298 # length of that.
299 iterable = tuple(self._iterator)
300 self._iterator = iter(iterable)
301 self._length = len(iterable) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200302 return self._length
303
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200304 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200305 return '<%s %r/%r>' % (
306 self.__class__.__name__,
307 self.index,
308 self.length
309 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200310
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200311
Armin Ronachered1e0d42008-05-18 20:25:28 +0200312class LoopContextIterator(object):
313 """The iterator for a loop context."""
314 __slots__ = ('context',)
315
316 def __init__(self, context):
317 self.context = context
318
319 def __iter__(self):
320 return self
321
322 def next(self):
323 ctx = self.context
324 ctx.index0 += 1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200325 return ctx._iterator.next(), ctx
Armin Ronachered1e0d42008-05-18 20:25:28 +0200326
327
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200328class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200329 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200330
Armin Ronacher963f97d2008-04-25 11:44:59 +0200331 def __init__(self, environment, func, name, arguments, defaults,
332 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200333 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200334 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200335 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200336 self.name = name
337 self.arguments = arguments
338 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200339 self.catch_kwargs = catch_kwargs
340 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200341 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200342
343 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200344 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200345 for idx, name in enumerate(self.arguments):
346 try:
347 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200348 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200349 try:
350 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200351 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200352 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200353 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200354 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200355 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200356 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200357 arguments.append(value)
358
359 # it's important that the order of these arguments does not change
360 # if not also changed in the compiler's `function_scoping` method.
361 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200362 if self.caller:
363 caller = kwargs.pop('caller', None)
364 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200365 caller = self._environment.undefined('No caller defined',
366 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200367 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200368 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200369 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200370 elif kwargs:
371 raise TypeError('macro %r takes no keyword argument %r' %
372 (self.name, iter(kwargs).next()))
373 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200374 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200375 elif len(args) > self._argument_count:
376 raise TypeError('macro %r takes not more than %d argument(s)' %
377 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200378 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200379
380 def __repr__(self):
381 return '<%s %s>' % (
382 self.__class__.__name__,
383 self.name is None and 'anonymous' or repr(self.name)
384 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200385
386
387class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200388 """The default undefined type. This undefined type can be printed and
389 iterated over, but every other access will raise an :exc:`UndefinedError`:
390
391 >>> foo = Undefined(name='foo')
392 >>> str(foo)
393 ''
394 >>> not foo
395 True
396 >>> foo + 42
397 Traceback (most recent call last):
398 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200399 UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200400 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200401 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
402 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200403
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200404 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200405 self._undefined_hint = hint
406 self._undefined_obj = obj
407 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200408 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200409
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200410 def _fail_with_undefined_error(self, *args, **kwargs):
411 """Regular callback function for undefined objects that raises an
412 `UndefinedError` on call.
413 """
414 if self._undefined_hint is None:
415 if self._undefined_obj is None:
416 hint = '%r is undefined' % self._undefined_name
417 elif not isinstance(self._undefined_name, basestring):
418 hint = '%r object has no element %r' % (
419 self._undefined_obj.__class__.__name__,
420 self._undefined_name
421 )
422 else:
423 hint = '%r object has no attribute %r' % (
424 self._undefined_obj.__class__.__name__,
425 self._undefined_name
426 )
427 else:
428 hint = self._undefined_hint
429 raise self._undefined_exception(hint)
430
Armin Ronacherc63243e2008-04-14 22:53:58 +0200431 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
Armin Ronacher9efe0812008-11-02 12:22:00 +0100432 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
Armin Ronacherc63243e2008-04-14 22:53:58 +0200433 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200434 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
Armin Ronacher9efe0812008-11-02 12:22:00 +0100435 __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
436 _fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200437
438 def __str__(self):
Armin Ronacherccae0552008-10-05 23:08:58 +0200439 return unicode(self).encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200440
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200441 def __unicode__(self):
442 return u''
443
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200444 def __len__(self):
445 return 0
446
447 def __iter__(self):
448 if 0:
449 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200450
451 def __nonzero__(self):
452 return False
453
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200454 def __repr__(self):
455 return 'Undefined'
456
Armin Ronacherc63243e2008-04-14 22:53:58 +0200457
458class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200459 """An undefined that returns the debug info when printed.
460
461 >>> foo = DebugUndefined(name='foo')
462 >>> str(foo)
463 '{{ foo }}'
464 >>> not foo
465 True
466 >>> foo + 42
467 Traceback (most recent call last):
468 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200469 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200470 """
Armin Ronacher53042292008-04-26 18:30:19 +0200471 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200472
473 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200474 if self._undefined_hint is None:
475 if self._undefined_obj is None:
476 return u'{{ %s }}' % self._undefined_name
477 return '{{ no such element: %s[%r] }}' % (
478 self._undefined_obj.__class__.__name__,
479 self._undefined_name
480 )
481 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200482
483
484class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200485 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200486 tests and all kinds of comparisons. In other words: you can do nothing
487 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200488
489 >>> foo = StrictUndefined(name='foo')
490 >>> str(foo)
491 Traceback (most recent call last):
492 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200493 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200494 >>> not foo
495 Traceback (most recent call last):
496 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200497 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200498 >>> foo + 42
499 Traceback (most recent call last):
500 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200501 UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200502 """
Armin Ronacher53042292008-04-26 18:30:19 +0200503 __slots__ = ()
504 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200505 Undefined._fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200506
Armin Ronacher53042292008-04-26 18:30:19 +0200507
508# remove remaining slots attributes, after the metaclass did the magic they
509# are unneeded and irritating as they contain wrong data for the subclasses.
510del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__