From b8be63c21384ab7d657db9dbbe3d7c6bde997b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Mon, 3 Feb 2025 05:16:03 +0100 Subject: [PATCH] add `has_upper_bound` method to `VersionConstraint` --- .../constraints/version/empty_constraint.py | 3 ++ .../constraints/version/version_constraint.py | 4 +++ .../version/version_range_constraint.py | 3 ++ .../core/constraints/version/version_union.py | 3 ++ .../version/test_version_constraint.py | 29 +++++++++++++++++++ 5 files changed, 42 insertions(+) diff --git a/src/poetry/core/constraints/version/empty_constraint.py b/src/poetry/core/constraints/version/empty_constraint.py index 5c9f6f5c7..ec78053cb 100644 --- a/src/poetry/core/constraints/version/empty_constraint.py +++ b/src/poetry/core/constraints/version/empty_constraint.py @@ -22,6 +22,9 @@ def is_any(self) -> bool: def is_simple(self) -> bool: return True + def has_upper_bound(self) -> bool: + return True + def allows(self, version: Version) -> bool: return False diff --git a/src/poetry/core/constraints/version/version_constraint.py b/src/poetry/core/constraints/version/version_constraint.py index ecabc3e31..0a21354e4 100644 --- a/src/poetry/core/constraints/version/version_constraint.py +++ b/src/poetry/core/constraints/version/version_constraint.py @@ -24,6 +24,10 @@ def is_any(self) -> bool: def is_simple(self) -> bool: raise NotImplementedError + @abstractmethod + def has_upper_bound(self) -> bool: + raise NotImplementedError + @abstractmethod def allows(self, version: Version) -> bool: raise NotImplementedError diff --git a/src/poetry/core/constraints/version/version_range_constraint.py b/src/poetry/core/constraints/version/version_range_constraint.py index df76423b9..324dbd061 100644 --- a/src/poetry/core/constraints/version/version_range_constraint.py +++ b/src/poetry/core/constraints/version/version_range_constraint.py @@ -62,6 +62,9 @@ def allowed_max(self) -> Version | None: # https://peps.python.org/pep-0440/#exclusive-ordered-comparison return self.max.first_devrelease() + def has_upper_bound(self) -> bool: + return self.max is not None + def allows_lower(self, other: VersionRangeConstraint) -> bool: _this, _other = self.allowed_min, other.allowed_min diff --git a/src/poetry/core/constraints/version/version_union.py b/src/poetry/core/constraints/version/version_union.py index a37d1d748..fadc700d2 100644 --- a/src/poetry/core/constraints/version/version_union.py +++ b/src/poetry/core/constraints/version/version_union.py @@ -95,6 +95,9 @@ def is_any(self) -> bool: def is_simple(self) -> bool: return self.excludes_single_version + def has_upper_bound(self) -> bool: + return all(constraint.has_upper_bound() for constraint in self._ranges) + def allows(self, version: Version) -> bool: if self.excludes_single_version: # when excluded version is local, special handling is required diff --git a/tests/constraints/version/test_version_constraint.py b/tests/constraints/version/test_version_constraint.py index 49834dee1..6ce15cd1f 100644 --- a/tests/constraints/version/test_version_constraint.py +++ b/tests/constraints/version/test_version_constraint.py @@ -30,3 +30,32 @@ def test_constraints_are_hashable(constraint: VersionConstraint) -> None: # We're just testing that constraints are hashable, there's nothing much to say # about the result. hash(constraint) + + +@pytest.mark.parametrize( + ("constraint", "expected"), + [ + (EmptyConstraint(), True), + (Version.parse("1"), True), + (VersionRange(), False), + (VersionRange(Version.parse("1")), False), + (VersionRange(max=Version.parse("2")), True), + (VersionRange(Version.parse("1"), Version.parse("2")), True), + ( + VersionUnion( + VersionRange(Version.parse("1"), Version.parse("2")), + VersionRange(Version.parse("3"), Version.parse("4")), + ), + True, + ), + ( + VersionUnion( + VersionRange(Version.parse("1"), Version.parse("2")), + VersionRange(Version.parse("3")), + ), + False, + ), + ], +) +def test_has_upper_bound(constraint: VersionConstraint, expected: bool) -> None: + assert constraint.has_upper_bound() is expected