Updated jinja version
This commit is contained in:
@@ -8,14 +8,16 @@
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from cStringIO import StringIO
|
||||
from itertools import chain
|
||||
from copy import deepcopy
|
||||
from keyword import iskeyword as is_python_keyword
|
||||
from jinja2 import nodes
|
||||
from jinja2.nodes import EvalContext
|
||||
from jinja2.visitor import NodeVisitor
|
||||
from jinja2.exceptions import TemplateAssertionError
|
||||
from jinja2.utils import Markup, concat, escape, is_python_keyword, next
|
||||
from jinja2.utils import Markup, concat, escape
|
||||
from jinja2._compat import range_type, text_type, string_types, \
|
||||
iteritems, NativeStringIO, imap
|
||||
|
||||
|
||||
operators = {
|
||||
@@ -29,14 +31,6 @@ operators = {
|
||||
'notin': 'not in'
|
||||
}
|
||||
|
||||
try:
|
||||
exec '(0 if 0 else 0)'
|
||||
except SyntaxError:
|
||||
have_condexpr = False
|
||||
else:
|
||||
have_condexpr = True
|
||||
|
||||
|
||||
# what method to iterate over items do we want to use for dict iteration
|
||||
# in generated code? on 2.x let's go with iteritems, on 3.x with items
|
||||
if hasattr(dict, 'iteritems'):
|
||||
@@ -51,7 +45,11 @@ def unoptimize_before_dead_code():
|
||||
def f():
|
||||
if 0: dummy(x)
|
||||
return f
|
||||
unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure)
|
||||
|
||||
# The getattr is necessary for pypy which does not set this attribute if
|
||||
# no closure is on the function
|
||||
unoptimize_before_dead_code = bool(
|
||||
getattr(unoptimize_before_dead_code(), '__closure__', None))
|
||||
|
||||
|
||||
def generate(node, environment, name, filename, stream=None,
|
||||
@@ -69,8 +67,8 @@ def has_safe_repr(value):
|
||||
"""Does the node have a safe representation?"""
|
||||
if value is None or value is NotImplemented or value is Ellipsis:
|
||||
return True
|
||||
if isinstance(value, (bool, int, long, float, complex, basestring,
|
||||
xrange, Markup)):
|
||||
if isinstance(value, (bool, int, float, complex, range_type,
|
||||
Markup) + string_types):
|
||||
return True
|
||||
if isinstance(value, (tuple, list, set, frozenset)):
|
||||
for item in value:
|
||||
@@ -78,7 +76,7 @@ def has_safe_repr(value):
|
||||
return False
|
||||
return True
|
||||
elif isinstance(value, dict):
|
||||
for key, value in value.iteritems():
|
||||
for key, value in iteritems(value):
|
||||
if not has_safe_repr(key):
|
||||
return False
|
||||
if not has_safe_repr(value):
|
||||
@@ -368,7 +366,7 @@ class CodeGenerator(NodeVisitor):
|
||||
def __init__(self, environment, name, filename, stream=None,
|
||||
defer_init=False):
|
||||
if stream is None:
|
||||
stream = StringIO()
|
||||
stream = NativeStringIO()
|
||||
self.environment = environment
|
||||
self.name = name
|
||||
self.filename = filename
|
||||
@@ -542,7 +540,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.write(', ')
|
||||
self.visit(kwarg, frame)
|
||||
if extra_kwargs is not None:
|
||||
for key, value in extra_kwargs.iteritems():
|
||||
for key, value in iteritems(extra_kwargs):
|
||||
self.write(', %s=%s' % (key, value))
|
||||
if node.dyn_args:
|
||||
self.write(', *')
|
||||
@@ -558,7 +556,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.visit(kwarg.value, frame)
|
||||
self.write(', ')
|
||||
if extra_kwargs is not None:
|
||||
for key, value in extra_kwargs.iteritems():
|
||||
for key, value in iteritems(extra_kwargs):
|
||||
self.write('%r: %s, ' % (key, value))
|
||||
if node.dyn_kwargs is not None:
|
||||
self.write('}, **')
|
||||
@@ -625,7 +623,7 @@ class CodeGenerator(NodeVisitor):
|
||||
|
||||
def pop_scope(self, aliases, frame):
|
||||
"""Restore all aliases and delete unused variables."""
|
||||
for name, alias in aliases.iteritems():
|
||||
for name, alias in iteritems(aliases):
|
||||
self.writeline('l_%s = %s' % (name, alias))
|
||||
to_delete = set()
|
||||
for name in frame.identifiers.declared_locally:
|
||||
@@ -663,16 +661,16 @@ class CodeGenerator(NodeVisitor):
|
||||
# it without aliasing all the variables.
|
||||
# this could be fixed in Python 3 where we have the nonlocal
|
||||
# keyword or if we switch to bytecode generation
|
||||
overriden_closure_vars = (
|
||||
overridden_closure_vars = (
|
||||
func_frame.identifiers.undeclared &
|
||||
func_frame.identifiers.declared &
|
||||
(func_frame.identifiers.declared_locally |
|
||||
func_frame.identifiers.declared_parameter)
|
||||
)
|
||||
if overriden_closure_vars:
|
||||
if overridden_closure_vars:
|
||||
self.fail('It\'s not possible to set and access variables '
|
||||
'derived from an outer scope! (affects: %s)' %
|
||||
', '.join(sorted(overriden_closure_vars)), node.lineno)
|
||||
', '.join(sorted(overridden_closure_vars)), node.lineno)
|
||||
|
||||
# remove variables from a closure from the frame's undeclared
|
||||
# identifiers.
|
||||
@@ -827,7 +825,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.outdent(2 + (not self.has_known_extends))
|
||||
|
||||
# at this point we now have the blocks collected and can visit them too.
|
||||
for name, block in self.blocks.iteritems():
|
||||
for name, block in iteritems(self.blocks):
|
||||
block_frame = Frame(eval_ctx)
|
||||
block_frame.inspect(block.body)
|
||||
block_frame.block = name
|
||||
@@ -894,12 +892,13 @@ class CodeGenerator(NodeVisitor):
|
||||
self.indent()
|
||||
self.writeline('raise TemplateRuntimeError(%r)' %
|
||||
'extended multiple times')
|
||||
self.outdent()
|
||||
|
||||
# if we have a known extends already we don't need that code here
|
||||
# as we know that the template execution will end here.
|
||||
if self.has_known_extends:
|
||||
raise CompilerExit()
|
||||
else:
|
||||
self.outdent()
|
||||
|
||||
self.writeline('parent_template = environment.get_template(', node)
|
||||
self.visit(node.template, frame)
|
||||
@@ -930,7 +929,7 @@ class CodeGenerator(NodeVisitor):
|
||||
|
||||
func_name = 'get_or_select_template'
|
||||
if isinstance(node.template, nodes.Const):
|
||||
if isinstance(node.template.value, basestring):
|
||||
if isinstance(node.template.value, string_types):
|
||||
func_name = 'get_template'
|
||||
elif isinstance(node.template.value, (tuple, list)):
|
||||
func_name = 'select_template'
|
||||
@@ -950,9 +949,16 @@ class CodeGenerator(NodeVisitor):
|
||||
self.indent()
|
||||
|
||||
if node.with_context:
|
||||
self.writeline('include_context = template.new_context('
|
||||
'context.parent, True, locals())')
|
||||
self.writeline('for name, context_blocks in context.'
|
||||
'blocks.%s():' % dict_item_iter)
|
||||
self.indent()
|
||||
self.writeline('include_context.blocks.setdefault('
|
||||
'name, [])[0:0] = context_blocks')
|
||||
self.outdent()
|
||||
self.writeline('for event in template.root_render_func('
|
||||
'template.new_context(context.parent, True, '
|
||||
'locals())):')
|
||||
'include_context):')
|
||||
else:
|
||||
self.writeline('for event in template.module._body_stream:')
|
||||
|
||||
@@ -1032,7 +1038,7 @@ class CodeGenerator(NodeVisitor):
|
||||
discarded_names[0])
|
||||
else:
|
||||
self.writeline('context.exported_vars.difference_'
|
||||
'update((%s))' % ', '.join(map(repr, discarded_names)))
|
||||
'update((%s))' % ', '.join(imap(repr, discarded_names)))
|
||||
|
||||
def visit_For(self, node, frame):
|
||||
# when calculating the nodes for the inner frame we have to exclude
|
||||
@@ -1060,7 +1066,7 @@ class CodeGenerator(NodeVisitor):
|
||||
|
||||
# otherwise we set up a buffer and add a function def
|
||||
else:
|
||||
self.writeline('def loop(reciter, loop_render_func):', node)
|
||||
self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
|
||||
self.indent()
|
||||
self.buffer(loop_frame)
|
||||
aliases = {}
|
||||
@@ -1068,6 +1074,7 @@ class CodeGenerator(NodeVisitor):
|
||||
# make sure the loop variable is a special one and raise a template
|
||||
# assertion error if a loop tries to write to loop
|
||||
if extended_loop:
|
||||
self.writeline('l_loop = missing')
|
||||
loop_frame.identifiers.add_special('loop')
|
||||
for name in node.find_all(nodes.Name):
|
||||
if name.ctx == 'store' and name.name == 'loop':
|
||||
@@ -1118,7 +1125,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.visit(node.iter, loop_frame)
|
||||
|
||||
if node.recursive:
|
||||
self.write(', recurse=loop_render_func):')
|
||||
self.write(', loop_render_func, depth):')
|
||||
else:
|
||||
self.write(extended_loop and '):' or ':')
|
||||
|
||||
@@ -1216,9 +1223,9 @@ class CodeGenerator(NodeVisitor):
|
||||
return
|
||||
|
||||
if self.environment.finalize:
|
||||
finalize = lambda x: unicode(self.environment.finalize(x))
|
||||
finalize = lambda x: text_type(self.environment.finalize(x))
|
||||
else:
|
||||
finalize = unicode
|
||||
finalize = text_type
|
||||
|
||||
# if we are inside a frame that requires output checking, we do so
|
||||
outdent_later = False
|
||||
@@ -1367,7 +1374,7 @@ class CodeGenerator(NodeVisitor):
|
||||
public_names[0])
|
||||
else:
|
||||
self.writeline('context.exported_vars.update((%s))' %
|
||||
', '.join(map(repr, public_names)))
|
||||
', '.join(imap(repr, public_names)))
|
||||
|
||||
# -- Expression Visitors
|
||||
|
||||
@@ -1555,22 +1562,13 @@ class CodeGenerator(NodeVisitor):
|
||||
'expression on %s evaluated to false and '
|
||||
'no else section was defined.' % self.position(node)))
|
||||
|
||||
if not have_condexpr:
|
||||
self.write('((')
|
||||
self.visit(node.test, frame)
|
||||
self.write(') and (')
|
||||
self.visit(node.expr1, frame)
|
||||
self.write(',) or (')
|
||||
write_expr2()
|
||||
self.write(',))[0]')
|
||||
else:
|
||||
self.write('(')
|
||||
self.visit(node.expr1, frame)
|
||||
self.write(' if ')
|
||||
self.visit(node.test, frame)
|
||||
self.write(' else ')
|
||||
write_expr2()
|
||||
self.write(')')
|
||||
self.write('(')
|
||||
self.visit(node.expr1, frame)
|
||||
self.write(' if ')
|
||||
self.visit(node.test, frame)
|
||||
self.write(' else ')
|
||||
write_expr2()
|
||||
self.write(')')
|
||||
|
||||
def visit_Call(self, node, frame, forward_caller=False):
|
||||
if self.environment.sandboxed:
|
||||
|
||||
Reference in New Issue
Block a user