From 7887a8c63c482d99efcb9a2b69eefd2d70afd327 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 8 Feb 2009 19:11:44 +0100 Subject: [PATCH] Made it possible to refer to names from outer scopes in included templates that were unused in the callers frame (#327). --HG-- branch : trunk --- CHANGES | 2 ++ jinja2/compiler.py | 14 ++++++++++++++ tests/test_imports.py | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index edbdb0e..0f65730 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,8 @@ Version 2.2 - Fixed a bug that caused syntax errors when defining macros or using the `{% call %}` tag inside loops. - Fixed a bug in the parser that made ``{{ foo[1, 2] }}`` impossible. +- Made it possible to refer to names from outer scopes in included templates + that were unused in the callers frame (#327) Version 2.1.1 ------------- diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 8d605c7..b6bf2eb 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -520,6 +520,16 @@ class CodeGenerator(NodeVisitor): self.writeline('%s = environment.%s[%r]' % (mapping[name], dependency, name)) + def unoptimize_scope(self, frame): + """Disable Python optimizations for the frame.""" + # XXX: this is not that nice but it has no real overhead. It + # mainly works because python finds the locals before dead code + # is removed. If that breaks we have to add a dummy function + # that just accepts the arguments and does nothing. + if frame.identifiers.declared: + self.writeline('if 0: dummy(%s)' % ', '.join( + 'l_' + name for name in frame.identifiers.declared)) + def push_scope(self, frame, extra_vars=()): """This function returns all the shadowed variables in a dict in the form name: alias and will write the required assignments @@ -821,6 +831,8 @@ class CodeGenerator(NodeVisitor): def visit_Include(self, node, frame): """Handles includes.""" + if node.with_context: + self.unoptimize_scope(frame) if node.ignore_missing: self.writeline('try:') self.indent() @@ -852,6 +864,8 @@ class CodeGenerator(NodeVisitor): def visit_Import(self, node, frame): """Visit regular imports.""" + if node.with_context: + self.unoptimize_scope(frame) self.writeline('l_%s = ' % node.target, node) if frame.toplevel: self.write('context.vars[%r] = ' % node.target) diff --git a/tests/test_imports.py b/tests/test_imports.py index a0bb032..f5b227f 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -13,7 +13,8 @@ from jinja2.exceptions import TemplateNotFound test_env = Environment(loader=DictLoader(dict( module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}', - header='[{{ foo }}|{{ 23 }}]' + header='[{{ foo }}|{{ 23 }}]', + o_printer='({{ o }})' ))) test_env.globals['bar'] = 23 @@ -80,3 +81,16 @@ def test_exports(): assert not hasattr(m, '__missing') assert m.variable == 42 assert not hasattr(m, 'notthere') + + +def test_unoptimized_scopes(): + t = test_env.from_string(""" + {% macro outer(o) %} + {% macro inner() %} + {% include "o_printer" %} + {% endmacro %} + {{ inner() }} + {% endmacro %} + {{ outer("FOO") }} + """) + assert t.render().strip() == '(FOO)' -- 2.26.2