blob: 87c2354606bfb316494a2ac53c86ea93ea126866 [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 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 Ronacher19cf9c22008-05-01 12:49:53 +020020__all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
21 '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 Ronacher19cf9c22008-05-01 12:49:53 +020045class Context(object):
Armin Ronacher7259c762008-04-30 13:03:59 +020046 """The template context holds the variables of a template. It stores the
47 values passed to the template and also the names the template exports.
48 Creating instances is neither supported nor useful as it's created
49 automatically at various stages of the template evaluation and should not
50 be created by hand.
Armin Ronacherc9705c22008-04-27 21:28:03 +020051
Armin Ronacher7259c762008-04-30 13:03:59 +020052 The context is immutable. Modifications on :attr:`parent` **must not**
53 happen and modifications on :attr:`vars` are allowed from generated
54 template code only. Template filters and global functions marked as
55 :func:`contextfunction`\s get the active context passed as first argument
56 and are allowed to access the context read-only.
57
58 The template context supports read only dict operations (`get`,
Armin Ronacherf35e2812008-05-06 16:04:10 +020059 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
60 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
61 method that doesn't fail with a `KeyError` but returns an
62 :class:`Undefined` object for missing variables.
Armin Ronacher9706fab2008-04-08 18:49:56 +020063 """
Armin Ronacher771c7502008-05-18 23:14:14 +020064 __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
Armin Ronacherdcc217c2008-09-18 18:38:58 +020065 'blocks', '__weakref__')
Armin Ronachere791c2a2008-04-07 18:39:54 +020066
Armin Ronacher203bfcb2008-04-24 21:54:44 +020067 def __init__(self, environment, parent, name, blocks):
68 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +020069 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +020070 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +020071 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020072 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +020073
Armin Ronacher203bfcb2008-04-24 21:54:44 +020074 # create the initial mapping of blocks. Whenever template inheritance
75 # takes place the runtime will update this mapping with the new blocks
76 # from the template.
Armin Ronacher75cfb862008-04-11 13:47:22 +020077 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020078
Armin Ronacher203bfcb2008-04-24 21:54:44 +020079 def super(self, name, current):
Armin Ronacher62f8a292008-04-13 23:18:05 +020080 """Render a parent block."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020081 try:
82 blocks = self.blocks[name]
Armin Ronacherc347ed02008-09-20 12:04:53 +020083 index = blocks.index(current) + 1
84 blocks[index]
Armin Ronacherc9705c22008-04-27 21:28:03 +020085 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020086 return self.environment.undefined('there is no parent block '
Armin Ronacher19cf9c22008-05-01 12:49:53 +020087 'called %r.' % name,
88 name='super')
Armin Ronacherc347ed02008-09-20 12:04:53 +020089 return BlockReference(name, self, blocks, index)
Armin Ronachere791c2a2008-04-07 18:39:54 +020090
Armin Ronacher53042292008-04-26 18:30:19 +020091 def get(self, key, default=None):
Armin Ronacher7259c762008-04-30 13:03:59 +020092 """Returns an item from the template context, if it doesn't exist
93 `default` is returned.
94 """
Armin Ronacherf35e2812008-05-06 16:04:10 +020095 try:
96 return self[key]
97 except KeyError:
98 return default
99
100 def resolve(self, key):
101 """Looks up a variable like `__getitem__` or `get` but returns an
102 :class:`Undefined` object with the name of the name looked up.
103 """
Armin Ronacher53042292008-04-26 18:30:19 +0200104 if key in self.vars:
105 return self.vars[key]
106 if key in self.parent:
107 return self.parent[key]
Armin Ronacherf35e2812008-05-06 16:04:10 +0200108 return self.environment.undefined(name=key)
Armin Ronacherb5124e62008-04-25 00:36:14 +0200109
Armin Ronacher9706fab2008-04-08 18:49:56 +0200110 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200111 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200112 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200113
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200114 def get_all(self):
Armin Ronacher7259c762008-04-30 13:03:59 +0200115 """Return a copy of the complete context as dict including the
Armin Ronacher5411ce72008-05-25 11:36:22 +0200116 exported variables.
Armin Ronacher7259c762008-04-30 13:03:59 +0200117 """
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200118 return dict(self.parent, **self.vars)
119
Armin Ronacherfd310492008-05-25 00:16:51 +0200120 def call(__self, __obj, *args, **kwargs):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200121 """Call the callable with the arguments and keyword arguments
122 provided but inject the active context or environment as first
123 argument if the callable is a :func:`contextfunction` or
124 :func:`environmentfunction`.
125 """
Armin Ronacher24b65582008-05-26 13:35:58 +0200126 if __debug__:
127 __traceback_hide__ = True
128 if isinstance(__obj, _context_function_types):
129 if getattr(__obj, 'contextfunction', 0):
130 args = (__self,) + args
131 elif getattr(__obj, 'environmentfunction', 0):
132 args = (__self.environment,) + args
Armin Ronacherfd310492008-05-25 00:16:51 +0200133 return __obj(*args, **kwargs)
134
Armin Ronacherf35e2812008-05-06 16:04:10 +0200135 def _all(meth):
Armin Ronachere9411b42008-05-15 16:22:07 +0200136 proxy = lambda self: getattr(self.get_all(), meth)()
Armin Ronacherf35e2812008-05-06 16:04:10 +0200137 proxy.__doc__ = getattr(dict, meth).__doc__
138 proxy.__name__ = meth
139 return proxy
140
141 keys = _all('keys')
142 values = _all('values')
143 items = _all('items')
144 iterkeys = _all('iterkeys')
145 itervalues = _all('itervalues')
146 iteritems = _all('iteritems')
147 del _all
148
Armin Ronacherb5124e62008-04-25 00:36:14 +0200149 def __contains__(self, name):
150 return name in self.vars or name in self.parent
151
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200152 def __getitem__(self, key):
Armin Ronacherbbbe0622008-05-19 00:23:37 +0200153 """Lookup a variable or raise `KeyError` if the variable is
154 undefined.
155 """
156 item = self.resolve(key)
157 if isinstance(item, Undefined):
158 raise KeyError(key)
159 return item
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200160
Armin Ronacherf059ec12008-04-11 22:21:00 +0200161 def __repr__(self):
162 return '<%s %s of %r>' % (
163 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200164 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200165 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200166 )
167
168
Armin Ronacherccae0552008-10-05 23:08:58 +0200169# register the context as mapping if possible
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200170try:
Armin Ronacherccae0552008-10-05 23:08:58 +0200171 from collections import Mapping
172 Mapping.register(Context)
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200173except ImportError:
174 pass
175
176
Armin Ronacherc9705c22008-04-27 21:28:03 +0200177class TemplateReference(object):
178 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200179
Armin Ronacherc9705c22008-04-27 21:28:03 +0200180 def __init__(self, context):
181 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200182
Armin Ronacherc9705c22008-04-27 21:28:03 +0200183 def __getitem__(self, name):
Armin Ronacherc347ed02008-09-20 12:04:53 +0200184 blocks = self.__context.blocks[name]
Armin Ronacherd1342312008-04-28 12:20:12 +0200185 wrap = self.__context.environment.autoescape and \
186 Markup or (lambda x: x)
Armin Ronacherc347ed02008-09-20 12:04:53 +0200187 return BlockReference(name, self.__context, blocks, 0)
Armin Ronacher62f8a292008-04-13 23:18:05 +0200188
189 def __repr__(self):
190 return '<%s %r>' % (
191 self.__class__.__name__,
Armin Ronacherc347ed02008-09-20 12:04:53 +0200192 self.__context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200193 )
194
195
Armin Ronacherc347ed02008-09-20 12:04:53 +0200196class BlockReference(object):
197 """One block on a template reference."""
198
199 def __init__(self, name, context, stack, depth):
200 self.name = name
201 self._context = context
202 self._stack = stack
203 self._depth = depth
204
205 @property
206 def super(self):
207 """Super the block."""
208 if self._depth + 1 >= len(self._stack):
209 return self._context.environment. \
210 undefined('there is no parent block called %r.' %
211 self.name, name='super')
212 return BlockReference(self.name, self._context, self._stack,
213 self._depth + 1)
214
215 def __call__(self):
216 rv = concat(self._stack[self._depth](self._context))
217 if self._context.environment.autoescape:
218 rv = Markup(rv)
219 return rv
220
221
Armin Ronacher32a910f2008-04-26 23:21:03 +0200222class LoopContext(object):
223 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200224
Armin Ronacher547d0b62008-07-04 16:35:10 +0200225 def __init__(self, iterable, recurse=None):
226 self._iterator = iter(iterable)
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200227 self._recurse = recurse
Armin Ronacher32a910f2008-04-26 23:21:03 +0200228 self.index0 = -1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200229
230 # try to get the length of the iterable early. This must be done
231 # here because there are some broken iterators around where there
232 # __len__ is the number of iterations left (i'm looking at your
233 # listreverseiterator!).
234 try:
235 self._length = len(iterable)
236 except (TypeError, AttributeError):
237 self._length = None
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200238
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200239 def cycle(self, *args):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200240 """Cycles among the arguments with the current loop index."""
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200241 if not args:
242 raise TypeError('no items for cycling given')
243 return args[self.index0 % len(args)]
244
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200245 first = property(lambda x: x.index0 == 0)
Armin Ronacher547d0b62008-07-04 16:35:10 +0200246 last = property(lambda x: x.index0 + 1 == x.length)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200247 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200248 revindex = property(lambda x: x.length - x.index0)
249 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200250
251 def __len__(self):
252 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200253
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200254 def __iter__(self):
Armin Ronachered1e0d42008-05-18 20:25:28 +0200255 return LoopContextIterator(self)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200256
Armin Ronacher66a93442008-05-11 23:42:19 +0200257 def loop(self, iterable):
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200258 if self._recurse is None:
259 raise TypeError('Tried to call non recursive loop. Maybe you '
Armin Ronacher66a93442008-05-11 23:42:19 +0200260 "forgot the 'recursive' modifier.")
Armin Ronacher1e1e8902008-05-11 23:21:16 +0200261 return self._recurse(iterable, self._recurse)
262
Armin Ronacher66a93442008-05-11 23:42:19 +0200263 # a nifty trick to enhance the error message if someone tried to call
264 # the the loop without or with too many arguments.
265 __call__ = loop; del loop
266
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200267 @property
268 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200269 if self._length is None:
Armin Ronacher547d0b62008-07-04 16:35:10 +0200270 # if was not possible to get the length of the iterator when
271 # the loop context was created (ie: iterating over a generator)
272 # we have to convert the iterable into a sequence and use the
273 # length of that.
274 iterable = tuple(self._iterator)
275 self._iterator = iter(iterable)
276 self._length = len(iterable) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200277 return self._length
278
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200279 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200280 return '<%s %r/%r>' % (
281 self.__class__.__name__,
282 self.index,
283 self.length
284 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200285
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200286
Armin Ronachered1e0d42008-05-18 20:25:28 +0200287class LoopContextIterator(object):
288 """The iterator for a loop context."""
289 __slots__ = ('context',)
290
291 def __init__(self, context):
292 self.context = context
293
294 def __iter__(self):
295 return self
296
297 def next(self):
298 ctx = self.context
299 ctx.index0 += 1
Armin Ronacher547d0b62008-07-04 16:35:10 +0200300 return ctx._iterator.next(), ctx
Armin Ronachered1e0d42008-05-18 20:25:28 +0200301
302
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200303class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200304 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200305
Armin Ronacher963f97d2008-04-25 11:44:59 +0200306 def __init__(self, environment, func, name, arguments, defaults,
307 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200308 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200309 self._func = func
Armin Ronacherd84ec462008-04-29 13:43:16 +0200310 self._argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200311 self.name = name
312 self.arguments = arguments
313 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200314 self.catch_kwargs = catch_kwargs
315 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200316 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200317
318 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200319 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200320 for idx, name in enumerate(self.arguments):
321 try:
322 value = args[idx]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200323 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200324 try:
325 value = kwargs.pop(name)
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200326 except:
Armin Ronacher9706fab2008-04-08 18:49:56 +0200327 try:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200328 value = self.defaults[idx - self._argument_count]
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200329 except:
Armin Ronacher9a822052008-04-17 18:44:07 +0200330 value = self._environment.undefined(
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200331 'parameter %r was not provided' % name, name=name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200332 arguments.append(value)
333
334 # it's important that the order of these arguments does not change
335 # if not also changed in the compiler's `function_scoping` method.
336 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200337 if self.caller:
338 caller = kwargs.pop('caller', None)
339 if caller is None:
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200340 caller = self._environment.undefined('No caller defined',
341 name='caller')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200342 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200343 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200344 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200345 elif kwargs:
346 raise TypeError('macro %r takes no keyword argument %r' %
347 (self.name, iter(kwargs).next()))
348 if self.catch_varargs:
Armin Ronacherd84ec462008-04-29 13:43:16 +0200349 arguments.append(args[self._argument_count:])
Armin Ronacher19cf9c22008-05-01 12:49:53 +0200350 elif len(args) > self._argument_count:
351 raise TypeError('macro %r takes not more than %d argument(s)' %
352 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200353 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200354
355 def __repr__(self):
356 return '<%s %s>' % (
357 self.__class__.__name__,
358 self.name is None and 'anonymous' or repr(self.name)
359 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200360
361
362class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200363 """The default undefined type. This undefined type can be printed and
364 iterated over, but every other access will raise an :exc:`UndefinedError`:
365
366 >>> foo = Undefined(name='foo')
367 >>> str(foo)
368 ''
369 >>> not foo
370 True
371 >>> foo + 42
372 Traceback (most recent call last):
373 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200374 UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200375 """
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200376 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
377 '_undefined_exception')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200378
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200379 def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
Armin Ronacher9a822052008-04-17 18:44:07 +0200380 self._undefined_hint = hint
381 self._undefined_obj = obj
382 self._undefined_name = name
Armin Ronacher5cdc1ac2008-05-07 12:17:18 +0200383 self._undefined_exception = exc
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200384
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200385 def _fail_with_undefined_error(self, *args, **kwargs):
386 """Regular callback function for undefined objects that raises an
387 `UndefinedError` on call.
388 """
389 if self._undefined_hint is None:
390 if self._undefined_obj is None:
391 hint = '%r is undefined' % self._undefined_name
392 elif not isinstance(self._undefined_name, basestring):
393 hint = '%r object has no element %r' % (
394 self._undefined_obj.__class__.__name__,
395 self._undefined_name
396 )
397 else:
398 hint = '%r object has no attribute %r' % (
399 self._undefined_obj.__class__.__name__,
400 self._undefined_name
401 )
402 else:
403 hint = self._undefined_hint
404 raise self._undefined_exception(hint)
405
Armin Ronacherc63243e2008-04-14 22:53:58 +0200406 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
Armin Ronacher9efe0812008-11-02 12:22:00 +0100407 __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
Armin Ronacherc63243e2008-04-14 22:53:58 +0200408 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200409 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
Armin Ronacher9efe0812008-11-02 12:22:00 +0100410 __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
411 _fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200412
413 def __str__(self):
Armin Ronacherccae0552008-10-05 23:08:58 +0200414 return unicode(self).encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200415
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200416 def __unicode__(self):
417 return u''
418
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200419 def __len__(self):
420 return 0
421
422 def __iter__(self):
423 if 0:
424 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200425
426 def __nonzero__(self):
427 return False
428
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200429 def __repr__(self):
430 return 'Undefined'
431
Armin Ronacherc63243e2008-04-14 22:53:58 +0200432
433class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200434 """An undefined that returns the debug info when printed.
435
436 >>> foo = DebugUndefined(name='foo')
437 >>> str(foo)
438 '{{ foo }}'
439 >>> not foo
440 True
441 >>> foo + 42
442 Traceback (most recent call last):
443 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200444 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200445 """
Armin Ronacher53042292008-04-26 18:30:19 +0200446 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200447
448 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200449 if self._undefined_hint is None:
450 if self._undefined_obj is None:
451 return u'{{ %s }}' % self._undefined_name
452 return '{{ no such element: %s[%r] }}' % (
453 self._undefined_obj.__class__.__name__,
454 self._undefined_name
455 )
456 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200457
458
459class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200460 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200461 tests and all kinds of comparisons. In other words: you can do nothing
462 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200463
464 >>> foo = StrictUndefined(name='foo')
465 >>> str(foo)
466 Traceback (most recent call last):
467 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200468 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200469 >>> not foo
470 Traceback (most recent call last):
471 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200472 UndefinedError: 'foo' is undefined
Armin Ronacherd1342312008-04-28 12:20:12 +0200473 >>> foo + 42
474 Traceback (most recent call last):
475 ...
Armin Ronacherabd36572008-06-27 08:45:19 +0200476 UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200477 """
Armin Ronacher53042292008-04-26 18:30:19 +0200478 __slots__ = ()
479 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200480 Undefined._fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200481
Armin Ronacher53042292008-04-26 18:30:19 +0200482
483# remove remaining slots attributes, after the metaclass did the magic they
484# are unneeded and irritating as they contain wrong data for the subclasses.
485del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__