Skip to content

Commit 2b06f90

Browse files
authored
Allow creating a SpecifierSet from a list of specifiers (pypa#777)
* Allow creating a SpecifierSet from a list of specifiers * Change from Union to | in type annotation
1 parent 680c31a commit 2b06f90

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ No unreleased changes.
2424
have not been provided (:issue:`733`)
2525
* Fix a bug preventing the use of the built in ``ExceptionGroup`` on versions of
2626
Python that support it (:issue:`725`)
27+
* Support creating a ``SpecifierSet`` from an iterable of ``Specifier`` objects (:issue:`775`)
2728

2829
23.2 - 2023-10-01
2930
~~~~~~~~~~~~~~~~~

src/packaging/specifiers.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -694,12 +694,18 @@ class SpecifierSet(BaseSpecifier):
694694
specifiers (``>=3.0,!=3.1``), or no specifier at all.
695695
"""
696696

697-
def __init__(self, specifiers: str = "", prereleases: bool | None = None) -> None:
697+
def __init__(
698+
self,
699+
specifiers: str | Iterable[Specifier] = "",
700+
prereleases: bool | None = None,
701+
) -> None:
698702
"""Initialize a SpecifierSet instance.
699703
700704
:param specifiers:
701705
The string representation of a specifier or a comma-separated list of
702706
specifiers which will be parsed and normalized before use.
707+
May also be an iterable of ``Specifier`` instances, which will be used
708+
as is.
703709
:param prereleases:
704710
This tells the SpecifierSet if it should accept prerelease versions if
705711
applicable or not. The default of ``None`` will autodetect it from the
@@ -710,12 +716,17 @@ def __init__(self, specifiers: str = "", prereleases: bool | None = None) -> Non
710716
raised.
711717
"""
712718

713-
# Split on `,` to break each individual specifier into it's own item, and
714-
# strip each item to remove leading/trailing whitespace.
715-
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
719+
if isinstance(specifiers, str):
720+
# Split on `,` to break each individual specifier into its own item, and
721+
# strip each item to remove leading/trailing whitespace.
722+
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
716723

717-
# Make each individual specifier a Specifier and save in a frozen set for later.
718-
self._specs = frozenset(map(Specifier, split_specifiers))
724+
# Make each individual specifier a Specifier and save in a frozen set
725+
# for later.
726+
self._specs = frozenset(map(Specifier, split_specifiers))
727+
else:
728+
# Save the supplied specifiers in a frozen set.
729+
self._specs = frozenset(specifiers)
719730

720731
# Store our prereleases value so we can use it later to determine if
721732
# we accept prereleases or not.

tests/test_specifiers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,12 @@ def test_empty_specifier(self, version):
646646
assert parse(version) in spec
647647
assert spec.contains(parse(version))
648648

649+
def test_create_from_specifiers(self):
650+
spec_strs = [">=1.0", "!=1.1", "!=1.2", "<2.0"]
651+
specs = [Specifier(s) for s in spec_strs]
652+
spec = SpecifierSet(iter(specs))
653+
assert set(spec) == set(specs)
654+
649655
def test_specifier_prereleases_explicit(self):
650656
spec = SpecifierSet()
651657
assert not spec.prereleases

0 commit comments

Comments
 (0)