New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jinja2 fails to render template with more than 98 if/elif statements #759

Closed
dseira opened this Issue Aug 22, 2017 · 3 comments

Comments

Projects
None yet
2 participants
@dseira

dseira commented Aug 22, 2017

Expected Behavior

No errors on rendering a template.

Actual Behavior

Having the following jinja template (this.jinja2 ) with 99 if/elif statements lines; when the template is rendered it shows the following error:

IndentationError: too many levels of indentation

On the other hand, if one of the elif statements line is removed (keeping 98 elif) the template is rendered correctly without any error.

It seems that there is a hard limit on the number of if/elif statements.

Template Code

this.jinja2

{% if name == 'server0' %}
{% elif name == 'server1' %}
{% elif name == 'server2' %}
{% elif name == 'server3' %}
....
{% elif name == 'server96' %}
{% elif name == 'server97' %}
{% elif name == 'server98' %}
{% endif %}

this.py

import os
import jinja2
def render(tpl_path, context):
    path, filename = os.path.split(tpl_path)
    return jinja2.Environment(
        loader=jinja2.FileSystemLoader(path or './')
    ).get_template(filename).render(context)

print(render('./this.jinja2', {'name': 'test'}))

Full Traceback

Traceback (most recent call last):
  File "this.py", line 9, in <module>
    print(render('./this.jinja2', {'name': 'test'}))
  File "this.py", line 7, in render
    ).get_template(filename).render(context)
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 791, in get_template
    return self._load_template(name, self.make_globals(globals))
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 765, in _load_template
    template = self.loader.load(self, name, globals)
  File "/usr/lib/python2.7/dist-packages/jinja2/loaders.py", line 125, in load
    code = environment.compile(source, name, filename)
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 551, in compile
    return self._compile(source, filename)
  File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 512, in _compile
    return compile(source, filename, 'exec')
  File "./this.jinja2", line 499
    if 0: yield None
                   ^
IndentationError: too many levels of indentation

Your Environment

  • Python version: 2.7.6
  • Jinja version: 2.7.2-2
@ThiefMaster

This comment has been minimized.

Show comment
Hide comment
@ThiefMaster

ThiefMaster Aug 22, 2017

Member

This happens because elif actually compiles to else: if ...:. Not sure what's the reason for that (probably there is one though).

Either way, I would recommend you to refactor your code to not have that many elifs - that sounds rather awful to have in the first place (but at least it seems to be generated code, so maybe not that bad)

Member

ThiefMaster commented Aug 22, 2017

This happens because elif actually compiles to else: if ...:. Not sure what's the reason for that (probably there is one though).

Either way, I would recommend you to refactor your code to not have that many elifs - that sounds rather awful to have in the first place (but at least it seems to be generated code, so maybe not that bad)

ThiefMaster added a commit to ThiefMaster/jinja that referenced this issue Aug 22, 2017

Compile `elif` tag to `elif` instead of `else: if`
This avoids deep nesting in case of many `{% elif .. %}` blocks (which
would fail during execution) and also deep recursion (which may fail
during compilation)

fixes #759

ThiefMaster added a commit to ThiefMaster/jinja that referenced this issue Aug 22, 2017

Compile `elif` tag to `elif` instead of `else: if`
This avoids deep nesting in case of many `{% elif .. %}` blocks (which
would fail during execution) and also deep recursion (which may fail
during compilation)

fixes #759

ThiefMaster added a commit to ThiefMaster/jinja that referenced this issue Aug 22, 2017

Compile `elif` tag to `elif` instead of `else: if`
This avoids deep nesting in case of many `{% elif .. %}` blocks (which
would fail during execution) and also deep recursion (which may fail
during compilation)

fixes #759
@ThiefMaster

This comment has been minimized.

Show comment
Hide comment
@ThiefMaster

ThiefMaster Aug 22, 2017

Member

I might have a fix for it - see the referenced PR. However, your Jinja version is ancient. This fix would go into 2.9.5

Member

ThiefMaster commented Aug 22, 2017

I might have a fix for it - see the referenced PR. However, your Jinja version is ancient. This fix would go into 2.9.5

@dseira

This comment has been minimized.

Show comment
Hide comment
@dseira

dseira Aug 22, 2017

The thing is that I've found this bug using salt configuration management (that uses jinja templating for the states), not writing a python program directly. But of course, a state can be splitted in several files.

Thanks @ThiefMaster

dseira commented Aug 22, 2017

The thing is that I've found this bug using salt configuration management (that uses jinja templating for the states), not writing a python program directly. But of course, a state can be splitted in several files.

Thanks @ThiefMaster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment