blob: 1f1d7bd7bb68c41cf6830277f3fe4ad916878dc0 [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)
145 revindex = property(lambda x: x.length)
146 revindex0 = property(lambda x: x.length - 1)
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
194 function call)."""
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200195
Armin Ronacherf64efb82008-04-18 10:32:14 +0200196 def __init__(self, index0, length):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200197 self.index0 = index0
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200198 self.length = length
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200199
200 def __repr__(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200201 """The repr is used by the optimizer to dump the object."""
Armin Ronacherf64efb82008-04-18 10:32:14 +0200202 return 'StaticLoopContext(%r, %r)' % (
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200203 self.index0,
Armin Ronacherf64efb82008-04-18 10:32:14 +0200204 self.length
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200205 )
206
207 def make_static(self):
208 return self
209
210
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 Ronacherc63243e2008-04-14 22:53:58 +0200214 def __init__(self, environment, func, name, arguments, defaults, catch_all, caller):
215 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200216 self._func = func
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200217 self.name = name
218 self.arguments = arguments
219 self.defaults = defaults
220 self.catch_all = catch_all
Armin Ronacher71082072008-04-12 14:19:36 +0200221 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200222
223 def __call__(self, *args, **kwargs):
Armin Ronacher9706fab2008-04-08 18:49:56 +0200224 arg_count = len(self.arguments)
225 if len(args) > arg_count:
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200226 raise TypeError('macro %r takes not more than %d argument(s).' %
227 (self.name, len(self.arguments)))
228 arguments = {}
Armin Ronacher9706fab2008-04-08 18:49:56 +0200229 for idx, name in enumerate(self.arguments):
230 try:
231 value = args[idx]
232 except IndexError:
233 try:
234 value = kwargs.pop(name)
235 except KeyError:
236 try:
237 value = self.defaults[idx - arg_count]
238 except IndexError:
Armin Ronacher9a822052008-04-17 18:44:07 +0200239 value = self._environment.undefined(
240 'parameter %r was not provided' % name)
Christoph Hackf9f029c2008-04-09 15:08:11 +0200241 arguments['l_' + name] = value
Armin Ronacher71082072008-04-12 14:19:36 +0200242 if self.caller:
243 caller = kwargs.pop('caller', None)
244 if caller is None:
Armin Ronacher9a822052008-04-17 18:44:07 +0200245 caller = self._environment.undefined('No caller defined')
Armin Ronacher71082072008-04-12 14:19:36 +0200246 arguments['l_caller'] = caller
Armin Ronacher9706fab2008-04-08 18:49:56 +0200247 if self.catch_all:
248 arguments['l_arguments'] = kwargs
Armin Ronacher625215e2008-04-13 16:31:08 +0200249 return self._func(**arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200250
251 def __repr__(self):
252 return '<%s %s>' % (
253 self.__class__.__name__,
254 self.name is None and 'anonymous' or repr(self.name)
255 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200256
257
258class Undefined(object):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200259 """The default undefined implementation. This undefined implementation
260 can be printed and iterated over, but every other access will raise a
261 `NameError`. Custom undefined classes must subclass this.
262 """
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200263
Armin Ronacher9a822052008-04-17 18:44:07 +0200264 def __init__(self, hint=None, obj=None, name=None):
265 self._undefined_hint = hint
266 self._undefined_obj = obj
267 self._undefined_name = name
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200268
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200269 def _fail_with_error(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200270 if self._undefined_hint is None:
271 if self._undefined_obj is None:
272 hint = '%r is undefined' % self._undefined_name
273 elif not isinstance(self._undefined_name, basestring):
274 hint = '%r object has no element %r' % (
275 self._undefined_obj.__class__.__name__,
276 self._undefined_name
277 )
278 else:
279 hint = '%r object has no attribute %s' % (
280 self._undefined_obj.__class__.__name__,
281 self._undefined_name
282 )
283 else:
284 hint = self._undefined_hint
285 raise UndefinedError(hint)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200286 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
287 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
288 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200289 __getattr__ = __getitem__ = _fail_with_error
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200290
291 def __unicode__(self):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200292 return u''
293
294 def __str__(self):
295 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200296
297 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200298 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200299
300 def __len__(self):
301 return 0
302
303 def __iter__(self):
304 if 0:
305 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200306
307 def __nonzero__(self):
308 return False
309
310
311class DebugUndefined(Undefined):
312 """An undefined that returns the debug info when printed."""
313
314 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200315 if self._undefined_hint is None:
316 if self._undefined_obj is None:
317 return u'{{ %s }}' % self._undefined_name
318 return '{{ no such element: %s[%r] }}' % (
319 self._undefined_obj.__class__.__name__,
320 self._undefined_name
321 )
322 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200323
324
325class StrictUndefined(Undefined):
Priit Laes4149a0e2008-04-17 19:04:44 +0200326 """An undefined that barks on print and iteration as well as boolean tests.
327 In other words: you can do nothing with it except checking if it's defined
328 using the `defined` test.
329 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200330
Priit Laes4149a0e2008-04-17 19:04:44 +0200331 __iter__ = __unicode__ = __len__ = __nonzero__ = Undefined._fail_with_error