diff --git a/pyproject_buildrequires.py b/pyproject_buildrequires.py index 61b31bd..769c059 100644 --- a/pyproject_buildrequires.py +++ b/pyproject_buildrequires.py @@ -139,31 +139,25 @@ class Requirements: return parsed_overrides - @staticmethod - def _base_package_name(package_name): - """Extract base package name, stripping any extras like [extra1].""" - bracket = package_name.find('[') - if bracket != -1: - package_name = package_name[:bracket] - return canonicalize_name(package_name) - def _should_ignore_dependency(self, package_name): """Check if a dependency should be completely ignored.""" - package_name = self._base_package_name(package_name) if package_name not in self.dependency_overrides: return False return any(o['action'] == 'ignore' for o in self.dependency_overrides[package_name]) - def _apply_dependency_overrides(self, package_name, specifiers): + def _apply_dependency_overrides(self, requirement): """Apply dependency overrides to a list of specifiers for a given package.""" - package_name = self._base_package_name(package_name) + package_name = canonicalize_name(requirement.name) if package_name not in self.dependency_overrides: - return specifiers + return requirement - return apply_overrides_to_specifiers( - specifiers, self.dependency_overrides[package_name], + overridden = apply_overrides_to_specifiers( + requirement.specifier, self.dependency_overrides[package_name], package_name=package_name, log_fn=print_err) + requirement.specifier = SpecifierSet(','.join(str(s) for s in overridden)) + return requirement + @property def marker_envs(self): if self.extras: @@ -242,11 +236,7 @@ class Requirements: # Apply dependency overrides before the installed-version check, # so the check reflects the constraints we will actually output. - if self._base_package_name(name) in self.dependency_overrides: - overridden = self._apply_dependency_overrides( - name, list(requirement.specifier)) - requirement.specifier = SpecifierSet( - ','.join(str(s) for s in overridden)) + requirement = self._apply_dependency_overrides(requirement) # We need to always accept pre-releases as satisfying the requirement # Otherwise e.g. installed cffi version 1.15.0rc2 won't even satisfy the requirement for "cffi" diff --git a/test_dependency_overrides.py b/test_dependency_overrides.py index be041cf..19ffe03 100644 --- a/test_dependency_overrides.py +++ b/test_dependency_overrides.py @@ -330,22 +330,6 @@ class TestParseDependencyOverrides: self._parse(['pkg:ignore:somevalue']) -# ---- Requirements._base_package_name ---- - -class TestBasePackageName: - def test_simple_name(self): - assert Requirements._base_package_name('requests') == 'requests' - - def test_with_extras(self): - assert Requirements._base_package_name('requests[security]') == 'requests' - - def test_normalization(self): - assert Requirements._base_package_name('My_Package') == 'my-package' - - def test_with_extras_and_normalization(self): - assert Requirements._base_package_name('My_Package[extra]') == 'my-package' - - # ---- Requirements._should_ignore_dependency ---- class TestShouldIgnoreDependency: @@ -375,81 +359,75 @@ class TestApplyDependencyOverrides: raise Exception('not installed') return Requirements(mock_version, dependency_overrides=overrides) - def _specs(self, spec_str): - return list(SpecifierSet(spec_str)) - def test_no_overrides(self): r = self._make_req([]) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 2 + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + assert len(list(result.specifier)) == 2 def test_drop_upper(self): r = self._make_req(['numpy:drop_upper']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 1 - assert result[0].operator == '>=' + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '>=' def test_drop_lower(self): r = self._make_req(['numpy:drop_lower']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 1 - assert result[0].operator == '<' + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '<' def test_drop_constraints(self): r = self._make_req(['numpy:drop_constraints']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert result == [] + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + assert list(result.specifier) == [] def test_set_upper(self): r = self._make_req(['numpy:set_upper:3.0']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 2 - ops = {s.operator for s in result} + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + specs = list(result.specifier) + assert len(specs) == 2 + ops = {s.operator for s in specs} assert '>=' in ops assert '<' in ops - upper = [s for s in result if s.operator == '<'][0] + upper = [s for s in specs if s.operator == '<'][0] assert upper.version == '3.0' def test_set_lower(self): r = self._make_req(['numpy:set_lower:0.5']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 2 - ops = {s.operator for s in result} + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + specs = list(result.specifier) + assert len(specs) == 2 + ops = {s.operator for s in specs} assert '>=' in ops assert '<' in ops - lower = [s for s in result if s.operator == '>='][0] + lower = [s for s in specs if s.operator == '>='][0] assert lower.version == '0.5' def test_drop_upper_decomposes_pin(self): """drop_upper on == decomposes to >= (keeps lower half).""" r = self._make_req(['attrs:drop_upper']) - specs = self._specs('==25.3.0') - result = r._apply_dependency_overrides('attrs', specs) - assert len(result) == 1 - assert result[0].operator == '>=' - assert result[0].version == '25.3.0' + result = r._apply_dependency_overrides(Requirement('attrs==25.3.0')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '>=' + assert specs[0].version == '25.3.0' def test_drop_lower_decomposes_pin(self): """drop_lower on == decomposes to <= (keeps upper half).""" r = self._make_req(['attrs:drop_lower']) - specs = self._specs('==25.3.0') - result = r._apply_dependency_overrides('attrs', specs) - assert len(result) == 1 - assert result[0].operator == '<=' - assert result[0].version == '25.3.0' + result = r._apply_dependency_overrides(Requirement('attrs==25.3.0')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '<=' + assert specs[0].version == '25.3.0' def test_drop_upper_preserves_exclusions(self): """!= exclusions are always preserved.""" r = self._make_req(['pkg:drop_upper']) - specs = self._specs('>=1.0,!=1.5,<3.0') - result = r._apply_dependency_overrides('pkg', specs) - ops = [s.operator for s in result] + result = r._apply_dependency_overrides(Requirement('pkg>=1.0,!=1.5,<3.0')) + ops = [s.operator for s in result.specifier] assert '>=' in ops assert '!=' in ops assert '<' not in ops @@ -457,31 +435,29 @@ class TestApplyDependencyOverrides: def test_ignore_action_passthrough(self): """ignore action is handled separately; _apply_dependency_overrides skips it.""" r = self._make_req(['pkg:ignore']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('pkg', specs) - assert len(result) == 2 + result = r._apply_dependency_overrides(Requirement('pkg>=1.0,<2.0')) + assert len(list(result.specifier)) == 2 def test_unrelated_package_not_affected(self): r = self._make_req(['other:drop_upper']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy', specs) - assert len(result) == 2 + result = r._apply_dependency_overrides(Requirement('numpy>=1.0,<2.0')) + assert len(list(result.specifier)) == 2 def test_extras_stripped_for_lookup(self): r = self._make_req(['numpy:drop_upper']) - specs = self._specs('>=1.0,<2.0') - result = r._apply_dependency_overrides('numpy[extra1]', specs) - assert len(result) == 1 - assert result[0].operator == '>=' + result = r._apply_dependency_overrides(Requirement('numpy[extra1]>=1.0,<2.0')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '>=' def test_drop_upper_decomposes_tilde(self): """drop_upper on ~= decomposes to >= (PEP 440: ~=V.N is >=V.N, ==V.*).""" r = self._make_req(['pkg:drop_upper']) - specs = self._specs('~=1.4') - result = r._apply_dependency_overrides('pkg', specs) - assert len(result) == 1 - assert result[0].operator == '>=' - assert result[0].version == '1.4' + result = r._apply_dependency_overrides(Requirement('pkg~=1.4')) + specs = list(result.specifier) + assert len(specs) == 1 + assert specs[0].operator == '>=' + assert specs[0].version == '1.4' # ---- pyproject_patch_metadata ----