| Index: third_party/jinja2/runtime.py | 
| diff --git a/third_party/jinja2/runtime.py b/third_party/jinja2/runtime.py | 
| index a4a47a284ed4a51ec9e54ae9b439682884e1905c..7791c645afe997d45e75355fddad384f9d525d94 100644 | 
| --- a/third_party/jinja2/runtime.py | 
| +++ b/third_party/jinja2/runtime.py | 
| @@ -8,12 +8,14 @@ | 
| :copyright: (c) 2010 by the Jinja Team. | 
| :license: BSD. | 
| """ | 
| -from itertools import chain, imap | 
| +from itertools import chain | 
| from jinja2.nodes import EvalContext, _context_function_types | 
| -from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ | 
| -     concat, internalcode, next, object_type_repr | 
| +from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \ | 
| +     internalcode, object_type_repr | 
| from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ | 
| TemplateNotFound | 
| +from jinja2._compat import next, imap, text_type, iteritems, \ | 
| +     implements_iterator, implements_to_string, string_types, PY2 | 
|  | 
|  | 
| # these variables are exported to the template runtime | 
| @@ -23,13 +25,14 @@ __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', | 
| 'TemplateNotFound'] | 
|  | 
| #: the name of the function that is used to convert something into | 
| -#: a string.  2to3 will adopt that automatically and the generated | 
| -#: code can take advantage of it. | 
| -to_string = unicode | 
| +#: a string.  We can just use the text type here. | 
| +to_string = text_type | 
|  | 
| #: the identity function.  Useful for certain things in the environment | 
| identity = lambda x: x | 
|  | 
| +_last_iteration = object() | 
| + | 
|  | 
| def markup_join(seq): | 
| """Concatenation that escapes if necessary and converts to unicode.""" | 
| @@ -44,7 +47,7 @@ def markup_join(seq): | 
|  | 
| def unicode_join(seq): | 
| """Simple args to unicode conversion and concatenation.""" | 
| -    return concat(imap(unicode, seq)) | 
| +    return concat(imap(text_type, seq)) | 
|  | 
|  | 
| def new_context(environment, template_name, blocks, vars=None, | 
| @@ -61,7 +64,7 @@ def new_context(environment, template_name, blocks, vars=None, | 
| # we don't want to modify the dict passed | 
| if shared: | 
| parent = dict(parent) | 
| -        for key, value in locals.iteritems(): | 
| +        for key, value in iteritems(locals): | 
| if key[:2] == 'l_' and value is not missing: | 
| parent[key[2:]] = value | 
| return Context(environment, parent, template_name, blocks) | 
| @@ -117,7 +120,7 @@ class Context(object): | 
| # create the initial mapping of blocks.  Whenever template inheritance | 
| # takes place the runtime will update this mapping with the new blocks | 
| # from the template. | 
| -        self.blocks = dict((k, [v]) for k, v in blocks.iteritems()) | 
| +        self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) | 
|  | 
| def super(self, name, current): | 
| """Render a parent block.""" | 
| @@ -169,6 +172,16 @@ class Context(object): | 
| """ | 
| if __debug__: | 
| __traceback_hide__ = True | 
| + | 
| +        # Allow callable classes to take a context | 
| +        fn = __obj.__call__ | 
| +        for fn_type in ('contextfunction', | 
| +                        'evalcontextfunction', | 
| +                        'environmentfunction'): | 
| +            if hasattr(fn, fn_type): | 
| +                __obj = fn | 
| +                break | 
| + | 
| if isinstance(__obj, _context_function_types): | 
| if getattr(__obj, 'contextfunction', 0): | 
| args = (__self,) + args | 
| @@ -189,7 +202,7 @@ class Context(object): | 
| self.parent, True, None, locals) | 
| context.vars.update(self.vars) | 
| context.eval_ctx = self.eval_ctx | 
| -        context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems()) | 
| +        context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) | 
| return context | 
|  | 
| def _all(meth): | 
| @@ -203,7 +216,7 @@ class Context(object): | 
| items = _all('items') | 
|  | 
| # not available on python 3 | 
| -    if hasattr(dict, 'iterkeys'): | 
| +    if PY2: | 
| iterkeys = _all('iterkeys') | 
| itervalues = _all('itervalues') | 
| iteritems = _all('iteritems') | 
| @@ -267,10 +280,12 @@ class BlockReference(object): | 
| class LoopContext(object): | 
| """A loop context for dynamic iteration.""" | 
|  | 
| -    def __init__(self, iterable, recurse=None): | 
| +    def __init__(self, iterable, recurse=None, depth0=0): | 
| self._iterator = iter(iterable) | 
| self._recurse = recurse | 
| +        self._after = self._safe_next() | 
| self.index0 = -1 | 
| +        self.depth0 = depth0 | 
|  | 
| # try to get the length of the iterable early.  This must be done | 
| # here because there are some broken iterators around where there | 
| @@ -288,10 +303,11 @@ class LoopContext(object): | 
| return args[self.index0 % len(args)] | 
|  | 
| first = property(lambda x: x.index0 == 0) | 
| -    last = property(lambda x: x.index0 + 1 == x.length) | 
| +    last = property(lambda x: x._after is _last_iteration) | 
| index = property(lambda x: x.index0 + 1) | 
| revindex = property(lambda x: x.length - x.index0) | 
| revindex0 = property(lambda x: x.length - x.index) | 
| +    depth = property(lambda x: x.depth0 + 1) | 
|  | 
| def __len__(self): | 
| return self.length | 
| @@ -299,12 +315,18 @@ class LoopContext(object): | 
| def __iter__(self): | 
| return LoopContextIterator(self) | 
|  | 
| +    def _safe_next(self): | 
| +        try: | 
| +            return next(self._iterator) | 
| +        except StopIteration: | 
| +            return _last_iteration | 
| + | 
| @internalcode | 
| def loop(self, iterable): | 
| if self._recurse is None: | 
| raise TypeError('Tried to call non recursive loop.  Maybe you ' | 
| "forgot the 'recursive' modifier.") | 
| -        return self._recurse(iterable, self._recurse) | 
| +        return self._recurse(iterable, self._recurse, self.depth0 + 1) | 
|  | 
| # a nifty trick to enhance the error message if someone tried to call | 
| # the the loop without or with too many arguments. | 
| @@ -331,6 +353,7 @@ class LoopContext(object): | 
| ) | 
|  | 
|  | 
| +@implements_iterator | 
| class LoopContextIterator(object): | 
| """The iterator for a loop context.""" | 
| __slots__ = ('context',) | 
| @@ -341,10 +364,14 @@ class LoopContextIterator(object): | 
| def __iter__(self): | 
| return self | 
|  | 
| -    def next(self): | 
| +    def __next__(self): | 
| ctx = self.context | 
| ctx.index0 += 1 | 
| -        return next(ctx._iterator), ctx | 
| +        if ctx._after is _last_iteration: | 
| +            raise StopIteration() | 
| +        next_elem = ctx._after | 
| +        ctx._after = ctx._safe_next() | 
| +        return next_elem, ctx | 
|  | 
|  | 
| class Macro(object): | 
| @@ -411,6 +438,7 @@ class Macro(object): | 
| ) | 
|  | 
|  | 
| +@implements_to_string | 
| class Undefined(object): | 
| """The default undefined type.  This undefined type can be printed and | 
| iterated over, but every other access will raise an :exc:`UndefinedError`: | 
| @@ -442,7 +470,7 @@ class Undefined(object): | 
| if self._undefined_hint is None: | 
| if self._undefined_obj is missing: | 
| hint = '%r is undefined' % self._undefined_name | 
| -            elif not isinstance(self._undefined_name, basestring): | 
| +            elif not isinstance(self._undefined_name, string_types): | 
| hint = '%s has no element %r' % ( | 
| object_type_repr(self._undefined_obj), | 
| self._undefined_name | 
| @@ -469,14 +497,16 @@ class Undefined(object): | 
| __float__ = __complex__ = __pow__ = __rpow__ = \ | 
| _fail_with_undefined_error | 
|  | 
| -    def __str__(self): | 
| -        return unicode(self).encode('utf-8') | 
| +    def __eq__(self, other): | 
| +        return type(self) is type(other) | 
| + | 
| +    def __ne__(self, other): | 
| +        return not self.__eq__(other) | 
| + | 
| +    def __hash__(self): | 
| +        return id(type(self)) | 
|  | 
| -    # unicode goes after __str__ because we configured 2to3 to rename | 
| -    # __unicode__ to __str__.  because the 2to3 tree is not designed to | 
| -    # remove nodes from it, we leave the above __str__ around and let | 
| -    # it override at runtime. | 
| -    def __unicode__(self): | 
| +    def __str__(self): | 
| return u'' | 
|  | 
| def __len__(self): | 
| @@ -493,6 +523,7 @@ class Undefined(object): | 
| return 'Undefined' | 
|  | 
|  | 
| +@implements_to_string | 
| class DebugUndefined(Undefined): | 
| """An undefined that returns the debug info when printed. | 
|  | 
| @@ -508,7 +539,7 @@ class DebugUndefined(Undefined): | 
| """ | 
| __slots__ = () | 
|  | 
| -    def __unicode__(self): | 
| +    def __str__(self): | 
| if self._undefined_hint is None: | 
| if self._undefined_obj is missing: | 
| return u'{{ %s }}' % self._undefined_name | 
| @@ -519,6 +550,7 @@ class DebugUndefined(Undefined): | 
| return u'{{ undefined value printed: %s }}' % self._undefined_hint | 
|  | 
|  | 
| +@implements_to_string | 
| class StrictUndefined(Undefined): | 
| """An undefined that barks on print and iteration as well as boolean | 
| tests and all kinds of comparisons.  In other words: you can do nothing | 
| @@ -539,8 +571,9 @@ class StrictUndefined(Undefined): | 
| UndefinedError: 'foo' is undefined | 
| """ | 
| __slots__ = () | 
| -    __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \ | 
| -        __ne__ = __bool__ = Undefined._fail_with_undefined_error | 
| +    __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ | 
| +        __ne__ = __bool__ = __hash__ = \ | 
| +        Undefined._fail_with_undefined_error | 
|  | 
|  | 
| # remove remaining slots attributes, after the metaclass did the magic they | 
|  |