blob: e1bf486d097b110f42106067e4ab1e048ada1e37 [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"""
11try:
12 from collections import defaultdict
13except ImportError:
14 defaultdict = None
Armin Ronacher18c6ca02008-04-17 10:03:29 +020015from jinja2.utils import Markup
Armin Ronacher9a822052008-04-17 18:44:07 +020016from jinja2.exceptions import UndefinedError
Armin Ronachere791c2a2008-04-07 18:39:54 +020017
18
Armin Ronacherc63243e2008-04-14 22:53:58 +020019__all__ = ['LoopContext', 'StaticLoopContext', 'TemplateContext',
Armin Ronacher5236d8c2008-04-17 11:23:16 +020020 'Macro', 'IncludedTemplate', 'Markup']
Armin Ronacher8edbe492008-04-10 20:43:43 +020021
22
Armin Ronachere791c2a2008-04-07 18:39:54 +020023class TemplateContext(dict):
Armin Ronacher8edbe492008-04-10 20:43:43 +020024 """Holds the variables of the local template or of the global one. It's
Armin Ronacher9706fab2008-04-08 18:49:56 +020025 not save to use this class outside of the compiled code. For example
26 update and other methods will not work as they seem (they don't update
27 the exported variables for example).
28 """
Armin Ronachere791c2a2008-04-07 18:39:54 +020029
Armin Ronacher68f77672008-04-17 11:50:39 +020030 def __init__(self, environment, globals, name, blocks, standalone):
Armin Ronacher9706fab2008-04-08 18:49:56 +020031 dict.__init__(self, globals)
Armin Ronacherc63243e2008-04-14 22:53:58 +020032 self.environment = environment
Armin Ronacher9706fab2008-04-08 18:49:56 +020033 self.exported = set()
Armin Ronacher68f77672008-04-17 11:50:39 +020034 self.name = name
Armin Ronacher75cfb862008-04-11 13:47:22 +020035 self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
Armin Ronacherf059ec12008-04-11 22:21:00 +020036
37 # if the template is in standalone mode we don't copy the blocks over.
38 # this is used for includes for example but otherwise, if the globals
39 # are a template context, this template is participating in a template
40 # inheritance chain and we have to copy the blocks over.
41 if not standalone and isinstance(globals, TemplateContext):
Armin Ronacher62f8a292008-04-13 23:18:05 +020042 for name, parent_blocks in globals.blocks.iteritems():
43 self.blocks.setdefault(name, []).extend(parent_blocks)
44
45 def super(self, block):
46 """Render a parent block."""
47 try:
48 func = self.blocks[block][-2]
49 except LookupError:
Armin Ronacher9a822052008-04-17 18:44:07 +020050 return self.environment.undefined('there is no parent block '
51 'called %r.' % block)
Armin Ronacher62f8a292008-04-13 23:18:05 +020052 return SuperBlock(block, self, func)
Armin Ronachere791c2a2008-04-07 18:39:54 +020053
Armin Ronacher9706fab2008-04-08 18:49:56 +020054 def __setitem__(self, key, value):
55 """If we set items to the dict we track the variables set so
56 that includes can access the exported variables."""
57 dict.__setitem__(self, key, value)
58 self.exported.add(key)
59
Armin Ronacher9706fab2008-04-08 18:49:56 +020060 def get_exported(self):
61 """Get a dict of all exported variables."""
62 return dict((k, self[k]) for k in self.exported)
63
Armin Ronachere791c2a2008-04-07 18:39:54 +020064 # if there is a default dict, dict has a __missing__ method we can use.
65 if defaultdict is None:
66 def __getitem__(self, name):
67 if name in self:
68 return self[name]
Armin Ronacher9a822052008-04-17 18:44:07 +020069 return self.environment.undefined(name=name)
Armin Ronachere791c2a2008-04-07 18:39:54 +020070 else:
Armin Ronacher9a822052008-04-17 18:44:07 +020071 def __missing__(self, name):
72 return self.environment.undefined(name=name)
Armin Ronacher4f62a9f2008-04-08 18:09:13 +020073
Armin Ronacherf059ec12008-04-11 22:21:00 +020074 def __repr__(self):
75 return '<%s %s of %r>' % (
76 self.__class__.__name__,
77 dict.__repr__(self),
Armin Ronacher68f77672008-04-17 11:50:39 +020078 self.name
Armin Ronacherf059ec12008-04-11 22:21:00 +020079 )
80
81
Armin Ronacher62f8a292008-04-13 23:18:05 +020082class SuperBlock(object):
83 """When called this renders a parent block."""
84
85 def __init__(self, name, context, render_func):
86 self.name = name
87 self._context = context
88 self._render_func = render_func
89
90 def __call__(self):
Armin Ronacher5236d8c2008-04-17 11:23:16 +020091 return Markup(u''.join(self._render_func(self._context)))
Armin Ronacher62f8a292008-04-13 23:18:05 +020092
93 def __repr__(self):
94 return '<%s %r>' % (
95 self.__class__.__name__,
96 self.name
97 )
98
99
Armin Ronacherf059ec12008-04-11 22:21:00 +0200100class IncludedTemplate(object):
101 """Represents an included template."""
102
103 def __init__(self, environment, context, template):
Armin Ronacher7c0116f2008-04-12 00:06:19 +0200104 template = environment.get_template(template)
105 gen = template.root_render_func(context, standalone=True)
106 context = gen.next()
Armin Ronacher68f77672008-04-17 11:50:39 +0200107 self._name = template.name
Armin Ronacherf059ec12008-04-11 22:21:00 +0200108 self._rendered_body = u''.join(gen)
Armin Ronacher7c0116f2008-04-12 00:06:19 +0200109 self._context = context.get_exported()
Armin Ronacherf059ec12008-04-11 22:21:00 +0200110
111 def __getitem__(self, name):
112 return self._context[name]
113
114 def __unicode__(self):
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200115 return self._rendered_body
116
117 def __html__(self):
118 return self._rendered_body
Armin Ronacherf059ec12008-04-11 22:21:00 +0200119
Armin Ronacher7c0116f2008-04-12 00:06:19 +0200120 def __repr__(self):
121 return '<%s %r>' % (
122 self.__class__.__name__,
Armin Ronacher68f77672008-04-17 11:50:39 +0200123 self._name
Armin Ronacher7c0116f2008-04-12 00:06:19 +0200124 )
125
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200126
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200127class LoopContextBase(object):
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200128 """Helper for extended iteration."""
129
130 def __init__(self, iterable, parent=None):
131 self._iterable = iterable
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200132 self._length = None
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200133 self.index0 = 0
134 self.parent = parent
135
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200136 def cycle(self, *args):
137 """A replacement for the old ``{% cycle %}`` tag."""
138 if not args:
139 raise TypeError('no items for cycling given')
140 return args[self.index0 % len(args)]
141
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200142 first = property(lambda x: x.index0 == 0)
143 last = property(lambda x: x.revindex0 == 0)
144 index = property(lambda x: x.index0 + 1)
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200145 revindex = property(lambda x: x.length - x.index0)
146 revindex0 = property(lambda x: x.length - x.index)
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200147
148 def __len__(self):
149 return self.length
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200150
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200151
152class LoopContext(LoopContextBase):
Armin Ronacherf059ec12008-04-11 22:21:00 +0200153 """A loop context for dynamic iteration."""
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200154
Armin Ronacherf64efb82008-04-18 10:32:14 +0200155 def __init__(self, iterable, enforce_length=False):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200156 self._iterable = iterable
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200157 self._next = iter(iterable).next
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200158 self._length = None
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200159 self.index0 = -1
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200160 if enforce_length:
161 len(self)
162
163 def make_static(self):
164 """Return a static loop context for the optimizer."""
Armin Ronacherf64efb82008-04-18 10:32:14 +0200165 return StaticLoopContext(self.index0, self.length)
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200166
167 def __iter__(self):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200168 return self
169
170 def next(self):
171 self.index0 += 1
172 return self._next(), self
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200173
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200174 @property
175 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200176 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200177 try:
178 length = len(self._iterable)
179 except TypeError:
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200180 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200181 self._next = iter(self._iterable).next
182 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200183 self._length = length
184 return self._length
185
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200186 def __repr__(self):
187 return 'LoopContext(%r)' % self.index0
188
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200189
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200190class StaticLoopContext(LoopContextBase):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200191 """The static loop context is used in the optimizer to "freeze" the
192 status of an iteration. The only reason for this object is if the
193 loop object is accessed in a non static way (eg: becomes part of a
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200194 function call).
195 """
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200196
Armin Ronacherf64efb82008-04-18 10:32:14 +0200197 def __init__(self, index0, length):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200198 self.index0 = index0
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200199 self.length = length
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200200
201 def __repr__(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200202 """The repr is used by the optimizer to dump the object."""
Armin Ronacherf64efb82008-04-18 10:32:14 +0200203 return 'StaticLoopContext(%r, %r)' % (
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200204 self.index0,
Armin Ronacherf64efb82008-04-18 10:32:14 +0200205 self.length
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200206 )
207
208 def make_static(self):
209 return self
210
211
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200212class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200213 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200214
Armin Ronacherc63243e2008-04-14 22:53:58 +0200215 def __init__(self, environment, func, name, arguments, defaults, catch_all, caller):
216 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
220 self.defaults = defaults
221 self.catch_all = catch_all
Armin Ronacher71082072008-04-12 14:19:36 +0200222 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200223
224 def __call__(self, *args, **kwargs):
Armin Ronacher9706fab2008-04-08 18:49:56 +0200225 arg_count = len(self.arguments)
226 if len(args) > arg_count:
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200227 raise TypeError('macro %r takes not more than %d argument(s).' %
228 (self.name, len(self.arguments)))
229 arguments = {}
Armin Ronacher9706fab2008-04-08 18:49:56 +0200230 for idx, name in enumerate(self.arguments):
231 try:
232 value = args[idx]
233 except IndexError:
234 try:
235 value = kwargs.pop(name)
236 except KeyError:
237 try:
238 value = self.defaults[idx - arg_count]
239 except IndexError:
Armin Ronacher9a822052008-04-17 18:44:07 +0200240 value = self._environment.undefined(
241 'parameter %r was not provided' % name)
Christoph Hackf9f029c2008-04-09 15:08:11 +0200242 arguments['l_' + name] = value
Armin Ronacher71082072008-04-12 14:19:36 +0200243 if self.caller:
244 caller = kwargs.pop('caller', None)
245 if caller is None:
Armin Ronacher9a822052008-04-17 18:44:07 +0200246 caller = self._environment.undefined('No caller defined')
Armin Ronacher71082072008-04-12 14:19:36 +0200247 arguments['l_caller'] = caller
Armin Ronacher9706fab2008-04-08 18:49:56 +0200248 if self.catch_all:
249 arguments['l_arguments'] = kwargs
Armin Ronacher625215e2008-04-13 16:31:08 +0200250 return self._func(**arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200251
252 def __repr__(self):
253 return '<%s %s>' % (
254 self.__class__.__name__,
255 self.name is None and 'anonymous' or repr(self.name)
256 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200257
258
259class Undefined(object):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200260 """The default undefined implementation. This undefined implementation
261 can be printed and iterated over, but every other access will raise a
262 `NameError`. Custom undefined classes must subclass this.
263 """
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200264
Armin Ronacher9a822052008-04-17 18:44:07 +0200265 def __init__(self, hint=None, obj=None, name=None):
266 self._undefined_hint = hint
267 self._undefined_obj = obj
268 self._undefined_name = name
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200269
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200270 def _fail_with_error(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200271 if self._undefined_hint is None:
272 if self._undefined_obj is None:
273 hint = '%r is undefined' % self._undefined_name
274 elif not isinstance(self._undefined_name, basestring):
275 hint = '%r object has no element %r' % (
276 self._undefined_obj.__class__.__name__,
277 self._undefined_name
278 )
279 else:
280 hint = '%r object has no attribute %s' % (
281 self._undefined_obj.__class__.__name__,
282 self._undefined_name
283 )
284 else:
285 hint = self._undefined_hint
286 raise UndefinedError(hint)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200287 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
288 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
289 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200290 __getattr__ = __getitem__ = _fail_with_error
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200291
292 def __unicode__(self):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200293 return u''
294
295 def __str__(self):
296 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200297
298 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200299 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200300
301 def __len__(self):
302 return 0
303
304 def __iter__(self):
305 if 0:
306 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200307
308 def __nonzero__(self):
309 return False
310
311
312class DebugUndefined(Undefined):
313 """An undefined that returns the debug info when printed."""
314
315 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200316 if self._undefined_hint is None:
317 if self._undefined_obj is None:
318 return u'{{ %s }}' % self._undefined_name
319 return '{{ no such element: %s[%r] }}' % (
320 self._undefined_obj.__class__.__name__,
321 self._undefined_name
322 )
323 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200324
325
326class StrictUndefined(Undefined):
Priit Laes4149a0e2008-04-17 19:04:44 +0200327 """An undefined that barks on print and iteration as well as boolean tests.
328 In other words: you can do nothing with it except checking if it's defined
329 using the `defined` test.
330 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200331
Priit Laes4149a0e2008-04-17 19:04:44 +0200332 __iter__ = __unicode__ = __len__ = __nonzero__ = Undefined._fail_with_error