From 41856b5d72b1de67e49e85af8ac4dbd0d9854333 Mon Sep 17 00:00:00 2001 From: "Matthew R. Becker" Date: Thu, 14 Nov 2024 11:39:08 -0600 Subject: [PATCH] fix: ensure variable finding works properly and add unit tests for variable finding (#5535) Co-authored-by: jaimergp --- conda_build/variants.py | 4 +- news/5535-fix-variant-finding.rst | 21 +++++++++++ tests/test_variants.py | 63 +++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 news/5535-fix-variant-finding.rst diff --git a/conda_build/variants.py b/conda_build/variants.py index 15feb9e687..ed21daf806 100644 --- a/conda_build/variants.py +++ b/conda_build/variants.py @@ -749,7 +749,9 @@ def find_used_variables_in_text(variant, recipe_text, selectors_only=False): continue v_regex = re.escape(v) v_req_regex = "[-_]".join(map(re.escape, v.split("_"))) - variant_regex = rf"\{{\s*(?:pin_[a-z]+\(\s*?['\"])?{v_regex}[^'\"]*?\}}\}}" + variant_regex = ( + rf"\{{\s*(?:pin_[a-z]+\(\s*?['\"])?{v_regex}[^_0-9a-zA-Z].*?\}}\}}" + ) selector_regex = rf"^[^#\[]*?\#?\s\[[^\]]*?(?!\]]" # NOTE: why use a regex instead of the jinja2 parser/AST? # One can ask the jinja2 parser for undefined variables, but conda-build moves whole diff --git a/news/5535-fix-variant-finding.rst b/news/5535-fix-variant-finding.rst new file mode 100644 index 0000000000..ea8a346e01 --- /dev/null +++ b/news/5535-fix-variant-finding.rst @@ -0,0 +1,21 @@ +### Enhancements + +* + +### Bug fixes + +* Fixed a bug where variants were incorrectly found as being used when they matched a leading substring of + another variant. (#5535) +* Fixed a bug where variants were not found when variables were used in ``pin_*`` statements. (#5535) + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/test_variants.py b/tests/test_variants.py index 84c1d96404..572d6362bf 100644 --- a/tests/test_variants.py +++ b/tests/test_variants.py @@ -19,6 +19,7 @@ filter_combined_spec_to_used_keys, find_used_variables_in_batch_script, find_used_variables_in_shell_script, + find_used_variables_in_text, get_package_variants, get_vars, validate_spec, @@ -816,6 +817,68 @@ def test_get_vars(): assert get_vars(variants) == {"nodejs"} +@pytest.mark.parametrize( + "vars,text,found_vars", + [ + # basic tests + ( + ("python", "python_min"), + "{{ python }}", + {"python"}, + ), + ( + ("python", "python_min"), + "{{ python_min }}", + {"python_min"}, + ), + # filters and other text + ( + ("python", "python_min"), + "python {{ python_min }}", + {"python_min"}, + ), + ( + ("python", "python_min"), + "python {{ python }}", + {"python"}, + ), + ( + ("python", "python_min"), + "python {{ python|lower }}", + {"python"}, + ), + ( + ("python", "python_min"), + "{{ python_min|lower }}", + {"python_min"}, + ), + # pin_* statements + ( + ("python", "python_min"), + "{{ pin_compatible('python') }}", + {"python"}, + ), + ( + ("python", "python_min"), + "{{ pin_compatible('python', max_pin='x.x') }}", + {"python"}, + ), + ( + ("python", "python_min"), + "{{ pin_compatible('python_min') }}", + {"python_min"}, + ), + ( + ("python", "python_min"), + "{{ pin_compatible('python_min', max_pin='x.x') }}", + {"python_min"}, + ), + ], +) +def test_find_used_variables_in_text(vars, text, found_vars): + assert find_used_variables_in_text(vars, text) == found_vars + + def test_find_used_variables_in_shell_script(tmp_path: Path) -> None: variants = ("FOO", "BAR", "BAZ", "QUX") (script := tmp_path / "script.sh").write_text(