Skip to content
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

Block assignment with filter and autoescape #1199

Open
juriad opened this issue Apr 24, 2020 · 1 comment
Open

Block assignment with filter and autoescape #1199

juriad opened this issue Apr 24, 2020 · 1 comment

Comments

@juriad
Copy link

juriad commented Apr 24, 2020

In the following code the result depends on atoescaping even though there are no characters which need escaping. Am I understanding atoescaping incorrectly?
If you set autoescape=False it works as expected.

There is a workaround (inspired by #486). I consider it a bug as it is exactly what the OP of #486 wanted to achieve from filtering.

The goal is to process (with a filter) whatever is inside the block assignment and store it to a variable. The filter is responsible for parsing the content and coercing it to a correct type (bool, number, string, lists). Note that the content of the block assignment can contain any Jinja instructions.

Expected Behavior

Prints POSTGRES

Actual Behavior

Prints ORACLE

Template Code

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader("."), autoescape=True)
env.filters['parse_bool'] = lambda s: s == 'True'

# BUG
template = env.from_string("""
{% set ORACLE | parse_bool %}False{% endset %}
{{ 'ORACLE' if ORACLE else 'POSTGRES' }}
""")
print(template.render())

# WORKAROUND
template = env.from_string("""
{% set ORACLE %}False{% endset %}{% set ORACLE = ORACLE | parse_bool %}
{{ 'ORACLE' if ORACLE else 'POSTGRES' }}
""")
print(template.render())

Your Environment

  • Python version: 3.8
  • Jinja version: 2.11.2
@mvolfik
Copy link
Contributor

mvolfik commented Mar 8, 2021

I dug into what exactly is happening there, this is the code that jinja generates for the buggy template:
(I stripped some whitespace, my template looks like this: "{% set ORACLE | parse_bool %}False{% endset %}{{ 'ORACLE' if ORACLE else 'POSTGRES' }}")

from __future__ import generator_stop
from jinja2.runtime import LoopContext, TemplateReference, Macro, Markup, TemplateRuntimeError, missing, concat, escape, markup_join, str_join, identity, TemplateNotFound, Namespace, Undefined
name = 'n'

def root(context, missing=missing, environment=environment):
    resolve = context.resolve_or_missing
    undefined = environment.undefined
    cond_expr_undefined = Undefined
    if 0: yield None
    l_0_ORACLE = missing
    t_1 = environment.filters['parse_bool']
    pass
    t_2 = []
    pass
    t_2.append(
        'False',
    )
    l_0_ORACLE = (Markup if context.eval_ctx.autoescape else identity)(t_1(Markup(concat(t_2)))) # the issue happens here
    context.vars['ORACLE'] = l_0_ORACLE
    context.exported_vars.add('ORACLE')
    yield escape(('ORACLE' if (undefined(name='ORACLE') if l_0_ORACLE is missing else l_0_ORACLE) else 'POSTGRES'))

blocks = {}
debug_info = '1=18'

The issue is the quite obvious - the "False" string is converted to markup, then to False by the filter, but then back to markup because autoescape is True. This points to that this is related to #490 . The markup calls are inserted by compiler here in visit_Filter and here in visit_AssignBlock

This needs to be solved by someone with deeper understanding of the Safe/Unsafe interactions in jinja, i.e. not me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants