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