From 20b248fb82803d49c52aa0caf9a3f9330a48eed0 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sat, 21 Mar 2026 19:04:05 +0000 Subject: [PATCH] fix != version constraint incorrectly excluding pre/post/dev releases --- .../core/constraints/version/version_union.py | 9 +------ .../constraints/version/test_version_range.py | 27 +++++++------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/poetry/core/constraints/version/version_union.py b/src/poetry/core/constraints/version/version_union.py index 11fe0b6e3..10d2603c8 100644 --- a/src/poetry/core/constraints/version/version_union.py +++ b/src/poetry/core/constraints/version/version_union.py @@ -100,14 +100,7 @@ def has_upper_bound(self) -> bool: def allows(self, version: Version) -> bool: if self.excludes_single_version: - # when excluded version is local, special handling is required - # to ensure that a constraint (!=2.0+deadbeef) will allow the - # provided version (2.0) - - excluded = self._excluded_single_version - - if excluded.is_local(): - return excluded != version + return not self._excluded_single_version.allows(version) return any(constraint.allows(version) for constraint in self._ranges) diff --git a/tests/constraints/version/test_version_range.py b/tests/constraints/version/test_version_range.py index da9b12fd3..8e86752fc 100644 --- a/tests/constraints/version/test_version_range.py +++ b/tests/constraints/version/test_version_range.py @@ -430,6 +430,14 @@ def test_union( ("2.0.1", "!=2.0"), ("2.0.1", "!=2.0.0"), ("2.0", "!=2.0+deadbeef"), + # != must not inherit exclusive ordered comparison rules from < and > + # (pre-releases, post-releases, dev-releases of the specified + # version are not equal to it) + ("2.0.dev1", "!=2"), + ("2.0a1", "!=2"), + ("2.0b1", "!=2"), + ("2.0rc1", "!=2"), + ("2.0.post1", "!=2"), # Test the in-equality operation with a prefix ("2.0", "!=3.*"), ("2.1", "!=2.0.*"), @@ -581,25 +589,10 @@ def test_specifiers(version: str, spec: str, expected: bool) -> None: https://github.com/pypa/packaging/blob/8b86d85797b9f26d98ecfbe0271ce4dc9495d98c/tests/test_specifiers.py#L469 """ constraint = parse_constraint(spec) - v = Version.parse(version) - if expected: - # Test that the plain string form works - # assert version in spec - assert constraint.allows(v) - - # Test that the version instance form works - # assert version in spec - assert constraint.allows(v) - else: - # Test that the plain string form works - # assert version not in spec - assert not constraint.allows(v) - - # Test that the version instance form works - # assert version not in spec - assert not constraint.allows(v) + allowed = constraint.allows(v) + assert allowed is expected @pytest.mark.parametrize(