blob: 8e407c9a9b7f22fe1b06cda4c424d561d4b18df9 [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
155 def __init__(self, iterable, parent=None, enforce_length=False):
156 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 self.parent = parent
161 if enforce_length:
162 len(self)
163
164 def make_static(self):
165 """Return a static loop context for the optimizer."""
166 parent = None
167 if self.parent is not None:
168 parent = self.parent.make_static()
169 return StaticLoopContext(self.index0, self.length, parent)
170
171 def __iter__(self):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200172 return self
173
174 def next(self):
175 self.index0 += 1
176 return self._next(), self
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200177
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200178 @property
179 def length(self):
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200180 if self._length is None:
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200181 try:
182 length = len(self._iterable)
183 except TypeError:
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200184 self._iterable = tuple(self._iterable)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200185 self._next = iter(self._iterable).next
186 length = len(tuple(self._iterable)) + self.index0 + 1
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200187 self._length = length
188 return self._length
189
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200190 def __repr__(self):
191 return 'LoopContext(%r)' % self.index0
192
Armin Ronacher180a1bd2008-04-09 12:14:24 +0200193
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200194class StaticLoopContext(LoopContextBase):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200195 """The static loop context is used in the optimizer to "freeze" the
196 status of an iteration. The only reason for this object is if the
197 loop object is accessed in a non static way (eg: becomes part of a
198 function call)."""
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200199
200 def __init__(self, index0, length, parent):
201 self.index0 = index0
202 self.parent = parent
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200203 self.length = length
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200204
205 def __repr__(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200206 """The repr is used by the optimizer to dump the object."""
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200207 return 'StaticLoopContext(%r, %r, %r)' % (
208 self.index0,
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200209 self.length,
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200210 self.parent
211 )
212
213 def make_static(self):
214 return self
215
216
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200217class Macro(object):
Armin Ronacherd55ab532008-04-09 16:13:39 +0200218 """Wraps a macro."""
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200219
Armin Ronacherc63243e2008-04-14 22:53:58 +0200220 def __init__(self, environment, func, name, arguments, defaults, catch_all, caller):
221 self._environment = environment
Armin Ronacher71082072008-04-12 14:19:36 +0200222 self._func = func
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200223 self.name = name
224 self.arguments = arguments
225 self.defaults = defaults
226 self.catch_all = catch_all
Armin Ronacher71082072008-04-12 14:19:36 +0200227 self.caller = caller
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200228
229 def __call__(self, *args, **kwargs):
Armin Ronacher9706fab2008-04-08 18:49:56 +0200230 arg_count = len(self.arguments)
231 if len(args) > arg_count:
Armin Ronacher4f62a9f2008-04-08 18:09:13 +0200232 raise TypeError('macro %r takes not more than %d argument(s).' %
233 (self.name, len(self.arguments)))
234 arguments = {}
Armin Ronacher9706fab2008-04-08 18:49:56 +0200235 for idx, name in enumerate(self.arguments):
236 try:
237 value = args[idx]
238 except IndexError:
239 try:
240 value = kwargs.pop(name)
241 except KeyError:
242 try:
243 value = self.defaults[idx - arg_count]
244 except IndexError:
Armin Ronacher9a822052008-04-17 18:44:07 +0200245 value = self._environment.undefined(
246 'parameter %r was not provided' % name)
Christoph Hackf9f029c2008-04-09 15:08:11 +0200247 arguments['l_' + name] = value
Armin Ronacher71082072008-04-12 14:19:36 +0200248 if self.caller:
249 caller = kwargs.pop('caller', None)
250 if caller is None:
Armin Ronacher9a822052008-04-17 18:44:07 +0200251 caller = self._environment.undefined('No caller defined')
Armin Ronacher71082072008-04-12 14:19:36 +0200252 arguments['l_caller'] = caller
Armin Ronacher9706fab2008-04-08 18:49:56 +0200253 if self.catch_all:
254 arguments['l_arguments'] = kwargs
Armin Ronacher625215e2008-04-13 16:31:08 +0200255 return self._func(**arguments)
Armin Ronacher71082072008-04-12 14:19:36 +0200256
257 def __repr__(self):
258 return '<%s %s>' % (
259 self.__class__.__name__,
260 self.name is None and 'anonymous' or repr(self.name)
261 )
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200262
263
264class Undefined(object):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200265 """The default undefined implementation. This undefined implementation
266 can be printed and iterated over, but every other access will raise a
267 `NameError`. Custom undefined classes must subclass this.
268 """
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200269
Armin Ronacher9a822052008-04-17 18:44:07 +0200270 def __init__(self, hint=None, obj=None, name=None):
271 self._undefined_hint = hint
272 self._undefined_obj = obj
273 self._undefined_name = name
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200274
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200275 def _fail_with_error(self, *args, **kwargs):
Armin Ronacher9a822052008-04-17 18:44:07 +0200276 if self._undefined_hint is None:
277 if self._undefined_obj is None:
278 hint = '%r is undefined' % self._undefined_name
279 elif not isinstance(self._undefined_name, basestring):
280 hint = '%r object has no element %r' % (
281 self._undefined_obj.__class__.__name__,
282 self._undefined_name
283 )
284 else:
285 hint = '%r object has no attribute %s' % (
286 self._undefined_obj.__class__.__name__,
287 self._undefined_name
288 )
289 else:
290 hint = self._undefined_hint
291 raise UndefinedError(hint)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200292 __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
293 __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
294 __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200295 __getattr__ = __getitem__ = _fail_with_error
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200296
297 def __unicode__(self):
Armin Ronacherc63243e2008-04-14 22:53:58 +0200298 return u''
299
300 def __str__(self):
301 return self.__unicode__().encode('utf-8')
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200302
303 def __repr__(self):
Priit Laes4149a0e2008-04-17 19:04:44 +0200304 return 'Undefined'
Armin Ronacherd1d2f3d2008-04-09 14:02:55 +0200305
306 def __len__(self):
307 return 0
308
309 def __iter__(self):
310 if 0:
311 yield None
Armin Ronacherc63243e2008-04-14 22:53:58 +0200312
313 def __nonzero__(self):
314 return False
315
316
317class DebugUndefined(Undefined):
318 """An undefined that returns the debug info when printed."""
319
320 def __unicode__(self):
Armin Ronacher9a822052008-04-17 18:44:07 +0200321 if self._undefined_hint is None:
322 if self._undefined_obj is None:
323 return u'{{ %s }}' % self._undefined_name
324 return '{{ no such element: %s[%r] }}' % (
325 self._undefined_obj.__class__.__name__,
326 self._undefined_name
327 )
328 return u'{{ undefined value printed: %s }}' % self._undefined_hint
Armin Ronacherc63243e2008-04-14 22:53:58 +0200329
330
331class StrictUndefined(Undefined):
Priit Laes4149a0e2008-04-17 19:04:44 +0200332 """An undefined that barks on print and iteration as well as boolean tests.
333 In other words: you can do nothing with it except checking if it's defined
334 using the `defined` test.
335 """
Armin Ronacherc63243e2008-04-14 22:53:58 +0200336
Priit Laes4149a0e2008-04-17 19:04:44 +0200337 __iter__ = __unicode__ = __len__ = __nonzero__ = Undefined._fail_with_error