1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# -*- coding: utf-8 -*-
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez"""
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    jinja2.runtime
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ~~~~~~~~~~~~~~
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Runtime helpers.
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :copyright: (c) 2010 by the Jinja Team.
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :license: BSD.
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez"""
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom itertools import chain
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.nodes import EvalContext, _context_function_types
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     internalcode, object_type_repr
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     TemplateNotFound
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2._compat import next, imap, text_type, iteritems, \
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     implements_iterator, implements_to_string, string_types, PY2
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# these variables are exported to the template runtime
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez           'TemplateRuntimeError', 'missing', 'concat', 'escape',
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez           'markup_join', 'unicode_join', 'to_string', 'identity',
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez           'TemplateNotFound']
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: the name of the function that is used to convert something into
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: a string.  We can just use the text type here.
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezto_string = text_type
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: the identity function.  Useful for certain things in the environment
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezidentity = lambda x: x
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_last_iteration = object()
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef markup_join(seq):
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Concatenation that escapes if necessary and converts to unicode."""
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    buf = []
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    iterator = imap(soft_unicode, seq)
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for arg in iterator:
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        buf.append(arg)
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if hasattr(arg, '__html__'):
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return Markup(u'').join(chain(buf, iterator))
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return concat(buf)
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef unicode_join(seq):
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Simple args to unicode conversion and concatenation."""
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return concat(imap(text_type, seq))
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef new_context(environment, template_name, blocks, vars=None,
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                shared=None, globals=None, locals=None):
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Internal helper to for context creation."""
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if vars is None:
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        vars = {}
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if shared:
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        parent = vars
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    else:
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        parent = dict(globals or (), **vars)
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if locals:
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # if the parent is shared a copy should be created because
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # we don't want to modify the dict passed
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if shared:
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            parent = dict(parent)
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        for key, value in iteritems(locals):
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if key[:2] == 'l_' and value is not missing:
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                parent[key[2:]] = value
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return Context(environment, parent, template_name, blocks)
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass TemplateReference(object):
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """The `self` in templates."""
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, context):
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.__context = context
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __getitem__(self, name):
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        blocks = self.__context.blocks[name]
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return BlockReference(name, self.__context, blocks, 0)
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __repr__(self):
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return '<%s %r>' % (
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.__class__.__name__,
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.__context.name
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        )
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Context(object):
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """The template context holds the variables of a template.  It stores the
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    values passed to the template and also the names the template exports.
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Creating instances is neither supported nor useful as it's created
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    automatically at various stages of the template evaluation and should not
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    be created by hand.
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    The context is immutable.  Modifications on :attr:`parent` **must not**
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    happen and modifications on :attr:`vars` are allowed from generated
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    template code only.  Template filters and global functions marked as
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :func:`contextfunction`\s get the active context passed as first argument
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    and are allowed to access the context read-only.
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    The template context supports read only dict operations (`get`,
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    method that doesn't fail with a `KeyError` but returns an
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :class:`Undefined` object for missing variables.
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars',
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 'name', 'blocks', '__weakref__')
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, environment, parent, name, blocks):
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.parent = parent
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.vars = {}
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.environment = environment
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.eval_ctx = EvalContext(self.environment, name)
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.exported_vars = set()
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.name = name
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # create the initial mapping of blocks.  Whenever template inheritance
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # takes place the runtime will update this mapping with the new blocks
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # from the template.
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def super(self, name, current):
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Render a parent block."""
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            blocks = self.blocks[name]
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            index = blocks.index(current) + 1
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            blocks[index]
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except LookupError:
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self.environment.undefined('there is no parent block '
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                              'called %r.' % name,
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                              name='super')
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return BlockReference(name, self, blocks, index)
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def get(self, key, default=None):
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Returns an item from the template context, if it doesn't exist
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        `default` is returned.
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self[key]
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except KeyError:
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return default
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def resolve(self, key):
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Looks up a variable like `__getitem__` or `get` but returns an
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        :class:`Undefined` object with the name of the name looked up.
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if key in self.vars:
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self.vars[key]
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if key in self.parent:
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self.parent[key]
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.environment.undefined(name=key)
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def get_exported(self):
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Get a new dict with the exported variables."""
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return dict((k, self.vars[k]) for k in self.exported_vars)
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def get_all(self):
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Return a copy of the complete context as dict including the
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        exported variables.
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return dict(self.parent, **self.vars)
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def call(__self, __obj, *args, **kwargs):
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Call the callable with the arguments and keyword arguments
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        provided but inject the active context or environment as first
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        argument if the callable is a :func:`contextfunction` or
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        :func:`environmentfunction`.
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if __debug__:
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            __traceback_hide__ = True
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # Allow callable classes to take a context
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        fn = __obj.__call__
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        for fn_type in ('contextfunction',
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        'evalcontextfunction',
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        'environmentfunction'):
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if hasattr(fn, fn_type):
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                __obj = fn
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                break
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if isinstance(__obj, _context_function_types):
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if getattr(__obj, 'contextfunction', 0):
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                args = (__self,) + args
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            elif getattr(__obj, 'evalcontextfunction', 0):
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                args = (__self.eval_ctx,) + args
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            elif getattr(__obj, 'environmentfunction', 0):
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                args = (__self.environment,) + args
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return __obj(*args, **kwargs)
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except StopIteration:
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return __self.environment.undefined('value was undefined because '
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                'a callable raised a '
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                'StopIteration exception')
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def derived(self, locals=None):
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Internal helper function to create a derived context."""
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        context = new_context(self.environment, self.name, {},
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                              self.parent, True, None, locals)
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        context.vars.update(self.vars)
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        context.eval_ctx = self.eval_ctx
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return context
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def _all(meth):
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        proxy = lambda self: getattr(self.get_all(), meth)()
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        proxy.__doc__ = getattr(dict, meth).__doc__
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        proxy.__name__ = meth
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return proxy
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    keys = _all('keys')
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    values = _all('values')
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    items = _all('items')
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    # not available on python 3
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if PY2:
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        iterkeys = _all('iterkeys')
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        itervalues = _all('itervalues')
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        iteritems = _all('iteritems')
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    del _all
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __contains__(self, name):
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return name in self.vars or name in self.parent
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __getitem__(self, key):
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Lookup a variable or raise `KeyError` if the variable is
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        undefined.
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        item = self.resolve(key)
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if isinstance(item, Undefined):
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise KeyError(key)
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return item
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __repr__(self):
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return '<%s %s of %r>' % (
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.__class__.__name__,
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            repr(self.get_all()),
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.name
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        )
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# register the context as mapping if possible
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztry:
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    from collections import Mapping
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Mapping.register(Context)
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezexcept ImportError:
250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pass
251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass BlockReference(object):
254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """One block on a template reference."""
255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, name, context, stack, depth):
257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.name = name
258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._context = context
259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._stack = stack
260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._depth = depth
261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @property
263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def super(self):
264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Super the block."""
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._depth + 1 >= len(self._stack):
266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self._context.environment. \
267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                undefined('there is no parent block called %r.' %
268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          self.name, name='super')
269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return BlockReference(self.name, self._context, self._stack,
270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                              self._depth + 1)
271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __call__(self):
274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        rv = concat(self._stack[self._depth](self._context))
275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._context.eval_ctx.autoescape:
276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            rv = Markup(rv)
277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return rv
278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass LoopContext(object):
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """A loop context for dynamic iteration."""
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, iterable, recurse=None, depth0=0):
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._iterator = iter(iterable)
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._recurse = recurse
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._after = self._safe_next()
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.index0 = -1
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.depth0 = depth0
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # try to get the length of the iterable early.  This must be done
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # here because there are some broken iterators around where there
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # __len__ is the number of iterations left (i'm looking at your
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # listreverseiterator!).
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self._length = len(iterable)
296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except (TypeError, AttributeError):
297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self._length = None
298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def cycle(self, *args):
300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Cycles among the arguments with the current loop index."""
301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if not args:
302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise TypeError('no items for cycling given')
303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return args[self.index0 % len(args)]
304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    first = property(lambda x: x.index0 == 0)
306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    last = property(lambda x: x._after is _last_iteration)
307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    index = property(lambda x: x.index0 + 1)
308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    revindex = property(lambda x: x.length - x.index0)
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    revindex0 = property(lambda x: x.length - x.index)
310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    depth = property(lambda x: x.depth0 + 1)
311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __len__(self):
313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.length
314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __iter__(self):
316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return LoopContextIterator(self)
317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def _safe_next(self):
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return next(self._iterator)
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except StopIteration:
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return _last_iteration
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def loop(self, iterable):
326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._recurse is None:
327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise TypeError('Tried to call non recursive loop.  Maybe you '
328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            "forgot the 'recursive' modifier.")
329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self._recurse(iterable, self._recurse, self.depth0 + 1)
330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    # a nifty trick to enhance the error message if someone tried to call
332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    # the the loop without or with too many arguments.
333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __call__ = loop
334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    del loop
335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @property
337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def length(self):
338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._length is None:
339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            # if was not possible to get the length of the iterator when
340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            # the loop context was created (ie: iterating over a generator)
341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            # we have to convert the iterable into a sequence and use the
342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            # length of that.
343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            iterable = tuple(self._iterator)
344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self._iterator = iter(iterable)
345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self._length = len(iterable) + self.index0 + 1
346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self._length
347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __repr__(self):
349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return '<%s %r/%r>' % (
350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.__class__.__name__,
351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.index,
352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.length
353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        )
354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez@implements_iterator
357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass LoopContextIterator(object):
358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """The iterator for a loop context."""
359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __slots__ = ('context',)
360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, context):
362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.context = context
363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __iter__(self):
365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self
366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __next__(self):
368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ctx = self.context
369645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ctx.index0 += 1
370645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if ctx._after is _last_iteration:
371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise StopIteration()
372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        next_elem = ctx._after
373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ctx._after = ctx._safe_next()
374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return next_elem, ctx
375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Macro(object):
378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Wraps a macro function."""
379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, environment, func, name, arguments, defaults,
381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 catch_kwargs, catch_varargs, caller):
382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._environment = environment
383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._func = func
384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._argument_count = len(arguments)
385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.name = name
386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.arguments = arguments
387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.defaults = defaults
388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.catch_kwargs = catch_kwargs
389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.catch_varargs = catch_varargs
390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.caller = caller
391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __call__(self, *args, **kwargs):
394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # try to consume the positional arguments
395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        arguments = list(args[:self._argument_count])
396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        off = len(arguments)
397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # if the number of arguments consumed is not the number of
399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # arguments expected we start filling in keyword arguments
400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # and defaults.
401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if off != self._argument_count:
402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            for idx, name in enumerate(self.arguments[len(arguments):]):
403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                try:
404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    value = kwargs.pop(name)
405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                except KeyError:
406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    try:
407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        value = self.defaults[idx - self._argument_count + off]
408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    except IndexError:
409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        value = self._environment.undefined(
410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            'parameter %r was not provided' % name, name=name)
411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                arguments.append(value)
412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # it's important that the order of these arguments does not change
414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # if not also changed in the compiler's `function_scoping` method.
415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # the order is caller, keyword arguments, positional arguments!
416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self.caller:
417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            caller = kwargs.pop('caller', None)
418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if caller is None:
419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                caller = self._environment.undefined('No caller defined',
420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                     name='caller')
421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            arguments.append(caller)
422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self.catch_kwargs:
423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            arguments.append(kwargs)
424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        elif kwargs:
425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise TypeError('macro %r takes no keyword argument %r' %
426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            (self.name, next(iter(kwargs))))
427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self.catch_varargs:
428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            arguments.append(args[self._argument_count:])
429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        elif len(args) > self._argument_count:
430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise TypeError('macro %r takes not more than %d argument(s)' %
431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            (self.name, len(self.arguments)))
432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self._func(*arguments)
433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __repr__(self):
435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return '<%s %s>' % (
436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.__class__.__name__,
437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            self.name is None and 'anonymous' or repr(self.name)
438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        )
439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez@implements_to_string
442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Undefined(object):
443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """The default undefined type.  This undefined type can be printed and
444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    iterated over, but every other access will raise an :exc:`UndefinedError`:
445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo = Undefined(name='foo')
447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> str(foo)
448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ''
449645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> not foo
450645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
451645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo + 42
452645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traceback (most recent call last):
453645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ...
454645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UndefinedError: 'foo' is undefined
455645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
456645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
457645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 '_undefined_exception')
458645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
459645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
460645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._undefined_hint = hint
461645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._undefined_obj = obj
462645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._undefined_name = name
463645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self._undefined_exception = exc
464645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
465645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
466645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def _fail_with_undefined_error(self, *args, **kwargs):
467645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Regular callback function for undefined objects that raises an
468645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        `UndefinedError` on call.
469645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
470645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._undefined_hint is None:
471645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if self._undefined_obj is missing:
472645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                hint = '%r is undefined' % self._undefined_name
473645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            elif not isinstance(self._undefined_name, string_types):
474645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                hint = '%s has no element %r' % (
475645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    object_type_repr(self._undefined_obj),
476645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    self._undefined_name
477645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                )
478645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            else:
479645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                hint = '%r has no attribute %r' % (
480645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    object_type_repr(self._undefined_obj),
481645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    self._undefined_name
482645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                )
483645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        else:
484645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            hint = self._undefined_hint
485645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        raise self._undefined_exception(hint)
486645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
487645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    @internalcode
488645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __getattr__(self, name):
489645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if name[:2] == '__':
490645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise AttributeError(name)
491645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self._fail_with_undefined_error()
492645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
493645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
494645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
495645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
496645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
497645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __float__ = __complex__ = __pow__ = __rpow__ = \
498645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        _fail_with_undefined_error
499645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
500645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __eq__(self, other):
501645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return type(self) is type(other)
502645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
503645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __ne__(self, other):
504645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return not self.__eq__(other)
505645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
506645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __hash__(self):
507645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return id(type(self))
508645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
509645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __str__(self):
510645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return u''
511645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
512645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __len__(self):
513645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return 0
514645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
515645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __iter__(self):
516645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if 0:
517645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            yield None
518645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
519645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __nonzero__(self):
520645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return False
521645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
522645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __repr__(self):
523645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return 'Undefined'
524645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
525645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
526645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez@implements_to_string
527645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass DebugUndefined(Undefined):
528645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """An undefined that returns the debug info when printed.
529645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
530645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo = DebugUndefined(name='foo')
531645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> str(foo)
532645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    '{{ foo }}'
533645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> not foo
534645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
535645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo + 42
536645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traceback (most recent call last):
537645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ...
538645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UndefinedError: 'foo' is undefined
539645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
540645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __slots__ = ()
541645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
542645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __str__(self):
543645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if self._undefined_hint is None:
544645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if self._undefined_obj is missing:
545645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                return u'{{ %s }}' % self._undefined_name
546645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return '{{ no such element: %s[%r] }}' % (
547645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                object_type_repr(self._undefined_obj),
548645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                self._undefined_name
549645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            )
550645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return u'{{ undefined value printed: %s }}' % self._undefined_hint
551645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
552645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
553645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez@implements_to_string
554645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass StrictUndefined(Undefined):
555645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """An undefined that barks on print and iteration as well as boolean
556645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    tests and all kinds of comparisons.  In other words: you can do nothing
557645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    with it except checking if it's defined using the `defined` test.
558645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
559645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo = StrictUndefined(name='foo')
560645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> str(foo)
561645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traceback (most recent call last):
562645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ...
563645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UndefinedError: 'foo' is undefined
564645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> not foo
565645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traceback (most recent call last):
566645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ...
567645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UndefinedError: 'foo' is undefined
568645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> foo + 42
569645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Traceback (most recent call last):
570645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      ...
571645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UndefinedError: 'foo' is undefined
572645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
573645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __slots__ = ()
574645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
575645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        __ne__ = __bool__ = __hash__ = \
576645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        Undefined._fail_with_undefined_error
577645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
578645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
579645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# remove remaining slots attributes, after the metaclass did the magic they
580645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# are unneeded and irritating as they contain wrong data for the subclasses.
581645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdel Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__
582