tests in one expression without extra parentheses. In particular you can
now write ``foo is divisibleby 2 or foo is divisibleby 3``
as you would expect.
+- Greatly changed the scoping system to be more consistent with what template
+ designers and developers expect. There is now no more magic difference
+ between the different include and import constructs. Context is now always
+ propagated the same way. The only remaining differences is the defaults
+ for `with context` and `without context`.
Version 2.8.2
-------------
if node.with_context:
loop = self.environment.is_async and 'async for' or 'for'
self.writeline('%s event in template.root_render_func('
- 'template.new_context(context.parent, True, '
+ 'template.new_context(context.get_all(), True, '
'%s)):' % (loop, self.dump_local_context(frame)))
elif self.environment.is_async:
self.writeline('for event in (await '
self.visit(node.template, frame)
self.write(', %r).' % self.name)
if node.with_context:
- self.write('make_module%s(context.parent, True, %s)'
+ self.write('make_module%s(context.get_all(), True, %s)'
% (self.environment.is_async and '_async' or '',
self.dump_local_context(frame)))
elif self.environment.is_async:
self.visit(node.template, frame)
self.write(', %r).' % self.name)
if node.with_context:
- self.write('make_module%s(context.parent, True, %s)'
+ self.write('make_module%s(context.get_all(), True, %s)'
% (self.environment.is_async and '_async' or '',
self.dump_local_context(frame)))
elif self.environment.is_async:
return dict((k, self.vars[k]) for k in self.exported_vars)
def get_all(self):
- """Return a copy of the complete context as dict including the
- exported variables.
+ """Return the complete context as dict including the exported
+ variables. For optimizations reasons this might not return an
+ actual copy so be careful with using it.
"""
+ if not self.vars:
+ return self.parent
+ if not self.parent:
+ return self.vars
return dict(self.parent, **self.vars)
@internalcode
''')
assert list(map(int, tmpl.render().split())) == \
[3, 2, 1, 5, 4, 3, 7, 6, 5]
+
+ def test_scopes_and_blocks(self):
+ env = Environment(loader=DictLoader({
+ 'a.html': '''
+ {%- set foo = 'bar' -%}
+ {% include 'x.html' -%}
+ ''',
+ 'b.html': '''
+ {%- set foo = 'bar' -%}
+ {% block test %}{% include 'x.html' %}{% endblock -%}
+ ''',
+ 'c.html': '''
+ {%- set foo = 'bar' -%}
+ {% block test %}{% set foo = foo
+ %}{% include 'x.html' %}{% endblock -%}
+ ''',
+ 'x.html': '''{{ foo }}|{{ test }}'''
+ }))
+
+ a = env.get_template('a.html')
+ b = env.get_template('b.html')
+ c = env.get_template('c.html')
+
+ assert a.render(test='x').strip() == 'bar|x'
+ assert b.render(test='x').strip() == 'bar|x'
+ assert c.render(test='x').strip() == 'bar|x'
+
+ def test_scopes_and_include(self):
+ env = Environment(loader=DictLoader({
+ 'include.html': '{{ var }}',
+ 'base.html': '{% include "include.html" %}',
+ 'child.html': '{% extends "base.html" %}{% set var = 42 %}',
+ }))
+ t = env.get_template('child.html')
+ assert t.render() == '42'