-
Notifications
You must be signed in to change notification settings - Fork 426
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
fix: make sure to catch jinja2 vars used in single-line for
and set
statements
#5447
Conversation
CodSpeed Performance ReportMerging #5447 will not alter performanceComparing Summary
|
for
and set
statements
@kenodegard @isuruf or anyone else, can you review this PR? It is an important bug fix that I'd like to see in 24.7.2 if we can. |
for
and set
statementsfor
and set
statements
Looking at this code for the first time I wonder why are regexes needed when apparently Jinja will happily give you a list of variables in use with three lines. Are we doing this before the selectors are parsed? Would it make sense to preprocess the selectors and then defer to the Jinja AST instead of regexes? Mentioning this because of the single-line limitations and exotic syntax not covered right now. Documenting these limitations in the function docstring might be enough. |
I looked at that stackoverflow for a while, but didn't do any investigating. Here is how it behaves: import jinja2
import jinja2.meta
env = jinja2.Environment()
parsed_content = env.parse(
"""
{% set CL_VERSION = "19.29" %}
{% if VCVER is not defined %}
{% set BLAH = "19.29" %}
{% set FOO = "19.29" %}
{% set VCVER = "" %}
{% else %}
{% set BLAH = "19.29" %}
{% set BAZ = "19.29" %}
{% endif %}
{% set clang_major = (CLANG_VERSION|default("19.29")).split(".")[0] %}
{% set cl_minor = CL_VERSION.split(".")[1] %}
{% set vc_major = VCVER.split(".")[0] %}
package:
name: clang-win-activation
version: {{ CLANG_VERSION }}
build:
number: 0
{% if clang_major|int == 16 and cl_minor|int >= 40 %}
skip: true
{% endif %}
outputs:
- name: clang_win-64
build:
run_exports:
strong:
- vc >={{ VCVER }}
requirements:
run:
- clang {{ CLANG_VERSION }}.*
"""
)
tokens = jinja2.meta.find_undeclared_variables(parsed_content)
print(tokens) This gives % python jinja.py
{'BAZ', 'VCVER', 'FOO', 'BLAH', 'CLANG_VERSION'} So the behavior is basically that anything that touches a conditional with a default value or uses a default filter is marked as undefined. I'd argue that As for when this happens, searches for jinja2 variables happens after selectors: conda-build/conda_build/metadata.py Lines 2856 to 2892 in d908fe1
and so using the jinja2 functions won't work unless we change the order (edit see below for more details, jinja2 functions won't ever work in all cases). |
Other details that are fun.
|
conda_build/variants.py
Outdated
# NOTE: why use a regex instead of the jinja2 parser/AST? | ||
# One can ask the jinj2 parser for undefined variables, but conda-build moves whole | ||
# blocks of text around when searching for variables and applies selectors to the text. | ||
# So the text that reaches this function is not necessarily valid jinja2 syntax. :/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jaimergp @wolfv @h-vetinari I have added a comment explaining why we have to use a regex here. Let's merge this one instead of letting the perfect be the enemy of the good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I think at this point it's impossible to fix this properly, sadly. LGTM!
@kenodegard @jaimergp @jezdez It appears a dev release of conda on the canary channel is buggy and that is breaking the tests here. What do we do in these cases? |
# TODO: this `for` regex won't catch some common cases like lists of vars, multiline | ||
# jinja2 blocks, if filters on the for loop, etc. | ||
for_regex = r"(?:^|[^\{])\{%\s*for\s*.*\s*in\s*" + v_regex + r"(?:[^%]*?)?%\}" | ||
set_regex = r"(?:^|[^\{])\{%\s*set\s*.*\s*=\s*.*" + v_regex + r"(?:[^%]*?)?%\}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regex is not very good.
The following yaml matches glib
and glibc
both.
{% set a = glibc %}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any suggestions to fix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set_regex = r"(?:^|[^\{])\{%\s*set\s*.*\s*=\s*.*" + v_regex + r"(?![a-zA-Z_0-9])(?:[^%]*?)?%\}"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #5514
Description
This PR adds two regexes to catch variables used in single-line jinja2
for
andset
statements. These have been missed for a long time and appear to be the cause of at least one bug. I have not gone through the bug tracker, but I have a hunch this PR might fix other bugs related to similar situations I've seen in the past.closes #5445
Checklist - did you ...
news
directory (using the template) for the next release's release notes?