summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--jinja2/compiler.py7
-rw-r--r--jinja2/idtracking.py3
-rw-r--r--jinja2/nodes.py2
-rw-r--r--jinja2/parser.py13
-rw-r--r--tests/test_core_tags.py9
-rw-r--r--tests/test_idtracking.py8
7 files changed, 32 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 38f4508..7e5df3d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -10,6 +10,9 @@ Version 2.9.7
(`#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
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index b2ab6fe..30826f3 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -1129,6 +1129,13 @@ class CodeGenerator(NodeVisitor):
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()
diff --git a/jinja2/idtracking.py b/jinja2/idtracking.py
index 8479b72..30e348d 100644
--- a/jinja2/idtracking.py
+++ b/jinja2/idtracking.py
@@ -222,9 +222,10 @@ class FrameSymbolVisitor(NodeVisitor):
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)
diff --git a/jinja2/nodes.py b/jinja2/nodes.py
index aa4df72..59e0765 100644
--- a/jinja2/nodes.py
+++ b/jinja2/nodes.py
@@ -314,7 +314,7 @@ class For(Stmt):
class If(Stmt):
"""If `test` is true, `body` is rendered, else `else_`."""
- fields = ('test', 'body', 'else_')
+ fields = ('test', 'body', 'elif_', 'else_')
class Macro(Stmt):
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 0bf74c9..70ab7ca 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -210,17 +210,16 @@ class Parser(object):
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
diff --git a/tests/test_core_tags.py b/tests/test_core_tags.py
index f48d8b4..19b849e 100644
--- a/tests/test_core_tags.py
+++ b/tests/test_core_tags.py
@@ -222,6 +222,15 @@ class TestIfCondition(object):
%}...{% 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() == '...'
diff --git a/tests/test_idtracking.py b/tests/test_idtracking.py
index ea01b17..29312d3 100644
--- a/tests/test_idtracking.py
+++ b/tests/test_idtracking.py
@@ -61,7 +61,7 @@ def test_complex():
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'),
@@ -155,7 +155,7 @@ def test_if_branching_stores():
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 == {
@@ -177,7 +177,7 @@ def test_if_branching_stores_undefined():
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 == {
@@ -197,7 +197,7 @@ def test_if_branching_stores_undefined():
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)