blob: b28950050e5421ed646d6fada4ae0632bb3922ac [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 Ronacher4f7d2d52008-04-22 10:40:26 +020011from types import FunctionType
Armin Ronacherd1342312008-04-28 12:20:12 +020012from itertools import chain, imap
13from jinja2.utils import Markup, partial, soft_unicode, escape
14from jinja2.exceptions import UndefinedError, TemplateRuntimeError
Armin Ronachere791c2a2008-04-07 18:39:54 +020015
16
Armin Ronacher2feed1d2008-04-26 16:26:52 +020017# these variables are exported to the template runtime
Armin Ronacherc9705c22008-04-27 21:28:03 +020018__all__ = ['LoopContext', 'TemplateContext', 'TemplateReference', 'Macro',
Armin Ronacherd1342312008-04-28 12:20:12 +020019 'TemplateRuntimeError', 'Markup', 'missing', 'concat', 'escape',
20 'markup_join', 'unicode_join']
Armin Ronacher0611e492008-04-25 23:44:14 +020021
22
23# special singleton representing missing values for the runtime
Armin Ronacher32a910f2008-04-26 23:21:03 +020024missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
Armin Ronacher8edbe492008-04-10 20:43:43 +020025
26
Armin Ronacherde6bf712008-04-26 01:44:14 +020027# concatenate a list of strings and convert them to unicode.
28concat = u''.join
29
30
Armin Ronacherd1342312008-04-28 12:20:12 +020031def markup_join(*args):
32 """Concatenation that escapes if necessary and converts to unicode."""
33 buf = []
34 iterator = imap(soft_unicode, args)
35 for arg in iterator:
36 buf.append(arg)
37 if hasattr(arg, '__html__'):
38 return Markup(u'').join(chain(buf, iterator))
39 return concat(buf)
40
41
42def unicode_join(*args):
43 """Simple args to unicode conversion and concatenation."""
44 return concat(imap(unicode, args))
45
46
Armin Ronacher203bfcb2008-04-24 21:54:44 +020047class TemplateContext(object):
Armin Ronacher8edbe492008-04-10 20:43:43 +020048 """Holds the variables of the local template or of the global one. It's
Armin Ronacher9706fab2008-04-08 18:49:56 +020049 not save to use this class outside of the compiled code. For example
50 update and other methods will not work as they seem (they don't update
51 the exported variables for example).
Armin Ronacherc9705c22008-04-27 21:28:03 +020052
53 The context is immutable. Modifications on `parent` must not happen and
54 modifications on `vars` are allowed from generated template code. However
55 functions that are passed the template context may not modify the context
56 in any way.
Armin Ronacher9706fab2008-04-08 18:49:56 +020057 """
Armin Ronachere791c2a2008-04-07 18:39:54 +020058
Armin Ronacher203bfcb2008-04-24 21:54:44 +020059 def __init__(self, environment, parent, name, blocks):
60 self.parent = parent
Armin Ronacher2feed1d2008-04-26 16:26:52 +020061 self.vars = vars = {}
Armin Ronacherc63243e2008-04-14 22:53:58 +020062 self.environment = environment
Armin Ronacher203bfcb2008-04-24 21:54:44 +020063 self.exported_vars = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020064 self.name = name
Armin Ronacher203bfcb2008-04-24 21:54:44 +020065
66 # bind functions to the context of environment if required
Armin Ronacher2feed1d2008-04-26 16:26:52 +020067 for name, obj in parent.iteritems():
Armin Ronacher203bfcb2008-04-24 21:54:44 +020068 if type(obj) is FunctionType:
69 if getattr(obj, 'contextfunction', 0):
Armin Ronacher2feed1d2008-04-26 16:26:52 +020070 vars[name] = partial(obj, self)
Armin Ronacher203bfcb2008-04-24 21:54:44 +020071 elif getattr(obj, 'environmentfunction', 0):
Armin Ronacher2feed1d2008-04-26 16:26:52 +020072 vars[name] = partial(obj, environment)
Armin Ronacher203bfcb2008-04-24 21:54:44 +020073
74 # 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]
83 pos = blocks.index(current) - 1
84 if pos < 0:
85 raise IndexError()
86 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020087 return self.environment.undefined('there is no parent block '
Armin Ronacherc9705c22008-04-27 21:28:03 +020088 'called %r.' % name)
Armin Ronacherd1342312008-04-28 12:20:12 +020089 wrap = self.environment.autoescape and Markup or (lambda x: x)
90 render = lambda: wrap(concat(blocks[pos](self)))
Armin Ronacherc9705c22008-04-27 21:28:03 +020091 render.__name__ = render.name = name
92 return render
Armin Ronachere791c2a2008-04-07 18:39:54 +020093
Armin Ronacher53042292008-04-26 18:30:19 +020094 def get(self, key, default=None):
Armin Ronacherb5124e62008-04-25 00:36:14 +020095 """For dict compatibility"""
Armin Ronacher53042292008-04-26 18:30:19 +020096 if key in self.vars:
97 return self.vars[key]
98 if key in self.parent:
99 return self.parent[key]
100 return default
Armin Ronacherb5124e62008-04-25 00:36:14 +0200101
Armin Ronacher9706fab2008-04-08 18:49:56 +0200102 def get_exported(self):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200103 """Get a new dict with the exported variables."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200104 return dict((k, self.vars[k]) for k in self.exported_vars)
Armin Ronacher9706fab2008-04-08 18:49:56 +0200105
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200106 def get_root(self):
107 """Return a new dict with all the non local variables."""
108 return dict(self.parent)
109
110 def get_all(self):
111 """Return a copy of the complete context as dict."""
112 return dict(self.parent, **self.vars)
113
Armin Ronacherc9705c22008-04-27 21:28:03 +0200114 def clone(self):
115 """Return a copy of the context without the locals."""
116 return self.__class__(self.environment, self.parent,
117 self.name, self.blocks)
118
Armin Ronacherb5124e62008-04-25 00:36:14 +0200119 def __contains__(self, name):
120 return name in self.vars or name in self.parent
121
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200122 def __getitem__(self, key):
123 if key in self.vars:
124 return self.vars[key]
Armin Ronacher53042292008-04-26 18:30:19 +0200125 if key in self.parent:
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200126 return self.parent[key]
Armin Ronacher53042292008-04-26 18:30:19 +0200127 return self.environment.undefined(name=key)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200128
Armin Ronacherf059ec12008-04-11 22:21:00 +0200129 def __repr__(self):
130 return '<%s %s of %r>' % (
131 self.__class__.__name__,
Armin Ronacher963f97d2008-04-25 11:44:59 +0200132 repr(self.get_all()),
Armin Ronacher68f77672008-04-17 11:50:39 +0200133 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200134 )
135
136
Armin Ronacherc9705c22008-04-27 21:28:03 +0200137class TemplateReference(object):
138 """The `self` in templates."""
Armin Ronacher62f8a292008-04-13 23:18:05 +0200139
Armin Ronacherc9705c22008-04-27 21:28:03 +0200140 def __init__(self, context):
141 self.__context = context
Armin Ronacher62f8a292008-04-13 23:18:05 +0200142
Armin Ronacherc9705c22008-04-27 21:28:03 +0200143 def __getitem__(self, name):
144 func = self.__context.blocks[name][-1]
Armin Ronacherd1342312008-04-28 12:20:12 +0200145 wrap = self.__context.environment.autoescape and \
146 Markup or (lambda x: x)
147 render = lambda: wrap(concat(func(self.__context)))
Armin Ronacherc9705c22008-04-27 21:28:03 +0200148 render.__name__ = render.name = name
149 return render
Armin Ronacher62f8a292008-04-13 23:18:05 +0200150
151 def __repr__(self):
152 return '<%s %r>' % (
153 self.__class__.__name__,
Armin Ronacherc9705c22008-04-27 21:28:03 +0200154 self._context.name
Armin Ronacher62f8a292008-04-13 23:18:05 +0200155 )
156
157
Armin Ronacher32a910f2008-04-26 23:21:03 +0200158class LoopContext(object):
159 """A loop context for dynamic iteration."""
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200160
Armin Ronacher32a910f2008-04-26 23:21:03 +0200161 def __init__(self, iterable, enforce_length=False):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200162 self._iterable = iterable
Armin Ronacher32a910f2008-04-26 23:21:03 +0200163 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200164 self._length = None
Armin Ronacher32a910f2008-04-26 23:21:03 +0200165 self.index0 = -1
166 if enforce_length:
167 len(self)
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200168
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200169 def cycle(self, *args):
170 """A replacement for the old ``{% cycle %}`` tag."""
171 if not args:
172 raise TypeError('no items for cycling given')
173 return args[self.index0 % len(args)]
174
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200175 first = property(lambda x: x.index0 == 0)
176 last = property(lambda x: x.revindex0 == 0)
177 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200178 revindex = property(lambda x: x.length - x.index0)
179 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200180
181 def __len__(self):
182 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200183
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200184 def __iter__(self):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200185 return self
186
187 def next(self):
188 self.index0 += 1
189 return self._next(), self
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200190
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200191 @property
192 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200193 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200194 try:
195 length = len(self._iterable)
196 except TypeError:
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200197 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200198 self._next = iter(self._iterable).next
199 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200200 self._length = length
201 return self._length
202
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200203 def __repr__(self):
Armin Ronacherc9705c22008-04-27 21:28:03 +0200204 return '<%s %r/%r>' % (
205 self.__class__.__name__,
206 self.index,
207 self.length
208 )
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200209
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200210
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200211class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200212 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200213
Armin Ronacher963f97d2008-04-25 11:44:59 +0200214 def __init__(self, environment, func, name, arguments, defaults,
215 catch_kwargs, catch_varargs, caller):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200216 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200217 self._func = func
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200218 self.name = name
219 self.arguments = arguments
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200220 self.argument_count = len(arguments)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200221 self.defaults = defaults
Armin Ronacher963f97d2008-04-25 11:44:59 +0200222 self.catch_kwargs = catch_kwargs
223 self.catch_varargs = catch_varargs
Armin Ronacher71082072008-04-12 14:19:36 +0200224 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200225
226 def __call__(self, *args, **kwargs):
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200227 self.argument_count = len(self.arguments)
228 if not self.catch_varargs and len(args) > self.argument_count:
Armin Ronacher963f97d2008-04-25 11:44:59 +0200229 raise TypeError('macro %r takes not more than %d argument(s)' %
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200230 (self.name, len(self.arguments)))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200231 arguments = []
Armin Ronacher9706fab2008-04-08 18:49:56 +0200232 for idx, name in enumerate(self.arguments):
233 try:
234 value = args[idx]
235 except IndexError:
236 try:
237 value = kwargs.pop(name)
238 except KeyError:
239 try:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200240 value = self.defaults[idx - self.argument_count]
Armin Ronacher9706fab2008-04-08 18:49:56 +0200241 except IndexError:
Armin Ronacher9a822052008-04-17 18:44:07 +0200242 value = self._environment.undefined(
243 'parameter %r was not provided' % name)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200244 arguments.append(value)
245
246 # it's important that the order of these arguments does not change
247 # if not also changed in the compiler's `function_scoping` method.
248 # the order is caller, keyword arguments, positional arguments!
Armin Ronacher71082072008-04-12 14:19:36 +0200249 if self.caller:
250 caller = kwargs.pop('caller', None)
251 if caller is None:
Armin Ronacher9a822052008-04-17 18:44:07 +0200252 caller = self._environment.undefined('No caller defined')
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200253 arguments.append(caller)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200254 if self.catch_kwargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200255 arguments.append(kwargs)
Armin Ronacher963f97d2008-04-25 11:44:59 +0200256 elif kwargs:
257 raise TypeError('macro %r takes no keyword argument %r' %
258 (self.name, iter(kwargs).next()))
259 if self.catch_varargs:
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200260 arguments.append(args[self.argument_count:])
261 return self._func(*arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200262
263 def __repr__(self):
264 return '<%s %s>' % (
265 self.__class__.__name__,
266 self.name is None and 'anonymous' or repr(self.name)
267 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200268
269
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200270def fail_with_undefined_error(self, *args, **kwargs):
271 """Regular callback function for undefined objects that raises an
272 `UndefinedError` on call.
273 """
274 if self._undefined_hint is None:
275 if self._undefined_obj is None:
276 hint = '%r is undefined' % self._undefined_name
277 elif not isinstance(self._undefined_name, basestring):
278 hint = '%r object has no element %r' % (
279 self._undefined_obj.__class__.__name__,
280 self._undefined_name
281 )
282 else:
283 hint = '%r object has no attribute %r' % (
284 self._undefined_obj.__class__.__name__,
285 self._undefined_name
286 )
287 else:
288 hint = self._undefined_hint
289 raise UndefinedError(hint)
290
291
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200292class Undefined(object):
Armin Ronacherd1342312008-04-28 12:20:12 +0200293 """The default undefined type. This undefined type can be printed and
294 iterated over, but every other access will raise an :exc:`UndefinedError`:
295
296 >>> foo = Undefined(name='foo')
297 >>> str(foo)
298 ''
299 >>> not foo
300 True
301 >>> foo + 42
302 Traceback (most recent call last):
303 ...
304 jinja2.exceptions.UndefinedError: 'foo' is undefined
Armin Ronacherc63243e2008-04-14 22:53:58 +0200305 """
Armin Ronacher53042292008-04-26 18:30:19 +0200306 __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200307
Armin Ronacher9a822052008-04-17 18:44:07 +0200308 def __init__(self, hint=None, obj=None, name=None):
309 self._undefined_hint = hint
310 self._undefined_obj = obj
311 self._undefined_name = name
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200312
Armin Ronacherc63243e2008-04-14 22:53:58 +0200313 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
314 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
315 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher53042292008-04-26 18:30:19 +0200316 __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
317 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200318
319 def __str__(self):
320 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200321
322 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200323 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200324
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200325 def __unicode__(self):
326 return u''
327
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200328 def __len__(self):
329 return 0
330
331 def __iter__(self):
332 if 0:
333 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200334
335 def __nonzero__(self):
336 return False
337
338
339class DebugUndefined(Undefined):
Armin Ronacherd1342312008-04-28 12:20:12 +0200340 """An undefined that returns the debug info when printed.
341
342 >>> foo = DebugUndefined(name='foo')
343 >>> str(foo)
344 '{{ foo }}'
345 >>> not foo
346 True
347 >>> foo + 42
348 Traceback (most recent call last):
349 ...
350 jinja2.exceptions.UndefinedError: 'foo' is undefined
351 """
Armin Ronacher53042292008-04-26 18:30:19 +0200352 __slots__ = ()
Armin Ronacherc63243e2008-04-14 22:53:58 +0200353
354 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200355 if self._undefined_hint is None:
356 if self._undefined_obj is None:
357 return u'{{ %s }}' % self._undefined_name
358 return '{{ no such element: %s[%r] }}' % (
359 self._undefined_obj.__class__.__name__,
360 self._undefined_name
361 )
362 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200363
364
365class StrictUndefined(Undefined):
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200366 """An undefined that barks on print and iteration as well as boolean
Armin Ronacher53042292008-04-26 18:30:19 +0200367 tests and all kinds of comparisons. In other words: you can do nothing
368 with it except checking if it's defined using the `defined` test.
Armin Ronacherd1342312008-04-28 12:20:12 +0200369
370 >>> foo = StrictUndefined(name='foo')
371 >>> str(foo)
372 Traceback (most recent call last):
373 ...
374 jinja2.exceptions.UndefinedError: 'foo' is undefined
375 >>> not foo
376 Traceback (most recent call last):
377 ...
378 jinja2.exceptions.UndefinedError: 'foo' is undefined
379 >>> foo + 42
380 Traceback (most recent call last):
381 ...
382 jinja2.exceptions.UndefinedError: 'foo' is undefined
Priit Laes4149a0e2008-04-17 19:04:44 +0200383 """
Armin Ronacher53042292008-04-26 18:30:19 +0200384 __slots__ = ()
385 __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
386 fail_with_undefined_error
Armin Ronacherc63243e2008-04-14 22:53:58 +0200387
Armin Ronacher53042292008-04-26 18:30:19 +0200388
389# remove remaining slots attributes, after the metaclass did the magic they
390# are unneeded and irritating as they contain wrong data for the subclasses.
391del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__