diff --git a/conda_build/metadata.py b/conda_build/metadata.py index 5cc5bc129a..2b8443e68c 100644 --- a/conda_build/metadata.py +++ b/conda_build/metadata.py @@ -1597,21 +1597,34 @@ def ms_depends(self, typ="run"): try: ms = MatchSpec(spec) except AssertionError: - raise RuntimeError(f"Invalid package specification: {spec!r}") + if len(self.undefined_jinja_vars) == 0: + raise RuntimeError(f"Invalid package specification: {spec!r}") + else: + continue except (AttributeError, ValueError) as e: - raise RuntimeError( - "Received dictionary as spec. Note that pip requirements are " - "not supported in conda-build meta.yaml. Error message: " + str(e) - ) + if len(self.undefined_jinja_vars) == 0: + raise RuntimeError( + "Received dictionary as spec. Note that pip requirements are " + "not supported in conda-build meta.yaml. Error message: " + + str(e) + ) + else: + continue + if ms.name == self.name() and not ( typ == "build" and self.config.host_subdir != self.config.build_subdir ): raise RuntimeError(f"{self.name()} cannot depend on itself") + + # TODO: IDK what this does since AFAIK the inner continue applies only + # to the inner loop for name, ver in name_ver_list: if ms.name == name: if self.noarch: continue + # TODO: the validation here appears to be a waste of time since MatchSpec + # appears to validate? for c in "=!@#$%^&*:;\"'\\|<>?/": if c in ms.name: sys.exit( diff --git a/news/5555-skip-bad-specs-while-still-parsing.rst b/news/5555-skip-bad-specs-while-still-parsing.rst new file mode 100644 index 0000000000..1454fb9bad --- /dev/null +++ b/news/5555-skip-bad-specs-while-still-parsing.rst @@ -0,0 +1,19 @@ +### Enhancements + +* + +### Bug fixes + +* Fixed a bug where bad match specs from intermediate parsing results would cause parsing to fail. (#5555) + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/test_api_build.py b/tests/test_api_build.py index d6a519cc5a..3e70dd64fe 100644 --- a/tests/test_api_build.py +++ b/tests/test_api_build.py @@ -2082,7 +2082,7 @@ def test_conda_build_script_errors_without_conda_info_handlers(tmp_path, recipe, def test_api_build_inject_jinja2_vars_on_first_pass(testing_config): recipe_dir = os.path.join(metadata_dir, "_inject_jinja2_vars_on_first_pass") - with pytest.raises(RuntimeError): + with pytest.raises((RuntimeError, CondaBuildUserError)): api.build(recipe_dir, config=testing_config) testing_config.variant = {"python_min": "3.12"} diff --git a/tests/test_metadata.py b/tests/test_metadata.py index d5feecf53c..3985bdc1df 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -655,3 +655,56 @@ def test_parse_until_resolved_skip_avoids_undefined_jinja( pytest.fail( "Undefined variable caused error, even though this build is skipped" ) + + +@pytest.mark.parametrize("have_variant", [True, False]) +def test_parse_until_resolved_missing_jinja_in_spec( + testing_metadata: MetaData, + tmp_path: Path, + have_variant: bool, +) -> None: + (recipe := tmp_path / (name := "meta.yaml")).write_text( + """ +package: + name: dummy + version: 1.0.0 + +build: + noarch: python + number: 0 + +requirements: + host: + - python ={{ python_min }} + run: + - python >={{ python_min }} +""" + ) + (tmp_path / "conda_build_config.yaml").write_text( + """ +python_min: + - 3.6 +""" + ) + testing_metadata._meta_path = recipe + testing_metadata._meta_name = name + if have_variant: + testing_metadata.config.variant = {"python_min": "3.6"} + else: + delattr(testing_metadata.config, "variant") + delattr(testing_metadata.config, "variant_config_files") + delattr(testing_metadata.config, "variants") + + try: + testing_metadata.parse_until_resolved() + if not have_variant: + pytest.fail("Undefined variable did NOT cause spec parsing error!") + else: + print("parsed OK!") + except (Exception, SystemExit): + if have_variant: + pytest.fail( + "Undefined variable caused spec parsing error even if we have the variant!" + ) + else: + print("did not parse OK!")