summaryrefslogtreecommitdiffstats
path: root/module/lib/jinja2/compiler.py
diff options
context:
space:
mode:
Diffstat (limited to 'module/lib/jinja2/compiler.py')
-rw-r--r--module/lib/jinja2/compiler.py138
1 files changed, 69 insertions, 69 deletions
diff --git a/module/lib/jinja2/compiler.py b/module/lib/jinja2/compiler.py
index 57641596a..75a60b8d2 100644
--- a/module/lib/jinja2/compiler.py
+++ b/module/lib/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, NodeTransformer
+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):
@@ -127,12 +125,10 @@ class Identifiers(object):
self.undeclared.discard(name)
self.declared.add(name)
- def is_declared(self, name, local_only=False):
+ def is_declared(self, name):
"""Check if a name is declared in this or an outer scope."""
if name in self.declared_locally or name in self.declared_parameter:
return True
- if local_only:
- return False
return name in self.declared
def copy(self):
@@ -193,12 +189,12 @@ class Frame(object):
rv.identifiers.__dict__.update(self.identifiers.__dict__)
return rv
- def inspect(self, nodes, hard_scope=False):
+ def inspect(self, nodes):
"""Walk the node and check for identifiers. If the scope is hard (eg:
enforce on a python level) overrides from outer scopes are tracked
differently.
"""
- visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
+ visitor = FrameIdentifierVisitor(self.identifiers)
for node in nodes:
visitor.visit(node)
@@ -275,9 +271,8 @@ class UndeclaredNameVisitor(NodeVisitor):
class FrameIdentifierVisitor(NodeVisitor):
"""A visitor for `Frame.inspect`."""
- def __init__(self, identifiers, hard_scope):
+ def __init__(self, identifiers):
self.identifiers = identifiers
- self.hard_scope = hard_scope
def visit_Name(self, node):
"""All assignments to names go through this function."""
@@ -286,7 +281,7 @@ class FrameIdentifierVisitor(NodeVisitor):
elif node.ctx == 'param':
self.identifiers.declared_parameter.add(node.name)
elif node.ctx == 'load' and not \
- self.identifiers.is_declared(node.name, self.hard_scope):
+ self.identifiers.is_declared(node.name):
self.identifiers.undeclared.add(node.name)
def visit_If(self, node):
@@ -371,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
@@ -545,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(', *')
@@ -561,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('}, **')
@@ -628,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:
@@ -658,7 +653,7 @@ class CodeGenerator(NodeVisitor):
children = node.iter_child_nodes()
children = list(children)
func_frame = frame.inner()
- func_frame.inspect(children, hard_scope=True)
+ func_frame.inspect(children)
# variables that are undeclared (accessed before declaration) and
# declared locally *and* part of an outside scope raise a template
@@ -666,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.
@@ -830,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
@@ -897,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)
@@ -933,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'
@@ -1035,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
@@ -1063,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 = {}
@@ -1071,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':
@@ -1089,7 +1086,7 @@ class CodeGenerator(NodeVisitor):
node.iter_child_nodes(only=('else_', 'test')), ('loop',)):
self.writeline("l_loop = environment.undefined(%r, name='loop')" %
("'loop' is undefined. the filter section of a loop as well "
- "as the else block doesn't have access to the special 'loop'"
+ "as the else block don't have access to the special 'loop'"
" variable of the current loop. Because there is no parent "
"loop it's undefined. Happened in loop on %s" %
self.position(node)))
@@ -1121,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 ':')
@@ -1219,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
@@ -1249,7 +1246,7 @@ class CodeGenerator(NodeVisitor):
else:
const = escape(const)
const = finalize(const)
- except:
+ except Exception:
# if something goes wrong here we evaluate the node
# at runtime for easier debugging
body.append(child)
@@ -1370,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
@@ -1421,19 +1418,31 @@ class CodeGenerator(NodeVisitor):
self.visit(item.value, frame)
self.write('}')
- def binop(operator):
+ def binop(operator, interceptable=True):
def visitor(self, node, frame):
- self.write('(')
- self.visit(node.left, frame)
- self.write(' %s ' % operator)
- self.visit(node.right, frame)
+ if self.environment.sandboxed and \
+ operator in self.environment.intercepted_binops:
+ self.write('environment.call_binop(context, %r, ' % operator)
+ self.visit(node.left, frame)
+ self.write(', ')
+ self.visit(node.right, frame)
+ else:
+ self.write('(')
+ self.visit(node.left, frame)
+ self.write(' %s ' % operator)
+ self.visit(node.right, frame)
self.write(')')
return visitor
- def uaop(operator):
+ def uaop(operator, interceptable=True):
def visitor(self, node, frame):
- self.write('(' + operator)
- self.visit(node.node, frame)
+ if self.environment.sandboxed and \
+ operator in self.environment.intercepted_unops:
+ self.write('environment.call_unop(context, %r, ' % operator)
+ self.visit(node.node, frame)
+ else:
+ self.write('(' + operator)
+ self.visit(node.node, frame)
self.write(')')
return visitor
@@ -1444,11 +1453,11 @@ class CodeGenerator(NodeVisitor):
visit_FloorDiv = binop('//')
visit_Pow = binop('**')
visit_Mod = binop('%')
- visit_And = binop('and')
- visit_Or = binop('or')
+ visit_And = binop('and', interceptable=False)
+ visit_Or = binop('or', interceptable=False)
visit_Pos = uaop('+')
visit_Neg = uaop('-')
- visit_Not = uaop('not ')
+ visit_Not = uaop('not ', interceptable=False)
del binop, uaop
def visit_Concat(self, node, frame):
@@ -1546,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: