blob: bd7e3057fad66c07f001707251ba7ece2960a024 [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.
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 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 Ronacher9a0078d2008-08-13 18:24:17 +020023
Armin Ronacherce677102008-08-17 19:43:22 +020024#: the types we support for context functions
25_context_function_types = (FunctionType, MethodType)
Armin Ronacher24b65582008-05-26 13:35:58 +020026
Armin Ronacher0611e492008-04-25 23:44:14 +020027
Armin Ronacherdc02b642008-05-15 22:47:27 +020028def markup_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020029 """Concatenation that escapes if necessary and converts to unicode."""
30 buf = []
Armin Ronacherdc02b642008-05-15 22:47:27 +020031 iterator = imap(soft_unicode, seq)
Armin Ronacherd1342312008-04-28 12:20:12 +020032 for arg in iterator:
33 buf.append(arg)
34 if hasattr(arg, '__html__'):
35 return Markup(u'').join(chain(buf, iterator))
36 return concat(buf)
37
38
Armin Ronacherdc02b642008-05-15 22:47:27 +020039def unicode_join(seq):
Armin Ronacherd1342312008-04-28 12:20:12 +020040 """Simple args to unicode conversion and concatenation."""
Armin Ronacherdc02b642008-05-15 22:47:27 +020041 return concat(imap(unicode, seq))
Armin Ronacherd1342312008-04-28 12:20:12 +020042
43
Armin Ronacher19cf9c22008-05-01 12:49:53 +020044class Context(object):
Armin Ronacher7259c762008-04-30 13:03:59 +020045 """The template context holds the variables of a template. It stores the
46 values passed to the template and also the names the template exports.
47 Creating instances is neither supported nor useful as it's created
48 automatically at various stages of the template evaluation and should not
49 be created by hand.
Armin Ronacherc9705c22008-04-27 21:28:03 +020050
Armin Ronacher7259c762008-04-30 13:03:59 +020051 The context is immutable. Modifications on :attr:`parent` **must not**
52 happen and modifications on :attr:`vars` are allowed from generated
53 template code only. Template filters and global functions marked as
54 :func:`contextfunction`\s get the active context passed as first argument
55 and are allowed to access the context read-only.
56
57 The template context supports read only dict operations (`get`,
Armin Ronacherf35e2812008-05-06 16:04:10 +020058 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
59 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
60 method that doesn't fail with a `KeyError` but returns an
61 :class:`Undefined` object for missing variables.
Armin Ronacher9706fab2008-04-08 18:49:56 +020062 """
Armin Ronacher771c7502008-05-18 23:14:14 +020063 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
Armin Ronacherdcc217c2008-09-18 18:38:58 +020064 'blocks', '__weakref__')
Armin Ronachere791c2a2008-04-07 18:39:54 +020065
Armin Ronacher203bfcb2008-04-24 21:54:44 +020066 def __init__(self, environment, parent, name, blocks):
67 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +020068 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +020069 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +020070 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020071 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +020072
Armin Ronacher203bfcb2008-04-24 21:54:44 +020073 # create the initial mapping of blocks. Whenever template inheritance
74 # takes place the runtime will update this mapping with the new blocks
75 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +020076 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020077
Armin Ronacher203bfcb2008-04-24 21:54:44 +020078 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +020079 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020080 try:
81 blocks = self.blocks[name]
Armin Ronacherc347ed02008-09-20 12:04:53 +020082 index = blocks.index(current) + 1
83 blocks[index]
Armin Ronacherc9705c22008-04-27 21:28:03 +020084 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020085 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +020086 'called %r.' % name,
87 name='super')
Armin Ronacherc347ed02008-09-20 12:04:53 +020088 return BlockReference(name, self, blocks, index)
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):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200120 """Call the callable with the arguments and keyword arguments
121 provided but inject the active context or environment as first
122 argument if the callable is a :func:`contextfunction` or
123 :func:`environmentfunction`.
124 """
Armin Ronacher24b65582008-05-26 13:35:58 +0200125 if __debug__:
126 __traceback_hide__ = True
127 if isinstance(__obj, _context_function_types):
128 if getattr(__obj, 'contextfunction', 0):
129 args = (__self,) + args
130 elif getattr(__obj, 'environmentfunction', 0):
131 args = (__self.environment,) + args
Armin Ronacherfd310492008-05-25 00:16:51 +0200132 return __obj(*args, **kwargs)
133
Armin Ronacherf35e2812008-05-06 16:04:10 +0200134 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200135 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200136 proxy.__doc__ = getattr(dict, meth).__doc__
137 proxy.__name__ = meth
138 return proxy
139
140 keys = _all('keys')
141 values = _all('values')
142 items = _all('items')
143 iterkeys = _all('iterkeys')
144 itervalues = _all('itervalues')
145 iteritems = _all('iteritems')
146 del _all
147
Armin Ronacherb5124e62008-04-25 00:36:14 +0200148 def __contains__(self, name):
149 return name in self.vars or name in self.parent
150
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200151 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200152 """Lookup a variable or raise `KeyError` if the variable is
153 undefined.
154 """
155 item = self.resolve(key)
156 if isinstance(item, Undefined):
157 raise KeyError(key)
158 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200159
Armin Ronacherf059ec12008-04-11 22:21:00 +0200160 def __repr__(self):
161 return '<%s %s of %r>' % (
162 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200163 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200164 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200165 )
166
167
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200168# register the context as mutable mapping if possible
169try:
170 from collections import MutableMapping
171 MutableMapping.register(Context)
172except ImportError:
173 pass
174
175
Armin Ronacherc9705c22008-04-27 21:28:03 +0200176class TemplateReference(object):
177 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200178
Armin Ronacherc9705c22008-04-27 21:28:03 +0200179 def __init__(self, context):
180 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200181
Armin Ronacherc9705c22008-04-27 21:28:03 +0200182 def __getitem__(self, name):
Armin Ronacherc347ed02008-09-20 12:04:53 +0200183 blocks = self.__context.blocks[name]
Armin Ronacherd1342312008-04-28 12:20:12 +0200184 wrap = self.__context.environment.autoescape and \
185 Markup or (lambda x: x)
Armin Ronacherc347ed02008-09-20 12:04:53 +0200186 return BlockReference(name, self.__context, blocks, 0)
Armin Ronacher62f8a292008-04-13 23:18:05 +0200187
188 def __repr__(self):
189 return '<%s %r>' % (
190 self.__class__.__name__,
Armin Ronacherc347ed02008-09-20 12:04:53 +0200191 self.__context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200192 )
193
194
Armin Ronacherc347ed02008-09-20 12:04:53 +0200195class BlockReference(object):
196 """One block on a template reference."""
197
198 def __init__(self, name, context, stack, depth):
199 self.name = name
200 self._context = context
201 self._stack = stack
202 self._depth = depth
203
204 @property
205 def super(self):
206 """Super the block."""
207 if self._depth + 1 >= len(self._stack):
208 return self._context.environment. \
209 undefined('there is no parent block called %r.' %
210 self.name, name='super')
211 return BlockReference(self.name, self._context, self._stack,
212 self._depth + 1)
213
214 def __call__(self):
215 rv = concat(self._stack[self._depth](self._context))
216 if self._context.environment.autoescape:
217 rv = Markup(rv)
218 return rv
219
220
Armin Ronacher32a910f2008-04-26 23:21:03 +0200221class LoopContext(object):
222 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200223
Armin Ronacher547d0b62008-07-04 16:35:10 +0200224 def __init__(self, iterable, recurse=None):
225 self._iterator = iter(iterable)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200226 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200227 self.index0 = -1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200228
229 # try to get the length of the iterable early. This must be done
230 # here because there are some broken iterators around where there
231 # __len__ is the number of iterations left (i'm looking at your
232 # listreverseiterator!).
233 try:
234 self._length = len(iterable)
235 except (TypeError, AttributeError):
236 self._length = None
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200237
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200238 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200239 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200240 if not args:
241 raise TypeError('no items for cycling given')
242 return args[self.index0 % len(args)]
243
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200244 first = property(lambda x: x.index0 == 0)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200245 last = property(lambda x: x.index0 + 1 == x.length)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200246 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200247 revindex = property(lambda x: x.length - x.index0)
248 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200249
250 def __len__(self):
251 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200252
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200253 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200254 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200255
Armin Ronacher66a93442008-05-11 23:42:19 +0200256 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200257 if self._recurse is None:
258 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200259 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200260 return self._recurse(iterable, self._recurse)
261
Armin Ronacher66a93442008-05-11 23:42:19 +0200262 # a nifty trick to enhance the error message if someone tried to call
263 # the the loop without or with too many arguments.
264 __call__ = loop; del loop
265
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200266 @property
267 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200268 if self._length is None:
Armin Ronacher547d0b62008-07-04 16:35:10 +0200269 # if was not possible to get the length of the iterator when
270 # the loop context was created (ie: iterating over a generator)
271 # we have to convert the iterable into a sequence and use the
272 # length of that.
273 iterable = tuple(self._iterator)
274 self._iterator = iter(iterable)
275 self._length = len(iterable) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200276 return self._length
277
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200278 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200279 return '<%s %r/%r>' % (
280 self.__class__.__name__,
281 self.index,
282 self.length
283 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200284
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200285
Armin Ronachered1e0d42008-05-18 20:25:28 +0200286class LoopContextIterator(object):
287 """The iterator for a loop context."""
288 __slots__ = ('context',)
289
290 def __init__(self, context):
291 self.context = context
292
293 def __iter__(self):
294 return self
295
296 def next(self):
297 ctx = self.context
298 ctx.index0 += 1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200299 return ctx._iterator.next(), ctx
Armin Ronachered1e0d42008-05-18 20:25:28 +0200300
301
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200302class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200303 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200304
Armin Ronacher963f97d2008-04-25 11:44:59 +0200305 def __init__(self, environment, func, name, arguments, defaults,
306 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200307 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200308 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200309 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200310 self.name = name
311 self.arguments = arguments
312 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200313 self.catch_kwargs = catch_kwargs
314 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200315 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200316
317 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200318 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200319 for idx, name in enumerate(self.arguments):
320 try:
321 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200322 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200323 try:
324 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200325 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200326 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200327 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200328 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200329 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200330 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200331 arguments.append(value)
332
333 # it's important that the order of these arguments does not change
334 # if not also changed in the compiler's `function_scoping` method.
335 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200336 if self.caller:
337 caller = kwargs.pop('caller', None)
338 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200339 caller = self._environment.undefined('No caller defined',
340 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200341 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200342 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200343 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200344 elif kwargs:
345 raise TypeError('macro %r takes no keyword argument %r' %
346 (self.name, iter(kwargs).next()))
347 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200348 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200349 elif len(args) > self._argument_count:
350 raise TypeError('macro %r takes not more than %d argument(s)' %
351 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200352 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200353
354 def __repr__(self):
355 return '<%s %s>' % (
356 self.__class__.__name__,
357 self.name is None and 'anonymous' or repr(self.name)
358 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200359
360
361class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200362 """The default undefined type. This undefined type can be printed and
363 iterated over, but every other access will raise an :exc:`UndefinedError`:
364
365 >>> foo = Undefined(name='foo')
366 >>> str(foo)
367 ''
368 >>> not foo
369 True
370 >>> foo + 42
371 Traceback (most recent call last):
372 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200373 UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200374 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200375 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
376 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200377
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200378 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200379 self._undefined_hint = hint
380 self._undefined_obj = obj
381 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200382 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200383
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200384 def _fail_with_undefined_error(self, *args, **kwargs):
385 """Regular callback function for undefined objects that raises an
386 `UndefinedError` on call.
387 """
388 if self._undefined_hint is None:
389 if self._undefined_obj is None:
390 hint = '%r is undefined' % self._undefined_name
391 elif not isinstance(self._undefined_name, basestring):
392 hint = '%r object has no element %r' % (
393 self._undefined_obj.__class__.__name__,
394 self._undefined_name
395 )
396 else:
397 hint = '%r object has no attribute %r' % (
398 self._undefined_obj.__class__.__name__,
399 self._undefined_name
400 )
401 else:
402 hint = self._undefined_hint
403 raise self._undefined_exception(hint)
404
Armin Ronacherc63243e2008-04-14 22:53:58 +0200405 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
406 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
407 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200408 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200409 __int__ = __float__ = __complex__ = _fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200410
411 def __str__(self):
412 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200413
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200414 def __unicode__(self):
415 return u''
416
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200417 def __len__(self):
418 return 0
419
420 def __iter__(self):
421 if 0:
422 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200423
424 def __nonzero__(self):
425 return False
426
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200427 def __repr__(self):
428 return 'Undefined'
429
Armin Ronacherc63243e2008-04-14 22:53:58 +0200430
431class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200432 """An undefined that returns the debug info when printed.
433
434 >>> foo = DebugUndefined(name='foo')
435 >>> str(foo)
436 '{{ foo }}'
437 >>> not foo
438 True
439 >>> foo + 42
440 Traceback (most recent call last):
441 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200442 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200443 """
Armin Ronacher53042292008-04-26 18:30:19 +0200444 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200445
446 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200447 if self._undefined_hint is None:
448 if self._undefined_obj is None:
449 return u'{{ %s }}' % self._undefined_name
450 return '{{ no such element: %s[%r] }}' % (
451 self._undefined_obj.__class__.__name__,
452 self._undefined_name
453 )
454 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200455
456
457class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200458 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200459 tests and all kinds of comparisons. In other words: you can do nothing
460 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200461
462 >>> foo = StrictUndefined(name='foo')
463 >>> str(foo)
464 Traceback (most recent call last):
465 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200466 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200467 >>> not foo
468 Traceback (most recent call last):
469 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200470 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200471 >>> foo + 42
472 Traceback (most recent call last):
473 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200474 UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200475 """
Armin Ronacher53042292008-04-26 18:30:19 +0200476 __slots__ = ()
477 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200478 Undefined._fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200479
Armin Ronacher53042292008-04-26 18:30:19 +0200480
481# remove remaining slots attributes, after the metaclass did the magic they
482# are unneeded and irritating as they contain wrong data for the subclasses.
483del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__