Skip to content

Commit b382079

Browse files
committed
Non-PEP440 versions shouldn't prevent prerelease versions in empty specifier
1 parent 5279967 commit b382079

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

src/packaging/specifiers.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,14 +1032,22 @@ def filter(
10321032

10331033
# Finally if prereleases is None, apply PEP 440 logic:
10341034
# exclude prereleases unless there are no final releases that matched.
1035-
filtered: list[UnparsedVersionVar] = []
1035+
filtered_items: list[UnparsedVersionVar] = []
10361036
found_prereleases: list[UnparsedVersionVar] = []
1037+
found_final_release = False
10371038

10381039
for item in iterable:
10391040
parsed_version = _coerce_version(item)
1040-
if parsed_version is not None and parsed_version.is_prerelease:
1041+
# Arbitrary strings are always included as it is not
1042+
# possible to determine if they are prereleases,
1043+
# and they have already passed all specifiers.
1044+
if parsed_version is None:
1045+
filtered_items.append(item)
1046+
found_prereleases.append(item)
1047+
elif parsed_version.is_prerelease:
10411048
found_prereleases.append(item)
10421049
else:
1043-
filtered.append(item)
1050+
filtered_items.append(item)
1051+
found_final_release = True
10441052

1045-
return iter(filtered if filtered else found_prereleases)
1053+
return iter(filtered_items if found_final_release else found_prereleases)

tests/test_specifiers.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ def test_specifier_prereleases_set(
594594
[
595595
("1.0.0", "===1.0", False),
596596
("1.0.dev0", "===1.0", False),
597-
# Test exact arbitrary equality (===)
597+
# Test identity comparison by itself
598598
("1.0", "===1.0", True),
599599
("1.0.dev0", "===1.0.dev0", True),
600600
# Test that local versions don't match
@@ -755,13 +755,7 @@ def test_specifiers_prereleases(
755755
# Test != with invalid versions (should not pass as versions are not valid)
756756
("!=1.0", None, None, ["invalid", "foobar"], []),
757757
("!=1.0", None, None, ["1.0", "invalid", "2.0"], ["2.0"]),
758-
(
759-
"!=2.0.*",
760-
None,
761-
None,
762-
["invalid", "foobar", "2.0"],
763-
[]
764-
),
758+
("!=2.0.*", None, None, ["invalid", "foobar", "2.0"], []),
765759
("!=2.0.*", None, None, ["1.0", "invalid", "2.0.0"], ["1.0"]),
766760
# Test that !== ignores prereleases parameter for non-PEP 440 versions
767761
("!=1.0", None, True, ["invalid", "foobar"], []),
@@ -875,15 +869,34 @@ def test_empty_specifier(self, version: str) -> None:
875869
assert spec.contains(parse(version))
876870

877871
@pytest.mark.parametrize(
878-
"prereleases",
879-
[None, False, True],
872+
("prereleases", "versions", "expected"),
873+
[
874+
# single arbitrary string
875+
(None, ["foobar"], ["foobar"]),
876+
(False, ["foobar"], ["foobar"]),
877+
(True, ["foobar"], ["foobar"]),
878+
# arbitrary string with a stable version present
879+
(None, ["foobar", "1.0"], ["foobar", "1.0"]),
880+
(False, ["foobar", "1.0"], ["foobar", "1.0"]),
881+
(True, ["foobar", "1.0"], ["foobar", "1.0"]),
882+
# arbitrary string with a prerelease only
883+
(None, ["foobar", "1.0a1"], ["foobar", "1.0a1"]),
884+
(False, ["foobar", "1.0a1"], ["foobar"]),
885+
(True, ["foobar", "1.0a1"], ["foobar", "1.0a1"]),
886+
],
880887
)
881-
def test_empty_specifier_arbitrary_string(self, prereleases):
888+
def test_empty_specifier_arbitrary_string(self, prereleases, versions, expected):
882889
"""Test empty SpecifierSet accepts arbitrary strings."""
883890

884891
spec = SpecifierSet("", prereleases=prereleases)
892+
893+
# basic behavior preserved
885894
assert spec.contains("foobar")
886895

896+
# check filter behavior (no override of prereleases passed to filter)
897+
kwargs = {}
898+
assert list(spec.filter(versions, **kwargs)) == expected
899+
887900
def test_create_from_specifiers(self) -> None:
888901
spec_strs = [">=1.0", "!=1.1", "!=1.2", "<2.0"]
889902
specs = [Specifier(s) for s in spec_strs]

0 commit comments

Comments
 (0)