Fix union(range, public_version) to fill local-variant punctures#950
Merged
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In the parametrized
test_union_with_public_version_is_symmetric, the parameter namesminandmaxshadow builtins and make the test harder to read; consider renaming them (e.g.,min_version,max_version) for clarity. - The broadening of the upper bound using
other.stable.next_patch()inVersionRange.unionassumesotherbehaves like a final release; it may be worth explicitly considering or guarding how this behaves for non-final versions (pre/dev/post releases) to ensure it matches the intended PEP 440 semantics.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the parametrized `test_union_with_public_version_is_symmetric`, the parameter names `min` and `max` shadow builtins and make the test harder to read; consider renaming them (e.g., `min_version`, `max_version`) for clarity.
- The broadening of the upper bound using `other.stable.next_patch()` in `VersionRange.union` assumes `other` behaves like a final release; it may be worth explicitly considering or guarding how this behaves for non-final versions (pre/dev/post releases) to ensure it matches the intended PEP 440 semantics.
## Individual Comments
### Comment 1
<location path="tests/constraints/version/test_version_range.py" line_range="738-756" />
<code_context>
assert isinstance(result, EmptyConstraint)
+def test_union_upper_bound_local_with_public_extends_to_next_patch() -> None:
+ """``>=X,<X+local ∪ ==X`` broadens the upper bound to
+ ``X.next_patch()`` (exclusive). ``==X`` matches every ``X+local``
+ variant by PEP 440 release-equality, so the union must cover them.
+ """
+ range_below = VersionRange(
+ Version.parse("0.21.0"),
+ Version.parse("0.21.0+cpu"),
+ include_min=True,
+ include_max=False,
+ )
+ public = Version.parse("0.21.0")
+ expected = VersionRange(
+ Version.parse("0.21.0"),
+ Version.parse("0.21.1"),
+ include_min=True,
+ include_max=False,
+ )
+ assert range_below.union(public) == expected
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a case where both bounds are local variants of the same public version to ensure the range collapses as intended
Current tests only cover cases where one bound is local and the other is public. Please add a case where both bounds are local variants of the same public version (e.g. `>=0.21.0+cpu,<=0.21.0+gpu ∪ ==0.21.0`) and assert it collapses to `[0.21.0, 0.21.1)`, checking both `range ∪ ==X` and `==X ∪ range` for symmetry.
```suggestion
def test_union_upper_bound_local_with_public_extends_to_next_patch() -> None:
"""``>=X,<X+local ∪ ==X`` broadens the upper bound to
``X.next_patch()`` (exclusive). ``==X`` matches every ``X+local``
variant by PEP 440 release-equality, so the union must cover them.
"""
range_below = VersionRange(
Version.parse("0.21.0"),
Version.parse("0.21.0+cpu"),
include_min=True,
include_max=False,
)
public = Version.parse("0.21.0")
expected = VersionRange(
Version.parse("0.21.0"),
Version.parse("0.21.1"),
include_min=True,
include_max=False,
)
assert range_below.union(public) == expected
def test_union_local_bounds_with_public_collapses_to_next_patch() -> None:
"""``>=X+local1,<=X+local2 ∪ ==X`` collapses to ``[X, X.next_patch())``.
Both bounds are local variants of the same public version ``X``.
Since ``==X`` matches all of them by PEP 440 release-equality, the
union must cover the entire public range up to ``X.next_patch()``.
"""
range_locals = VersionRange(
Version.parse("0.21.0+cpu"),
Version.parse("0.21.0+gpu"),
include_min=True,
include_max=True,
)
public = Version.parse("0.21.0")
expected = VersionRange(
Version.parse("0.21.0"),
Version.parse("0.21.1"),
include_min=True,
include_max=False,
)
# range ∪ ==X
assert range_locals.union(public) == expected
# ==X ∪ range (symmetry)
assert public.union(range_locals) == expected
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
64d1169 to
c3de379
Compare
radoering
reviewed
Jun 8, 2026
The constraint algebra treated '==X' as the literal point [X, X] when computing 'range.union(public_X)', returning the range unchanged whenever the range already allowed X. But per PEP 440 release-equality '==X' also matches every local-tagged variant 'X+local', so a range whose bound is such a variant (e.g. '>=X,<X+local' or '>X+local,<Y') must be broadened to include those variants in the union. Apply the broadening symmetrically in VersionRange.union(Version), handling both bounds in a single pass, and delegate Version.union(non Version) to the other operand so the rules apply regardless of operand order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- remove mostly duplicated test and test for symmetry in other tests instead - add test with both local bounds
radoering
approved these changes
Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The constraint algebra treated '==X' as the literal point [X, X] when computing 'range.union(public_X)', returning the range unchanged whenever the range already allowed X. But per PEP 440 release-equality '==X' also matches every local-tagged variant 'X+local', so a range whose bound is such a variant (e.g. '>=X,<X+local' or '>X+local,<Y') must be broadened to include those variants in the union.
Apply the broadening symmetrically in VersionRange.union(Version), handling both bounds in a single pass, and delegate Version.union(non Version) to the other operand so the rules apply regardless of operand order.
Resolves: python-poetry#