is not consistenly implementable.
--HG--
branch : trunk
Jinja2 Changelog
================
-Version 2.3
------------
-(codename Gnok, release date to be selected.)
+Version 2.2.2
+-------------
+(bugfix release, release date to be selected.)
- fixes issue with code generator that causes unbound variables
to be generated if set was used in if-blocks.
-- added a deprecation warning for a variable assignment, scope bug
- that exists since 2.0, code could depend on. See :ref:`jinja-scoping-bug`
- for more information on this problem.
Version 2.2.1
-------------
Python 2.3 support you either have to use `Jinja 1`_ or other templating
engines that still support 2.3.
-.. _jinja-scoping-bug:
-
-Scoping Bug in Jinja2
----------------------
+My Macros are overriden by something
+------------------------------------
-Jinja2 currently has a scoping bug that causes confusing behavior. If you
-have a layout template that defines a macro, and a child template that
-does the same thing, it will see the macro from the layout template:
+In some situations the Jinja scoping appears arbitrary:
layout.tmpl:
{% macro foo() %}CHILD{% endmacro %}
{% block body %}{{ foo() }}{% endblock %}
-This will print ``LAYOUT`` in Jinja2 versions older than 2.5. Starting
-with Jinja 2.2.2, there will however be a deprecation warning for this
-behavior. Starting with Jinja 2.5, this behavior will change so that
-``CHILD`` is printed instead.
-
-The reason why it was not changed right away is that some templates could
-depend on macros or variables defined in the layout template to be
-available in a child template. This however was undocumented behavior and
-is considered a bug.
-
-If you depend on this behavior, move your macros into a different file and
-import it into the layout and child template.
+This will print ``LAYOUT`` in Jinja2. This is a side effect of having
+the parent template evaluated after the child one. This allows child
+templates passing information to the parent template. To avoid this
+issue rename the macro or variable in the parent template to have an
+uncommon prefix.
.. _Jinja 1: http://jinja.pocoo.org/1/
self.name = name
self.filename = filename
self.stream = stream
+ self.created_block_context = False
# aliases for imports
self.import_aliases = {}
# overhead by just not processing any inheritance code.
have_extends = node.find(nodes.Extends) is not None
- # are there any block tags? If yes, we need a copy of the scope.
- have_blocks = node.find(nodes.Block) is not None
-
# find all blocks
for block in node.find_all(nodes.Block):
if block.name in self.blocks:
self.indent()
if have_extends:
self.writeline('parent_template = None')
- if have_blocks:
- self.writeline('block_context = context._block()')
if 'self' in find_undeclared(node.body, ('self',)):
frame.identifiers.add_special('self')
self.writeline('l_self = TemplateReference(context)')
if 'self' in undeclared:
block_frame.identifiers.add_special('self')
self.writeline('l_self = TemplateReference(context)')
- if block.find(nodes.Block) is not None:
- self.writeline('block_context = context._block(%r)' % name)
if 'super' in undeclared:
block_frame.identifiers.add_special('super')
self.writeline('l_super = context.super(%r, '
self.writeline('if parent_template is None:')
self.indent()
level += 1
- if node.scoped:
- context = 'block_context.derived(locals())'
- else:
- context = 'block_context'
+ context = node.scoped and 'context.derived(locals())' or 'context'
self.writeline('for event in context.blocks[%r][0](%s):' % (
node.name, context), node)
self.indent()
def __init__(self, environment, parent, name, blocks):
self.parent = parent
- self.vars = vars = {}
+ self.vars = {}
self.environment = environment
self.exported_vars = set()
self.name = name
context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems())
return context
- def _block(self, block=None):
- """Creates a context that is used for block execution. Currently this
- returns a special `_BlockContext` that warns about changed behavior.
- In Jinja 2.5, this will instead just return a new context with the same
- resolve behavior. Do not call from anywhere but the generated code!
-
- :private:
- """
- return _BlockContext(self, block)
-
def _all(meth):
proxy = lambda self: getattr(self.get_all(), meth)()
proxy.__doc__ = getattr(dict, meth).__doc__
)
-class _BlockContext(Context):
- """Implements a deprecation warning for the changed block assignments."""
- __slots__ = ('real_context', 'block_name')
-
- def __init__(self, real_context, block_name):
- super(_BlockContext, self).__init__(real_context.environment,
- real_context.parent,
- real_context.name, {})
- self.vars = dict(real_context.vars)
- self.exported_vars = set(real_context.exported_vars)
- self.blocks = real_context.blocks
- self.real_context = real_context
- self.block_name = block_name
-
- def resolve(self, key):
- self_rv = super(_BlockContext, self).resolve(key)
- base_rv = self.real_context.resolve(key)
- if self_rv != base_rv and not isinstance(base_rv, Undefined):
- from warnings import warn
- if self.block_name is not None:
- detail = 'accessing %r from inside block %r' \
- % (key, self.block_name)
- else:
- detail = 'accessing %r toplevel' % key
- detail += ', in template %s' % self.name
- warn(DeprecationWarning('variables set in a base template '
- 'will no longer leak into the child '
- 'context in future versions. Happened '
- 'when ' + detail))
- return base_rv
- return self_rv
-
-
# register the context as mapping if possible
try:
from collections import Mapping
setup(
name='Jinja2',
- version='2.3',
+ version='2.2.2',
url='http://jinja.pocoo.org/',
license='BSD',
author='Armin Ronacher',
assert tmpl.render(b=True) == '42'
-def test_local_macros_first():
- raise SkipTest('Behavior will change in 2.3')
- env = Environment(loader=DictLoader({
- 'layout.html': ('{% macro foo() %}LAYOUT{% endmacro %}'
- '{% block body %}{% endblock %}'),
- 'child.html': ('{% extends "layout.html" %}'
- '{% macro foo() %}CHILD{% endmacro %}'
- '{% block body %}{{ foo() }}{% endblock %}')
- }))
- assert env.get_template('child.html').render() == 'CHILD'
-
-
def test_stacked_locals_scoping_bug():
env = Environment(line_statement_prefix='#')
t = env.from_string('''\