Updated jinja version
This commit is contained in:
@@ -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 imap, text_type, iteritems, \
|
||||
implements_iterator, implements_to_string, string_types, PY2
|
||||
|
||||
|
||||
# these variables are exported to the template runtime
|
||||
@@ -23,9 +25,8 @@ __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
|
||||
@@ -46,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,
|
||||
@@ -63,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)
|
||||
@@ -119,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."""
|
||||
@@ -171,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
|
||||
@@ -191,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):
|
||||
@@ -205,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')
|
||||
@@ -269,11 +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
|
||||
@@ -295,6 +307,7 @@ class LoopContext(object):
|
||||
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
|
||||
@@ -313,7 +326,7 @@ class LoopContext(object):
|
||||
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.
|
||||
@@ -340,6 +353,7 @@ class LoopContext(object):
|
||||
)
|
||||
|
||||
|
||||
@implements_iterator
|
||||
class LoopContextIterator(object):
|
||||
"""The iterator for a loop context."""
|
||||
__slots__ = ('context',)
|
||||
@@ -350,7 +364,7 @@ class LoopContextIterator(object):
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
def __next__(self):
|
||||
ctx = self.context
|
||||
ctx.index0 += 1
|
||||
if ctx._after is _last_iteration:
|
||||
@@ -424,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`:
|
||||
@@ -455,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
|
||||
@@ -483,13 +498,6 @@ class Undefined(object):
|
||||
_fail_with_undefined_error
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
# 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):
|
||||
return u''
|
||||
|
||||
def __len__(self):
|
||||
@@ -506,6 +514,7 @@ class Undefined(object):
|
||||
return 'Undefined'
|
||||
|
||||
|
||||
@implements_to_string
|
||||
class DebugUndefined(Undefined):
|
||||
"""An undefined that returns the debug info when printed.
|
||||
|
||||
@@ -521,7 +530,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
|
||||
@@ -532,6 +541,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
|
||||
@@ -552,7 +562,7 @@ class StrictUndefined(Undefined):
|
||||
UndefinedError: 'foo' is undefined
|
||||
"""
|
||||
__slots__ = ()
|
||||
__iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \
|
||||
__iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
|
||||
__ne__ = __bool__ = Undefined._fail_with_undefined_error
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user