2dbd5693edd6d204110dd71ec131c41f2a1c6b3b
[jinja2.git] / jinja2 / runtime.py
1 # -*- 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 """
11 import sys
12 from types import FunctionType, MethodType
13 from itertools import chain, imap
14 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, concat
15 from jinja2.exceptions import UndefinedError, TemplateRuntimeError
16
17
18 # these variables are exported to the template runtime
19 __all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup',
20            'TemplateRuntimeError', 'missing', 'concat', 'escape',
21            'markup_join', 'unicode_join']
22
23 _context_function_types = (FunctionType, MethodType)
24
25
26 def markup_join(seq):
27     """Concatenation that escapes if necessary and converts to unicode."""
28     buf = []
29     iterator = imap(soft_unicode, seq)
30     for arg in iterator:
31         buf.append(arg)
32         if hasattr(arg, '__html__'):
33             return Markup(u'').join(chain(buf, iterator))
34     return concat(buf)
35
36
37 def unicode_join(seq):
38     """Simple args to unicode conversion and concatenation."""
39     return concat(imap(unicode, seq))
40
41
42 class Context(object):
43     """The template context holds the variables of a template.  It stores the
44     values passed to the template and also the names the template exports.
45     Creating instances is neither supported nor useful as it's created
46     automatically at various stages of the template evaluation and should not
47     be created by hand.
48
49     The context is immutable.  Modifications on :attr:`parent` **must not**
50     happen and modifications on :attr:`vars` are allowed from generated
51     template code only.  Template filters and global functions marked as
52     :func:`contextfunction`\s get the active context passed as first argument
53     and are allowed to access the context read-only.
54
55     The template context supports read only dict operations (`get`,
56     `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
57     `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
58     method that doesn't fail with a `KeyError` but returns an
59     :class:`Undefined` object for missing variables.
60     """
61     __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name',
62                  'blocks')
63
64     def __init__(self, environment, parent, name, blocks):
65         self.parent = parent
66         self.vars = vars = {}
67         self.environment = environment
68         self.exported_vars = set()
69         self.name = name
70
71         # create the initial mapping of blocks.  Whenever template inheritance
72         # takes place the runtime will update this mapping with the new blocks
73         # from the template.
74         self.blocks = dict((k, [v]) for k, v in blocks.iteritems())
75
76     def super(self, name, current):
77         """Render a parent block."""
78         try:
79             blocks = self.blocks[name]
80             block = blocks[blocks.index(current) + 1]
81         except LookupError:
82             return self.environment.undefined('there is no parent block '
83                                               'called %r.' % name,
84                                               name='super')
85         wrap = self.environment.autoescape and Markup or (lambda x: x)
86         render = lambda: wrap(concat(block(self)))
87         render.__name__ = render.name = name
88         return render
89
90     def get(self, key, default=None):
91         """Returns an item from the template context, if it doesn't exist
92         `default` is returned.
93         """
94         try:
95             return self[key]
96         except KeyError:
97             return default
98
99     def resolve(self, key):
100         """Looks up a variable like `__getitem__` or `get` but returns an
101         :class:`Undefined` object with the name of the name looked up.
102         """
103         if key in self.vars:
104             return self.vars[key]
105         if key in self.parent:
106             return self.parent[key]
107         return self.environment.undefined(name=key)
108
109     def get_exported(self):
110         """Get a new dict with the exported variables."""
111         return dict((k, self.vars[k]) for k in self.exported_vars)
112
113     def get_all(self):
114         """Return a copy of the complete context as dict including the
115         exported variables.
116         """
117         return dict(self.parent, **self.vars)
118
119     def call(__self, __obj, *args, **kwargs):
120         """Call the callable with the arguments and keyword arguments
121         provided but inject the active context or environment as first
122         argument if the callable is a :func:`contextfunction` or
123         :func:`environmentfunction`.
124         """
125         if __debug__:
126             __traceback_hide__ = True
127         if isinstance(__obj, _context_function_types):
128             if getattr(__obj, 'contextfunction', 0):
129                 args = (__self,) + args
130             elif getattr(__obj, 'environmentfunction', 0):
131                 args = (__self.environment,) + args
132         return __obj(*args, **kwargs)
133
134     def _all(meth):
135         proxy = lambda self: getattr(self.get_all(), meth)()
136         proxy.__doc__ = getattr(dict, meth).__doc__
137         proxy.__name__ = meth
138         return proxy
139
140     keys = _all('keys')
141     values = _all('values')
142     items = _all('items')
143     iterkeys = _all('iterkeys')
144     itervalues = _all('itervalues')
145     iteritems = _all('iteritems')
146     del _all
147
148     def __contains__(self, name):
149         return name in self.vars or name in self.parent
150
151     def __getitem__(self, key):
152         """Lookup a variable or raise `KeyError` if the variable is
153         undefined.
154         """
155         item = self.resolve(key)
156         if isinstance(item, Undefined):
157             raise KeyError(key)
158         return item
159
160     def __repr__(self):
161         return '<%s %s of %r>' % (
162             self.__class__.__name__,
163             repr(self.get_all()),
164             self.name
165         )
166
167
168 # register the context as mutable mapping if possible
169 try:
170     from collections import MutableMapping
171     MutableMapping.register(Context)
172 except ImportError:
173     pass
174
175
176 class TemplateReference(object):
177     """The `self` in templates."""
178
179     def __init__(self, context):
180         self.__context = context
181
182     def __getitem__(self, name):
183         func = self.__context.blocks[name][0]
184         wrap = self.__context.environment.autoescape and \
185                Markup or (lambda x: x)
186         render = lambda: wrap(concat(func(self.__context)))
187         render.__name__ = render.name = name
188         return render
189
190     def __repr__(self):
191         return '<%s %r>' % (
192             self.__class__.__name__,
193             self._context.name
194         )
195
196
197 class LoopContext(object):
198     """A loop context for dynamic iteration."""
199
200     def __init__(self, iterable, enforce_length=False, recurse=None):
201         self._iterable = iterable
202         self._next = iter(iterable).next
203         self._length = None
204         self._recurse = recurse
205         self.index0 = -1
206         if enforce_length:
207             len(self)
208
209     def cycle(self, *args):
210         """Cycles among the arguments with the current loop index."""
211         if not args:
212             raise TypeError('no items for cycling given')
213         return args[self.index0 % len(args)]
214
215     first = property(lambda x: x.index0 == 0)
216     last = property(lambda x: x.revindex0 == 0)
217     index = property(lambda x: x.index0 + 1)
218     revindex = property(lambda x: x.length - x.index0)
219     revindex0 = property(lambda x: x.length - x.index)
220
221     def __len__(self):
222         return self.length
223
224     def __iter__(self):
225         return LoopContextIterator(self)
226
227     def loop(self, iterable):
228         if self._recurse is None:
229             raise TypeError('Tried to call non recursive loop.  Maybe you '
230                             "forgot the 'recursive' modifier.")
231         return self._recurse(iterable, self._recurse)
232
233     # a nifty trick to enhance the error message if someone tried to call
234     # the the loop without or with too many arguments.
235     __call__ = loop; del loop
236
237     @property
238     def length(self):
239         if self._length is None:
240             try:
241                 # first try to get the length from the iterable (if the
242                 # iterable is a sequence)
243                 length = len(self._iterable)
244             except TypeError:
245                 # if that's not possible (ie: iterating over a generator)
246                 # we have to convert the iterable into a sequence and
247                 # use the length of that.
248                 self._iterable = tuple(self._iterable)
249                 self._next = iter(self._iterable).next
250                 length = len(tuple(self._iterable)) + self.index0 + 1
251             self._length = length
252         return self._length
253
254     def __repr__(self):
255         return '<%s %r/%r>' % (
256             self.__class__.__name__,
257             self.index,
258             self.length
259         )
260
261
262 class LoopContextIterator(object):
263     """The iterator for a loop context."""
264     __slots__ = ('context',)
265
266     def __init__(self, context):
267         self.context = context
268
269     def __iter__(self):
270         return self
271
272     def next(self):
273         ctx = self.context
274         ctx.index0 += 1
275         return ctx._next(), ctx
276
277
278 class Macro(object):
279     """Wraps a macro."""
280
281     def __init__(self, environment, func, name, arguments, defaults,
282                  catch_kwargs, catch_varargs, caller):
283         self._environment = environment
284         self._func = func
285         self._argument_count = len(arguments)
286         self.name = name
287         self.arguments = arguments
288         self.defaults = defaults
289         self.catch_kwargs = catch_kwargs
290         self.catch_varargs = catch_varargs
291         self.caller = caller
292
293     def __call__(self, *args, **kwargs):
294         arguments = []
295         for idx, name in enumerate(self.arguments):
296             try:
297                 value = args[idx]
298             except:
299                 try:
300                     value = kwargs.pop(name)
301                 except:
302                     try:
303                         value = self.defaults[idx - self._argument_count]
304                     except:
305                         value = self._environment.undefined(
306                             'parameter %r was not provided' % name, name=name)
307             arguments.append(value)
308
309         # it's important that the order of these arguments does not change
310         # if not also changed in the compiler's `function_scoping` method.
311         # the order is caller, keyword arguments, positional arguments!
312         if self.caller:
313             caller = kwargs.pop('caller', None)
314             if caller is None:
315                 caller = self._environment.undefined('No caller defined',
316                                                      name='caller')
317             arguments.append(caller)
318         if self.catch_kwargs:
319             arguments.append(kwargs)
320         elif kwargs:
321             raise TypeError('macro %r takes no keyword argument %r' %
322                             (self.name, iter(kwargs).next()))
323         if self.catch_varargs:
324             arguments.append(args[self._argument_count:])
325         elif len(args) > self._argument_count:
326             raise TypeError('macro %r takes not more than %d argument(s)' %
327                             (self.name, len(self.arguments)))
328         return self._func(*arguments)
329
330     def __repr__(self):
331         return '<%s %s>' % (
332             self.__class__.__name__,
333             self.name is None and 'anonymous' or repr(self.name)
334         )
335
336
337 class Undefined(object):
338     """The default undefined type.  This undefined type can be printed and
339     iterated over, but every other access will raise an :exc:`UndefinedError`:
340
341     >>> foo = Undefined(name='foo')
342     >>> str(foo)
343     ''
344     >>> not foo
345     True
346     >>> foo + 42
347     Traceback (most recent call last):
348       ...
349     jinja2.exceptions.UndefinedError: 'foo' is undefined
350     """
351     __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
352                  '_undefined_exception')
353
354     def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError):
355         self._undefined_hint = hint
356         self._undefined_obj = obj
357         self._undefined_name = name
358         self._undefined_exception = exc
359
360     def _fail_with_undefined_error(self, *args, **kwargs):
361         """Regular callback function for undefined objects that raises an
362         `UndefinedError` on call.
363         """
364         if self._undefined_hint is None:
365             if self._undefined_obj is None:
366                 hint = '%r is undefined' % self._undefined_name
367             elif not isinstance(self._undefined_name, basestring):
368                 hint = '%r object has no element %r' % (
369                     self._undefined_obj.__class__.__name__,
370                     self._undefined_name
371                 )
372             else:
373                 hint = '%r object has no attribute %r' % (
374                     self._undefined_obj.__class__.__name__,
375                     self._undefined_name
376                 )
377         else:
378             hint = self._undefined_hint
379         raise self._undefined_exception(hint)
380
381     __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
382     __realdiv__ = __rrealdiv__ = __floordiv__ = __rfloordiv__ = \
383     __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
384     __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
385     __int__ = __float__ = __complex__ = _fail_with_undefined_error
386
387     def __str__(self):
388         return self.__unicode__().encode('utf-8')
389
390     def __unicode__(self):
391         return u''
392
393     def __len__(self):
394         return 0
395
396     def __iter__(self):
397         if 0:
398             yield None
399
400     def __nonzero__(self):
401         return False
402
403     def __repr__(self):
404         return 'Undefined'
405
406
407 class DebugUndefined(Undefined):
408     """An undefined that returns the debug info when printed.
409
410     >>> foo = DebugUndefined(name='foo')
411     >>> str(foo)
412     '{{ foo }}'
413     >>> not foo
414     True
415     >>> foo + 42
416     Traceback (most recent call last):
417       ...
418     jinja2.exceptions.UndefinedError: 'foo' is undefined
419     """
420     __slots__ = ()
421
422     def __unicode__(self):
423         if self._undefined_hint is None:
424             if self._undefined_obj is None:
425                 return u'{{ %s }}' % self._undefined_name
426             return '{{ no such element: %s[%r] }}' % (
427                 self._undefined_obj.__class__.__name__,
428                 self._undefined_name
429             )
430         return u'{{ undefined value printed: %s }}' % self._undefined_hint
431
432
433 class StrictUndefined(Undefined):
434     """An undefined that barks on print and iteration as well as boolean
435     tests and all kinds of comparisons.  In other words: you can do nothing
436     with it except checking if it's defined using the `defined` test.
437
438     >>> foo = StrictUndefined(name='foo')
439     >>> str(foo)
440     Traceback (most recent call last):
441       ...
442     jinja2.exceptions.UndefinedError: 'foo' is undefined
443     >>> not foo
444     Traceback (most recent call last):
445       ...
446     jinja2.exceptions.UndefinedError: 'foo' is undefined
447     >>> foo + 42
448     Traceback (most recent call last):
449       ...
450     jinja2.exceptions.UndefinedError: 'foo' is undefined
451     """
452     __slots__ = ()
453     __iter__ = __unicode__ = __len__ = __nonzero__ = __eq__ = __ne__ = \
454         Undefined._fail_with_undefined_error
455
456
457 # remove remaining slots attributes, after the metaclass did the magic they
458 # are unneeded and irritating as they contain wrong data for the subclasses.
459 del Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__