| Index: third_party/jinja2/compiler.py
|
| diff --git a/third_party/jinja2/compiler.py b/third_party/jinja2/compiler.py
|
| index b21cb3865db61c08c321117b8cf6c8a08fa44f15..75a60b8d2d6b326d6248b64a0b74538316d4f82c 100644
|
| --- a/third_party/jinja2/compiler.py
|
| +++ b/third_party/jinja2/compiler.py
|
| @@ -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, next, 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'
|
| @@ -1032,7 +1031,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 +1059,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 +1067,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 +1118,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 +1216,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 +1367,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 +1555,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:
|
|
|