(`#718`_)
- Resolved a bug where getting debug locals for tracebacks could
modify template context.
+- Fixed a bug where having many `{% elif ... %}` blocks resulted in a
+ "too many levels of indentation" error. These blocks now compile to
+ native `elif ..:` instead of `else: if ..:` (#759)
.. _#718: https://github.com/pallets/jinja/pull/718
self.indent()
self.blockvisit(node.body, if_frame)
self.outdent()
+ for elif_ in node.elif_:
+ self.writeline('elif ', elif_)
+ self.visit(elif_.test, if_frame)
+ self.write(':')
+ self.indent()
+ self.blockvisit(elif_.body, if_frame)
+ self.outdent()
if node.else_:
self.writeline('else:')
self.indent()
return rv
body_symbols = inner_visit(node.body)
+ elif_symbols = inner_visit(node.elif_)
else_symbols = inner_visit(node.else_ or ())
- self.symbols.branch_update([body_symbols, else_symbols])
+ self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
def visit_Macro(self, node, **kwargs):
self.symbols.store(node.name)
class If(Stmt):
"""If `test` is true, `body` is rendered, else `else_`."""
- fields = ('test', 'body', 'else_')
+ fields = ('test', 'body', 'elif_', 'else_')
class Macro(Stmt):
node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(('name:elif', 'name:else',
'name:endif'))
+ node.elif_ = []
+ node.else_ = []
token = next(self.stream)
if token.test('name:elif'):
- new_node = nodes.If(lineno=self.stream.current.lineno)
- node.else_ = [new_node]
- node = new_node
+ node = nodes.If(lineno=self.stream.current.lineno)
+ result.elif_.append(node)
continue
elif token.test('name:else'):
- node.else_ = self.parse_statements(('name:endif',),
- drop_needle=True)
- else:
- node.else_ = []
+ result.else_ = self.parse_statements(('name:endif',),
+ drop_needle=True)
break
return result
%}...{% else %}XXX{% endif %}''')
assert tmpl.render() == '...'
+ def test_elif_deep(self, env):
+ elifs = '\n'.join('{{% elif a == {0} %}}{0}'.format(i)
+ for i in range(1, 1000))
+ tmpl = env.from_string('{{% if a == 0 %}}0{0}{{% else %}}x{{% endif %}}'
+ .format(elifs))
+ for x in (0, 10, 999):
+ assert tmpl.render(a=x).strip() == str(x)
+ assert tmpl.render(a=1000).strip() == 'x'
+
def test_else(self, env):
tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
assert tmpl.render() == '...'
nodes.Output([
nodes.Name('title_upper', 'load'),
nodes.Call(nodes.Name('render_title', 'load'), [
- nodes.Const('Aha')], [], None, None)])], [])])])
+ nodes.Const('Aha')], [], None, None)])], [], [])])])
for_loop = nodes.For(
nodes.Name('item', 'store'),
tmpl = nodes.Template([
nodes.If(nodes.Name('expression', 'load'), [
nodes.Assign(nodes.Name('variable', 'store'),
- nodes.Const(42))], [])])
+ nodes.Const(42))], [], [])])
sym = symbols_for_node(tmpl)
assert sym.refs == {
nodes.Assign(nodes.Name('variable', 'store'), nodes.Const(23)),
nodes.If(nodes.Name('expression', 'load'), [
nodes.Assign(nodes.Name('variable', 'store'),
- nodes.Const(42))], [])])
+ nodes.Const(42))], [], [])])
sym = symbols_for_node(tmpl)
assert sym.refs == {
def test_if_branching_multi_scope():
for_loop = nodes.For(nodes.Name('item', 'store'), nodes.Name('seq', 'load'), [
nodes.If(nodes.Name('expression', 'load'), [
- nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], []),
+ nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], [], []),
nodes.Include(nodes.Const('helper.html'), True, False)
], [], None, False)