diff --git a/src/fromager/constraints.py b/src/fromager/constraints.py index f81a9f6e..f41ac459 100644 --- a/src/fromager/constraints.py +++ b/src/fromager/constraints.py @@ -25,6 +25,11 @@ def add_constraint(self, unparsed: str) -> None: req = Requirement(unparsed) canon_name = canonicalize_name(req.name) previous = self._data.get(canon_name) + + if not requirements_file.evaluate_marker(req, req): + logger.debug(f"Constraint {req} does not match environment") + return + if previous is not None: raise KeyError( f"{canon_name}: new constraint '{req}' conflicts with '{previous}'" diff --git a/tests/test_constraints.py b/tests/test_constraints.py index 6e0c96e0..f9253800 100644 --- a/tests/test_constraints.py +++ b/tests/test_constraints.py @@ -1,6 +1,8 @@ import pathlib +import typing import pytest +from packaging import markers from packaging.requirements import Requirement from packaging.version import Version @@ -37,15 +39,67 @@ def test_add_constraint_conflict(): c = constraints.Constraints() c.add_constraint("foo<=1.1") c.add_constraint("flit_core==2.0rc3") + + # Exact duplicate should raise error (same package, same marker) with pytest.raises(KeyError): c.add_constraint("foo<=1.1") + + # Different version, same marker (no marker) should raise error with pytest.raises(KeyError): c.add_constraint("foo>1.1") + + # Different version for flit_core should raise error with pytest.raises(KeyError): c.add_constraint("flit_core>2.0.0") + + # Normalized name conflict should raise error with pytest.raises(KeyError): c.add_constraint("flit-core>2.0.0") + # Different, but equivalent markers should raise KeyError + with pytest.raises(KeyError): + c.add_constraint( + "bar==1.0; python_version >= '3.11' and platform_machine == 'x86_64'" + ) + c.add_constraint( + "bar==1.1; platform_machine == 'x86_64' and python_version >= '3.11'" + ) + c.add_constraint( + "bar==1.0; python_version >= '3.11' and platform_machine == 'arm64'" + ) + c.add_constraint( + "bar==1.1; platform_machine == 'arm64' and python_version >= '3.11'" + ) + + # Same package with different markers should NOT raise error + c.add_constraint("baz==1.0; platform_machine != 'ppc64le'") + c.add_constraint("baz==1.1; platform_machine == 'ppc64le'") + + # But same package with same marker should raise error + with pytest.raises(KeyError): + c.add_constraint("foo==1.2; platform_machine != 'ppc64le'") + + # Verify multiple constraints for same package are stored + assert len(c._data) == 4 # flit_core, foo, bar, and baz + + # Make sure correct constraint is added + env = typing.cast(dict[str, str], markers.default_environment()) + constraint = c.get_constraint("bar") + + if env.get("platform_machine") == "x86_64" and constraint is not None: + assert constraint.name == "bar" + assert constraint.specifier == "==1.0" + assert constraint.marker == markers.Marker( + 'python_version >= "3.11" and platform_machine == "x86_64"' + ) + + if env.get("platform_machine") == "arm64" and constraint is not None: + assert constraint.name == "bar" + assert constraint.specifier == "==1.0" + assert constraint.marker == markers.Marker( + 'python_version >= "3.11" and platform_machine == "arm64"' + ) + def test_allow_prerelease(): c = constraints.Constraints()