1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4"""
5.. testsetup::
6
7 from pip._vendor.packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier
8 from pip._vendor.packaging.version import Version
9"""
10
11from __future__ import annotations
12
13import abc
14import enum
15import functools
16import itertools
17import re
18import sys
19import typing
20from typing import (
21 TYPE_CHECKING,
22 Any,
23 Callable,
24 Final,
25 Iterable,
26 Iterator,
27 Sequence,
28 TypeVar,
29 Union,
30)
31
32from .utils import canonicalize_version
33from .version import InvalidVersion, Version
34
35if sys.version_info >= (3, 10):
36 from typing import TypeGuard # pragma: no cover
37elif TYPE_CHECKING:
38 from typing_extensions import TypeGuard
39
40__all__ = [
41 "BaseSpecifier",
42 "InvalidSpecifier",
43 "Specifier",
44 "SpecifierSet",
45]
46
47
48def __dir__() -> list[str]:
49 return __all__
50
51
52def _validate_spec(spec: object, /) -> TypeGuard[tuple[str, str]]:
53 return (
54 isinstance(spec, tuple)
55 and len(spec) == 2
56 and isinstance(spec[0], str)
57 and isinstance(spec[1], str)
58 )
59
60
61def _validate_pre(pre: object, /) -> TypeGuard[bool | None]:
62 return pre is None or isinstance(pre, bool)
63
64
65T = TypeVar("T")
66UnparsedVersion = Union[Version, str]
67UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
68CallableOperator = Callable[[Version, str], bool]
69
70# The smallest possible PEP 440 version. No valid version is less than this.
71_MIN_VERSION: Final[Version] = Version("0.dev0")
72
73
74def _trim_release(release: tuple[int, ...]) -> tuple[int, ...]:
75 """Strip trailing zeros from a release tuple for normalized comparison."""
76 end = len(release)
77 while end > 1 and release[end - 1] == 0:
78 end -= 1
79 return release if end == len(release) else release[:end]
80
81
82class _BoundaryKind(enum.Enum):
83 """Where a boundary marker sits in the version ordering."""
84
85 AFTER_LOCALS = enum.auto() # after V+local, before V.post0
86 AFTER_POSTS = enum.auto() # after V.postN, before next release
87
88
89@functools.total_ordering
90class _BoundaryVersion:
91 """A point on the version line between two real PEP 440 versions.
92
93 Some specifier semantics imply boundaries between real versions:
94 ``<=1.0`` includes ``1.0+local`` and ``>1.0`` excludes
95 ``1.0.post0``. No real :class:`Version` falls on those boundaries,
96 so this class creates values that sort between the real versions
97 on either side.
98
99 Two kinds exist, shown relative to a base version V::
100
101 V < V+local < AFTER_LOCALS(V) < V.post0 < AFTER_POSTS(V)
102
103 ``AFTER_LOCALS`` sits after V and every V+local, but before
104 V.post0. Upper bound of ``<=V``, ``==V``, ``!=V``.
105
106 ``AFTER_POSTS`` sits after every V.postN, but before the next
107 release segment. Lower bound of ``>V`` (final or pre-release V)
108 to exclude post-releases per PEP 440.
109 """
110
111 __slots__ = ("_kind", "_trimmed_release", "version")
112
113 def __init__(self, version: Version, kind: _BoundaryKind) -> None:
114 self.version = version
115 self._kind = kind
116 self._trimmed_release = _trim_release(version.release)
117
118 def _is_family(self, other: Version) -> bool:
119 """Is ``other`` a version that this boundary sorts above?"""
120 v = self.version
121 if not (
122 other.epoch == v.epoch
123 and _trim_release(other.release) == self._trimmed_release
124 and other.pre == v.pre
125 ):
126 return False
127 if self._kind == _BoundaryKind.AFTER_LOCALS:
128 # Local family: exact same public version (any local label).
129 return other.post == v.post and other.dev == v.dev
130 # Post family: same base + any post-release (or identical).
131 return other.dev == v.dev or other.post is not None
132
133 def __eq__(self, other: object) -> bool:
134 if isinstance(other, _BoundaryVersion):
135 return self.version == other.version and self._kind == other._kind
136 return NotImplemented
137
138 def __lt__(self, other: _BoundaryVersion | Version) -> bool:
139 if isinstance(other, _BoundaryVersion):
140 if self.version != other.version:
141 return self.version < other.version
142 return self._kind.value < other._kind.value
143 return not self._is_family(other) and self.version < other
144
145 def __hash__(self) -> int:
146 return hash((self.version, self._kind))
147
148 def __repr__(self) -> str:
149 return f"{self.__class__.__name__}({self.version!r}, {self._kind.name})"
150
151
152@functools.total_ordering
153class _LowerBound:
154 """Lower bound of a version range.
155
156 A version *v* of ``None`` means unbounded below (-inf).
157 At equal versions, ``[v`` sorts before ``(v`` because an inclusive
158 bound starts earlier.
159 """
160
161 __slots__ = ("inclusive", "version")
162
163 def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:
164 self.version = version
165 self.inclusive = inclusive
166
167 def __eq__(self, other: object) -> bool:
168 if not isinstance(other, _LowerBound):
169 return NotImplemented # pragma: no cover
170 return self.version == other.version and self.inclusive == other.inclusive
171
172 def __lt__(self, other: _LowerBound) -> bool:
173 if not isinstance(other, _LowerBound): # pragma: no cover
174 return NotImplemented
175 # -inf < anything (except -inf).
176 if self.version is None:
177 return other.version is not None
178 if other.version is None:
179 return False
180 if self.version != other.version:
181 return self.version < other.version
182 # [v < (v: inclusive starts earlier.
183 return self.inclusive and not other.inclusive
184
185 def __hash__(self) -> int:
186 return hash((self.version, self.inclusive))
187
188 def __repr__(self) -> str:
189 bracket = "[" if self.inclusive else "("
190 return f"<{self.__class__.__name__} {bracket}{self.version!r}>"
191
192
193@functools.total_ordering
194class _UpperBound:
195 """Upper bound of a version range.
196
197 A version *v* of ``None`` means unbounded above (+inf).
198 At equal versions, ``v)`` sorts before ``v]`` because an exclusive
199 bound ends earlier.
200 """
201
202 __slots__ = ("inclusive", "version")
203
204 def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:
205 self.version = version
206 self.inclusive = inclusive
207
208 def __eq__(self, other: object) -> bool:
209 if not isinstance(other, _UpperBound):
210 return NotImplemented # pragma: no cover
211 return self.version == other.version and self.inclusive == other.inclusive
212
213 def __lt__(self, other: _UpperBound) -> bool:
214 if not isinstance(other, _UpperBound): # pragma: no cover
215 return NotImplemented
216 # Nothing < +inf (except +inf itself).
217 if self.version is None:
218 return False
219 if other.version is None:
220 return True
221 if self.version != other.version:
222 return self.version < other.version
223 # v) < v]: exclusive ends earlier.
224 return not self.inclusive and other.inclusive
225
226 def __hash__(self) -> int:
227 return hash((self.version, self.inclusive))
228
229 def __repr__(self) -> str:
230 bracket = "]" if self.inclusive else ")"
231 return f"<{self.__class__.__name__} {self.version!r}{bracket}>"
232
233
234if typing.TYPE_CHECKING:
235 _VersionOrBoundary = Union[Version, _BoundaryVersion, None]
236
237 #: A single contiguous version range, represented as a
238 #: (lower bound, upper bound) pair.
239 _VersionRange = tuple[_LowerBound, _UpperBound]
240
241_NEG_INF = _LowerBound(None, False)
242_POS_INF = _UpperBound(None, False)
243_FULL_RANGE: tuple[_VersionRange] = ((_NEG_INF, _POS_INF),)
244
245
246def _range_is_empty(lower: _LowerBound, upper: _UpperBound) -> bool:
247 """True when the range defined by *lower* and *upper* contains no versions."""
248 if lower.version is None or upper.version is None:
249 return False
250 if lower.version == upper.version:
251 return not (lower.inclusive and upper.inclusive)
252 return lower.version > upper.version
253
254
255def _intersect_ranges(
256 left: Sequence[_VersionRange],
257 right: Sequence[_VersionRange],
258) -> list[_VersionRange]:
259 """Intersect two sorted, non-overlapping range lists (two-pointer merge)."""
260 result: list[_VersionRange] = []
261 left_index = right_index = 0
262 while left_index < len(left) and right_index < len(right):
263 left_lower, left_upper = left[left_index]
264 right_lower, right_upper = right[right_index]
265
266 lower = max(left_lower, right_lower)
267 upper = min(left_upper, right_upper)
268
269 if not _range_is_empty(lower, upper):
270 result.append((lower, upper))
271
272 # Advance whichever side has the smaller upper bound.
273 if left_upper < right_upper:
274 left_index += 1
275 else:
276 right_index += 1
277
278 return result
279
280
281def _next_prefix_dev0(version: Version) -> Version:
282 """Smallest version in the next prefix: 1.2 -> 1.3.dev0."""
283 release = (*version.release[:-1], version.release[-1] + 1)
284 return Version.from_parts(epoch=version.epoch, release=release, dev=0)
285
286
287def _base_dev0(version: Version) -> Version:
288 """The .dev0 of a version's base release: 1.2 -> 1.2.dev0."""
289 return Version.from_parts(epoch=version.epoch, release=version.release, dev=0)
290
291
292def _coerce_version(version: UnparsedVersion) -> Version | None:
293 if not isinstance(version, Version):
294 try:
295 version = Version(version)
296 except InvalidVersion:
297 return None
298 return version
299
300
301def _public_version(version: Version) -> Version:
302 if version.local is None:
303 return version
304 return version.__replace__(local=None)
305
306
307def _post_base(version: Version) -> Version:
308 """The version that *version* is a post-release of.
309
310 1.0.post1 -> 1.0, 1.0a1.post0 -> 1.0a1, 1.0.post0.dev1 -> 1.0.
311 """
312 return version.__replace__(post=None, dev=None, local=None)
313
314
315def _earliest_prerelease(version: Version) -> Version:
316 """Earliest pre-release of *version*.
317
318 1.2 -> 1.2.dev0, 1.2.post1 -> 1.2.post1.dev0.
319 """
320 return version.__replace__(dev=0, local=None)
321
322
323def _nearest_non_prerelease(
324 v: _VersionOrBoundary,
325) -> Version | None:
326 """Smallest non-pre-release version at or above *v*, or None."""
327 if v is None:
328 return None
329 if isinstance(v, _BoundaryVersion):
330 inner = v.version
331 if inner.is_prerelease:
332 # AFTER_LOCALS(1.0a1) -> nearest non-pre is 1.0
333 return inner.__replace__(pre=None, dev=None, local=None)
334 # AFTER_LOCALS(1.0) -> nearest non-pre is 1.0.post0
335 # AFTER_LOCALS(1.0.post0) -> nearest non-pre is 1.0.post1
336 k = (inner.post + 1) if inner.post is not None else 0
337 return inner.__replace__(post=k, local=None)
338 if not v.is_prerelease:
339 return v
340 # Strip pre/dev to get the final or post-release form.
341 return v.__replace__(pre=None, dev=None, local=None)
342
343
344class InvalidSpecifier(ValueError):
345 """
346 Raised when attempting to create a :class:`Specifier` with a specifier
347 string that is invalid.
348
349 >>> Specifier("lolwat")
350 Traceback (most recent call last):
351 ...
352 packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat'
353 """
354
355
356class BaseSpecifier(metaclass=abc.ABCMeta):
357 __slots__ = ()
358 __match_args__ = ("_str",)
359
360 @property
361 def _str(self) -> str:
362 """Internal property for match_args"""
363 return str(self)
364
365 @abc.abstractmethod
366 def __str__(self) -> str:
367 """
368 Returns the str representation of this Specifier-like object. This
369 should be representative of the Specifier itself.
370 """
371
372 @abc.abstractmethod
373 def __hash__(self) -> int:
374 """
375 Returns a hash value for this Specifier-like object.
376 """
377
378 @abc.abstractmethod
379 def __eq__(self, other: object) -> bool:
380 """
381 Returns a boolean representing whether or not the two Specifier-like
382 objects are equal.
383
384 :param other: The other object to check against.
385 """
386
387 @property
388 @abc.abstractmethod
389 def prereleases(self) -> bool | None:
390 """Whether or not pre-releases as a whole are allowed.
391
392 This can be set to either ``True`` or ``False`` to explicitly enable or disable
393 prereleases or it can be set to ``None`` (the default) to use default semantics.
394 """
395
396 @prereleases.setter # noqa: B027
397 def prereleases(self, value: bool) -> None:
398 """Setter for :attr:`prereleases`.
399
400 :param value: The value to set.
401 """
402
403 @abc.abstractmethod
404 def contains(self, item: str, prereleases: bool | None = None) -> bool:
405 """
406 Determines if the given item is contained within this specifier.
407 """
408
409 @typing.overload
410 def filter(
411 self,
412 iterable: Iterable[UnparsedVersionVar],
413 prereleases: bool | None = None,
414 key: None = ...,
415 ) -> Iterator[UnparsedVersionVar]: ...
416
417 @typing.overload
418 def filter(
419 self,
420 iterable: Iterable[T],
421 prereleases: bool | None = None,
422 key: Callable[[T], UnparsedVersion] = ...,
423 ) -> Iterator[T]: ...
424
425 @abc.abstractmethod
426 def filter(
427 self,
428 iterable: Iterable[Any],
429 prereleases: bool | None = None,
430 key: Callable[[Any], UnparsedVersion] | None = None,
431 ) -> Iterator[Any]:
432 """
433 Takes an iterable of items and filters them so that only items which
434 are contained within this specifier are allowed in it.
435 """
436
437
438class Specifier(BaseSpecifier):
439 """This class abstracts handling of version specifiers.
440
441 .. tip::
442
443 It is generally not required to instantiate this manually. You should instead
444 prefer to work with :class:`SpecifierSet` instead, which can parse
445 comma-separated version specifiers (which is what package metadata contains).
446
447 Instances are safe to serialize with :mod:`pickle`. They use a stable
448 format so the same pickle can be loaded in future packaging releases.
449
450 .. versionchanged:: 26.2
451
452 Added a stable pickle format. Pickles created with packaging 26.2+ can
453 be unpickled with future releases. Backward compatibility with pickles
454 from pip._vendor.packaging < 26.2 is supported but may be removed in a future
455 release.
456 """
457
458 __slots__ = (
459 "_prereleases",
460 "_ranges",
461 "_spec",
462 "_spec_version",
463 "_wildcard_split",
464 )
465
466 _specifier_regex_str = r"""
467 (?:
468 (?:
469 # The identity operators allow for an escape hatch that will
470 # do an exact string match of the version you wish to install.
471 # This will not be parsed by PEP 440 and we cannot determine
472 # any semantic meaning from it. This operator is discouraged
473 # but included entirely as an escape hatch.
474 === # Only match for the identity operator
475 \s*
476 [^\s;)]* # The arbitrary version can be just about anything,
477 # we match everything except for whitespace, a
478 # semi-colon for marker support, and a closing paren
479 # since versions can be enclosed in them.
480 )
481 |
482 (?:
483 # The (non)equality operators allow for wild card and local
484 # versions to be specified so we have to define these two
485 # operators separately to enable that.
486 (?:==|!=) # Only match for equals and not equals
487
488 \s*
489 v?
490 (?:[0-9]+!)? # epoch
491 [0-9]+(?:\.[0-9]+)* # release
492
493 # You cannot use a wild card and a pre-release, post-release, a dev or
494 # local version together so group them with a | and make them optional.
495 (?:
496 \.\* # Wild card syntax of .*
497 |
498 (?a: # pre release
499 [-_\.]?
500 (alpha|beta|preview|pre|a|b|c|rc)
501 [-_\.]?
502 [0-9]*
503 )?
504 (?a: # post release
505 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
506 )?
507 (?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
508 (?a:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
509 )?
510 )
511 |
512 (?:
513 # The compatible operator requires at least two digits in the
514 # release segment.
515 (?:~=) # Only match for the compatible operator
516
517 \s*
518 v?
519 (?:[0-9]+!)? # epoch
520 [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
521 (?: # pre release
522 [-_\.]?
523 (alpha|beta|preview|pre|a|b|c|rc)
524 [-_\.]?
525 [0-9]*
526 )?
527 (?: # post release
528 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
529 )?
530 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
531 )
532 |
533 (?:
534 # All other operators only allow a sub set of what the
535 # (non)equality operators do. Specifically they do not allow
536 # local versions to be specified nor do they allow the prefix
537 # matching wild cards.
538 (?:<=|>=|<|>)
539
540 \s*
541 v?
542 (?:[0-9]+!)? # epoch
543 [0-9]+(?:\.[0-9]+)* # release
544 (?a: # pre release
545 [-_\.]?
546 (alpha|beta|preview|pre|a|b|c|rc)
547 [-_\.]?
548 [0-9]*
549 )?
550 (?a: # post release
551 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
552 )?
553 (?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
554 )
555 )
556 """
557
558 _regex = re.compile(
559 r"\s*" + _specifier_regex_str + r"\s*", re.VERBOSE | re.IGNORECASE
560 )
561
562 _operators: Final = {
563 "~=": "compatible",
564 "==": "equal",
565 "!=": "not_equal",
566 "<=": "less_than_equal",
567 ">=": "greater_than_equal",
568 "<": "less_than",
569 ">": "greater_than",
570 "===": "arbitrary",
571 }
572
573 def __init__(self, spec: str = "", prereleases: bool | None = None) -> None:
574 """Initialize a Specifier instance.
575
576 :param spec:
577 The string representation of a specifier which will be parsed and
578 normalized before use.
579 :param prereleases:
580 This tells the specifier if it should accept prerelease versions if
581 applicable or not. The default of ``None`` will autodetect it from the
582 given specifiers.
583 :raises InvalidSpecifier:
584 If the given specifier is invalid (i.e. bad syntax).
585 """
586 if not self._regex.fullmatch(spec):
587 raise InvalidSpecifier(f"Invalid specifier: {spec!r}")
588
589 spec = spec.strip()
590 if spec.startswith("==="):
591 operator, version = spec[:3], spec[3:].strip()
592 elif spec.startswith(("~=", "==", "!=", "<=", ">=")):
593 operator, version = spec[:2], spec[2:].strip()
594 else:
595 operator, version = spec[:1], spec[1:].strip()
596
597 self._spec: tuple[str, str] = (operator, version)
598
599 # Store whether or not this Specifier should accept prereleases
600 self._prereleases = prereleases
601
602 # Specifier version cache
603 self._spec_version: tuple[str, Version] | None = None
604
605 # Populated on first wildcard (==X.*) comparison
606 self._wildcard_split: tuple[list[str], int] | None = None
607
608 # Version range cache (populated by _to_ranges)
609 self._ranges: Sequence[_VersionRange] | None = None
610
611 def _get_spec_version(self, version: str) -> Version | None:
612 """One element cache, as only one spec Version is needed per Specifier."""
613 if self._spec_version is not None and self._spec_version[0] == version:
614 return self._spec_version[1]
615
616 version_specifier = _coerce_version(version)
617 if version_specifier is None:
618 return None
619
620 self._spec_version = (version, version_specifier)
621 return version_specifier
622
623 def _require_spec_version(self, version: str) -> Version:
624 """Get spec version, asserting it's valid (not for === operator).
625
626 This method should only be called for operators where version
627 strings are guaranteed to be valid PEP 440 versions (not ===).
628 """
629 spec_version = self._get_spec_version(version)
630 assert spec_version is not None
631 return spec_version
632
633 def _to_ranges(self) -> Sequence[_VersionRange]:
634 """Convert this specifier to sorted, non-overlapping version ranges.
635
636 Each standard operator maps to one or two ranges. ``===`` is
637 modeled as full range (actual check done separately). Cached.
638 """
639 if self._ranges is not None:
640 return self._ranges
641
642 op = self.operator
643 ver_str = self.version
644
645 if op == "===":
646 self._ranges = _FULL_RANGE
647 return _FULL_RANGE
648
649 if ver_str.endswith(".*"):
650 result = self._wildcard_ranges(op, ver_str)
651 else:
652 result = self._standard_ranges(op, ver_str)
653
654 self._ranges = result
655 return result
656
657 def _wildcard_ranges(self, op: str, ver_str: str) -> list[_VersionRange]:
658 # ==1.2.* -> [1.2.dev0, 1.3.dev0); !=1.2.* -> complement.
659 base = self._require_spec_version(ver_str[:-2])
660 lower = _base_dev0(base)
661 upper = _next_prefix_dev0(base)
662 if op == "==":
663 return [(_LowerBound(lower, True), _UpperBound(upper, False))]
664 # !=
665 return [
666 (_NEG_INF, _UpperBound(lower, False)),
667 (_LowerBound(upper, True), _POS_INF),
668 ]
669
670 def _standard_ranges(self, op: str, ver_str: str) -> list[_VersionRange]:
671 v = self._require_spec_version(ver_str)
672
673 if op == ">=":
674 return [(_LowerBound(v, True), _POS_INF)]
675
676 if op == "<=":
677 return [
678 (
679 _NEG_INF,
680 _UpperBound(_BoundaryVersion(v, _BoundaryKind.AFTER_LOCALS), True),
681 )
682 ]
683
684 if op == ">":
685 if v.dev is not None:
686 # >V.devN: dev versions have no post-releases, so the
687 # next real version is V.dev(N+1).
688 lower_ver = v.__replace__(dev=v.dev + 1, local=None)
689 return [(_LowerBound(lower_ver, True), _POS_INF)]
690 if v.post is not None:
691 # >V.postN: next real version is V.post(N+1).dev0.
692 lower_ver = v.__replace__(post=v.post + 1, dev=0, local=None)
693 return [(_LowerBound(lower_ver, True), _POS_INF)]
694 # >V (final or pre-release): skip V+local and all V.postN.
695 return [
696 (
697 _LowerBound(_BoundaryVersion(v, _BoundaryKind.AFTER_POSTS), False),
698 _POS_INF,
699 )
700 ]
701
702 if op == "<":
703 # <V excludes prereleases of V when V is not a prerelease.
704 # V.dev0 is the earliest prerelease of V (final, post, etc.).
705 bound = v if v.is_prerelease else v.__replace__(dev=0, local=None)
706 if bound <= _MIN_VERSION:
707 return []
708 return [(_NEG_INF, _UpperBound(bound, False))]
709
710 # ==, !=: local versions of V match when spec has no local segment.
711 has_local = "+" in ver_str
712 after_locals = _BoundaryVersion(v, _BoundaryKind.AFTER_LOCALS)
713 upper = v if has_local else after_locals
714
715 if op == "==":
716 return [(_LowerBound(v, True), _UpperBound(upper, True))]
717
718 if op == "!=":
719 return [
720 (_NEG_INF, _UpperBound(v, False)),
721 (_LowerBound(upper, False), _POS_INF),
722 ]
723
724 if op == "~=":
725 prefix = v.__replace__(release=v.release[:-1])
726 return [
727 (_LowerBound(v, True), _UpperBound(_next_prefix_dev0(prefix), False))
728 ]
729
730 raise ValueError(f"Unknown operator: {op!r}") # pragma: no cover
731
732 @property
733 def prereleases(self) -> bool | None:
734 # If there is an explicit prereleases set for this, then we'll just
735 # blindly use that.
736 if self._prereleases is not None:
737 return self._prereleases
738
739 # Only the "!=" operator does not imply prereleases when
740 # the version in the specifier is a prerelease.
741 operator, version_str = self._spec
742 if operator == "!=":
743 return False
744
745 # The == specifier with trailing .* cannot include prereleases
746 # e.g. "==1.0a1.*" is not valid.
747 if operator == "==" and version_str.endswith(".*"):
748 return False
749
750 # "===" can have arbitrary string versions, so we cannot parse
751 # those, we take prereleases as unknown (None) for those.
752 version = self._get_spec_version(version_str)
753 if version is None:
754 return None
755
756 # For all other operators, use the check if spec Version
757 # object implies pre-releases.
758 return version.is_prerelease
759
760 @prereleases.setter
761 def prereleases(self, value: bool | None) -> None:
762 self._prereleases = value
763
764 def __getstate__(self) -> tuple[tuple[str, str], bool | None]:
765 # Return state as a 2-item tuple for compactness:
766 # ((operator, version), prereleases)
767 # Cache members are excluded and will be recomputed on demand.
768 return (self._spec, self._prereleases)
769
770 def __setstate__(self, state: object) -> None:
771 # Always discard cached values - they will be recomputed on demand.
772 self._spec_version = None
773 self._wildcard_split = None
774 self._ranges = None
775
776 if isinstance(state, tuple):
777 if len(state) == 2:
778 # New format (26.2+): ((operator, version), prereleases)
779 spec, prereleases = state
780 if _validate_spec(spec) and _validate_pre(prereleases):
781 self._spec = spec
782 self._prereleases = prereleases
783 return
784 if len(state) == 2 and isinstance(state[1], dict):
785 # Format (packaging 26.0-26.1): (None, {slot: value}).
786 _, slot_dict = state
787 spec = slot_dict.get("_spec")
788 prereleases = slot_dict.get("_prereleases", "invalid")
789 if _validate_spec(spec) and _validate_pre(prereleases):
790 self._spec = spec
791 self._prereleases = prereleases
792 return
793 if isinstance(state, dict):
794 # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
795 spec = state.get("_spec")
796 prereleases = state.get("_prereleases", "invalid")
797 if _validate_spec(spec) and _validate_pre(prereleases):
798 self._spec = spec
799 self._prereleases = prereleases
800 return
801
802 raise TypeError(f"Cannot restore Specifier from {state!r}")
803
804 @property
805 def operator(self) -> str:
806 """The operator of this specifier.
807
808 >>> Specifier("==1.2.3").operator
809 '=='
810 """
811 return self._spec[0]
812
813 @property
814 def version(self) -> str:
815 """The version of this specifier.
816
817 >>> Specifier("==1.2.3").version
818 '1.2.3'
819 """
820 return self._spec[1]
821
822 def __repr__(self) -> str:
823 """A representation of the Specifier that shows all internal state.
824
825 >>> Specifier('>=1.0.0')
826 <Specifier('>=1.0.0')>
827 >>> Specifier('>=1.0.0', prereleases=False)
828 <Specifier('>=1.0.0', prereleases=False)>
829 >>> Specifier('>=1.0.0', prereleases=True)
830 <Specifier('>=1.0.0', prereleases=True)>
831 """
832 pre = (
833 f", prereleases={self.prereleases!r}"
834 if self._prereleases is not None
835 else ""
836 )
837
838 return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
839
840 def __str__(self) -> str:
841 """A string representation of the Specifier that can be round-tripped.
842
843 >>> str(Specifier('>=1.0.0'))
844 '>=1.0.0'
845 >>> str(Specifier('>=1.0.0', prereleases=False))
846 '>=1.0.0'
847 """
848 return "{}{}".format(*self._spec)
849
850 @property
851 def _canonical_spec(self) -> tuple[str, str]:
852 operator, version = self._spec
853 if operator == "===" or version.endswith(".*"):
854 return operator, version
855
856 spec_version = self._require_spec_version(version)
857
858 canonical_version = canonicalize_version(
859 spec_version, strip_trailing_zero=(operator != "~=")
860 )
861
862 return operator, canonical_version
863
864 def __hash__(self) -> int:
865 return hash(self._canonical_spec)
866
867 def __eq__(self, other: object) -> bool:
868 """Whether or not the two Specifier-like objects are equal.
869
870 :param other: The other object to check against.
871
872 The value of :attr:`prereleases` is ignored.
873
874 >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0")
875 True
876 >>> (Specifier("==1.2.3", prereleases=False) ==
877 ... Specifier("==1.2.3", prereleases=True))
878 True
879 >>> Specifier("==1.2.3") == "==1.2.3"
880 True
881 >>> Specifier("==1.2.3") == Specifier("==1.2.4")
882 False
883 >>> Specifier("==1.2.3") == Specifier("~=1.2.3")
884 False
885 """
886 if isinstance(other, str):
887 try:
888 other = self.__class__(str(other))
889 except InvalidSpecifier:
890 return NotImplemented
891 elif not isinstance(other, self.__class__):
892 return NotImplemented
893
894 return self._canonical_spec == other._canonical_spec
895
896 def _get_operator(self, op: str) -> CallableOperator:
897 operator_callable: CallableOperator = getattr(
898 self, f"_compare_{self._operators[op]}"
899 )
900 return operator_callable
901
902 def _compare_compatible(self, prospective: Version, spec: str) -> bool:
903 # Compatible releases have an equivalent combination of >= and ==. That
904 # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
905 # implement this in terms of the other specifiers instead of
906 # implementing it ourselves. The only thing we need to do is construct
907 # the other specifiers.
908
909 # We want everything but the last item in the version, but we want to
910 # ignore suffix segments.
911 prefix = _version_join(
912 list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1]
913 )
914
915 # Add the prefix notation to the end of our string
916 prefix += ".*"
917
918 return (self._compare_greater_than_equal(prospective, spec)) and (
919 self._compare_equal(prospective, prefix)
920 )
921
922 def _get_wildcard_split(self, spec: str) -> tuple[list[str], int]:
923 """Cached split of a wildcard spec into components and numeric length.
924
925 >>> Specifier("==1.*")._get_wildcard_split("1.*")
926 (['0', '1'], 2)
927 >>> Specifier("==3.10.*")._get_wildcard_split("3.10.*")
928 (['0', '3', '10'], 3)
929 """
930 wildcard_split = self._wildcard_split
931 if wildcard_split is None:
932 normalized = canonicalize_version(spec[:-2], strip_trailing_zero=False)
933 split_spec = _version_split(normalized)
934 wildcard_split = (split_spec, _numeric_prefix_len(split_spec))
935 self._wildcard_split = wildcard_split
936 return wildcard_split
937
938 def _compare_equal(self, prospective: Version, spec: str) -> bool:
939 # We need special logic to handle prefix matching
940 if spec.endswith(".*"):
941 split_spec, spec_numeric_len = self._get_wildcard_split(spec)
942
943 # In the case of prefix matching we want to ignore local segment.
944 normalized_prospective = canonicalize_version(
945 _public_version(prospective), strip_trailing_zero=False
946 )
947 # Split the prospective version out by bangs and dots, and pretend
948 # that there is an implicit dot in between a release segment and
949 # a pre-release segment.
950 split_prospective = _version_split(normalized_prospective)
951
952 # 0-pad the prospective version before shortening it to get the correct
953 # shortened version.
954 padded_prospective = _left_pad(split_prospective, spec_numeric_len)
955
956 # Shorten the prospective version to be the same length as the spec
957 # so that we can determine if the specifier is a prefix of the
958 # prospective version or not.
959 shortened_prospective = padded_prospective[: len(split_spec)]
960
961 return shortened_prospective == split_spec
962 else:
963 # Convert our spec string into a Version
964 spec_version = self._require_spec_version(spec)
965
966 # If the specifier does not have a local segment, then we want to
967 # act as if the prospective version also does not have a local
968 # segment.
969 if not spec_version.local:
970 prospective = _public_version(prospective)
971
972 return prospective == spec_version
973
974 def _compare_not_equal(self, prospective: Version, spec: str) -> bool:
975 return not self._compare_equal(prospective, spec)
976
977 def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool:
978 # NB: Local version identifiers are NOT permitted in the version
979 # specifier, so local version labels can be universally removed from
980 # the prospective version.
981 return _public_version(prospective) <= self._require_spec_version(spec)
982
983 def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool:
984 # NB: Local version identifiers are NOT permitted in the version
985 # specifier, so local version labels can be universally removed from
986 # the prospective version.
987 return _public_version(prospective) >= self._require_spec_version(spec)
988
989 def _compare_less_than(self, prospective: Version, spec_str: str) -> bool:
990 # Convert our spec to a Version instance, since we'll want to work with
991 # it as a version.
992 spec = self._require_spec_version(spec_str)
993
994 # Check to see if the prospective version is less than the spec
995 # version. If it's not we can short circuit and just return False now
996 # instead of doing extra unneeded work.
997 if not prospective < spec:
998 return False
999
1000 # The spec says: "<V MUST NOT allow a pre-release of the specified
1001 # version unless the specified version is itself a pre-release."
1002 if (
1003 not spec.is_prerelease
1004 and prospective.is_prerelease
1005 and prospective >= _earliest_prerelease(spec)
1006 ):
1007 return False
1008
1009 # If we've gotten to here, it means that prospective version is both
1010 # less than the spec version *and* it's not a pre-release of the same
1011 # version in the spec.
1012 return True
1013
1014 def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool:
1015 # Convert our spec to a Version instance, since we'll want to work with
1016 # it as a version.
1017 spec = self._require_spec_version(spec_str)
1018
1019 # Check to see if the prospective version is greater than the spec
1020 # version. If it's not we can short circuit and just return False now
1021 # instead of doing extra unneeded work.
1022 if not prospective > spec:
1023 return False
1024
1025 # The spec says: ">V MUST NOT allow a post-release of the specified
1026 # version unless the specified version is itself a post-release."
1027 if (
1028 not spec.is_postrelease
1029 and prospective.is_postrelease
1030 and _post_base(prospective) == spec
1031 ):
1032 return False
1033
1034 # Per the spec: ">V MUST NOT match a local version of the specified
1035 # version". A "local version of V" is any version whose public part
1036 # equals V. So >1.0a1 must not match 1.0a1+local, but must still
1037 # match 1.0a2+local.
1038 if prospective.local is not None and _public_version(prospective) == spec:
1039 return False
1040
1041 # If we've gotten to here, it means that prospective version is both
1042 # greater than the spec version *and* it's not a pre-release of the
1043 # same version in the spec.
1044 return True
1045
1046 def _compare_arbitrary(self, prospective: Version | str, spec: str) -> bool:
1047 return str(prospective).lower() == str(spec).lower()
1048
1049 def __contains__(self, item: str | Version) -> bool:
1050 """Return whether or not the item is contained in this specifier.
1051
1052 :param item: The item to check for.
1053
1054 This is used for the ``in`` operator and behaves the same as
1055 :meth:`contains` with no ``prereleases`` argument passed.
1056
1057 >>> "1.2.3" in Specifier(">=1.2.3")
1058 True
1059 >>> Version("1.2.3") in Specifier(">=1.2.3")
1060 True
1061 >>> "1.0.0" in Specifier(">=1.2.3")
1062 False
1063 >>> "1.3.0a1" in Specifier(">=1.2.3")
1064 True
1065 >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)
1066 True
1067 """
1068 return self.contains(item)
1069
1070 def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool:
1071 """Return whether or not the item is contained in this specifier.
1072
1073 :param item:
1074 The item to check for, which can be a version string or a
1075 :class:`Version` instance.
1076 :param prereleases:
1077 Whether or not to match prereleases with this Specifier. If set to
1078 ``None`` (the default), it will follow the recommendation from
1079 :pep:`440` and match prereleases, as there are no other versions.
1080
1081 >>> Specifier(">=1.2.3").contains("1.2.3")
1082 True
1083 >>> Specifier(">=1.2.3").contains(Version("1.2.3"))
1084 True
1085 >>> Specifier(">=1.2.3").contains("1.0.0")
1086 False
1087 >>> Specifier(">=1.2.3").contains("1.3.0a1")
1088 True
1089 >>> Specifier(">=1.2.3", prereleases=False).contains("1.3.0a1")
1090 False
1091 >>> Specifier(">=1.2.3").contains("1.3.0a1")
1092 True
1093 """
1094
1095 return bool(list(self.filter([item], prereleases=prereleases)))
1096
1097 @typing.overload
1098 def filter(
1099 self,
1100 iterable: Iterable[UnparsedVersionVar],
1101 prereleases: bool | None = None,
1102 key: None = ...,
1103 ) -> Iterator[UnparsedVersionVar]: ...
1104
1105 @typing.overload
1106 def filter(
1107 self,
1108 iterable: Iterable[T],
1109 prereleases: bool | None = None,
1110 key: Callable[[T], UnparsedVersion] = ...,
1111 ) -> Iterator[T]: ...
1112
1113 def filter(
1114 self,
1115 iterable: Iterable[Any],
1116 prereleases: bool | None = None,
1117 key: Callable[[Any], UnparsedVersion] | None = None,
1118 ) -> Iterator[Any]:
1119 """Filter items in the given iterable, that match the specifier.
1120
1121 :param iterable:
1122 An iterable that can contain version strings and :class:`Version` instances.
1123 The items in the iterable will be filtered according to the specifier.
1124 :param prereleases:
1125 Whether or not to allow prereleases in the returned iterator. If set to
1126 ``None`` (the default), it will follow the recommendation from :pep:`440`
1127 and match prereleases if there are no other versions.
1128 :param key:
1129 A callable that takes a single argument (an item from the iterable) and
1130 returns a version string or :class:`Version` instance to be used for
1131 filtering.
1132
1133 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
1134 ['1.3']
1135 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")]))
1136 ['1.2.3', '1.3', <Version('1.4')>]
1137 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"]))
1138 ['1.5a1']
1139 >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
1140 ['1.3', '1.5a1']
1141 >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
1142 ['1.3', '1.5a1']
1143 >>> list(Specifier(">=1.2.3").filter(
1144 ... [{"ver": "1.2"}, {"ver": "1.3"}],
1145 ... key=lambda x: x["ver"]))
1146 [{'ver': '1.3'}]
1147 """
1148 prereleases_versions = []
1149 found_non_prereleases = False
1150
1151 # Determine if to include prereleases by default
1152 include_prereleases = (
1153 prereleases if prereleases is not None else self.prereleases
1154 )
1155
1156 # Get the matching operator
1157 operator_callable = self._get_operator(self.operator)
1158
1159 # Filter versions
1160 for version in iterable:
1161 parsed_version = _coerce_version(version if key is None else key(version))
1162 match = False
1163 if parsed_version is None:
1164 # === operator can match arbitrary (non-version) strings
1165 if self.operator == "===" and self._compare_arbitrary(
1166 version, self.version
1167 ):
1168 yield version
1169 elif self.operator == "===":
1170 match = self._compare_arbitrary(
1171 version if key is None else key(version), self.version
1172 )
1173 else:
1174 match = operator_callable(parsed_version, self.version)
1175
1176 if match and parsed_version is not None:
1177 # If it's not a prerelease or prereleases are allowed, yield it directly
1178 if not parsed_version.is_prerelease or include_prereleases:
1179 found_non_prereleases = True
1180 yield version
1181 # Otherwise collect prereleases for potential later use
1182 elif prereleases is None and self._prereleases is not False:
1183 prereleases_versions.append(version)
1184
1185 # If no non-prereleases were found and prereleases weren't
1186 # explicitly forbidden, yield the collected prereleases
1187 if (
1188 not found_non_prereleases
1189 and prereleases is None
1190 and self._prereleases is not False
1191 ):
1192 yield from prereleases_versions
1193
1194
1195_prefix_regex = re.compile(r"([0-9]+)((?:a|b|c|rc)[0-9]+)")
1196
1197
1198def _pep440_filter_prereleases(
1199 iterable: Iterable[Any], key: Callable[[Any], UnparsedVersion] | None
1200) -> Iterator[Any]:
1201 """Filter per PEP 440: exclude prereleases unless no finals exist."""
1202 # Two lists used:
1203 # * all_nonfinal to preserve order if no finals exist
1204 # * arbitrary_strings for streaming when first final found
1205 all_nonfinal: list[Any] = []
1206 arbitrary_strings: list[Any] = []
1207
1208 found_final = False
1209 for item in iterable:
1210 parsed = _coerce_version(item if key is None else key(item))
1211
1212 if parsed is None:
1213 # Arbitrary strings are always included as it is not
1214 # possible to determine if they are prereleases,
1215 # and they have already passed all specifiers.
1216 if found_final:
1217 yield item
1218 else:
1219 arbitrary_strings.append(item)
1220 all_nonfinal.append(item)
1221 continue
1222
1223 if not parsed.is_prerelease:
1224 # Final release found - flush arbitrary strings, then yield
1225 if not found_final:
1226 yield from arbitrary_strings
1227 found_final = True
1228 yield item
1229 continue
1230
1231 # Prerelease - buffer if no finals yet, otherwise skip
1232 if not found_final:
1233 all_nonfinal.append(item)
1234
1235 # No finals found - yield all buffered items
1236 if not found_final:
1237 yield from all_nonfinal
1238
1239
1240def _version_split(version: str) -> list[str]:
1241 """Split version into components.
1242
1243 The split components are intended for version comparison. The logic does
1244 not attempt to retain the original version string, so joining the
1245 components back with :func:`_version_join` may not produce the original
1246 version string.
1247 """
1248 result: list[str] = []
1249
1250 epoch, _, rest = version.rpartition("!")
1251 result.append(epoch or "0")
1252
1253 for item in rest.split("."):
1254 match = _prefix_regex.fullmatch(item)
1255 if match:
1256 result.extend(match.groups())
1257 else:
1258 result.append(item)
1259 return result
1260
1261
1262def _version_join(components: list[str]) -> str:
1263 """Join split version components into a version string.
1264
1265 This function assumes the input came from :func:`_version_split`, where the
1266 first component must be the epoch (either empty or numeric), and all other
1267 components numeric.
1268 """
1269 epoch, *rest = components
1270 return f"{epoch}!{'.'.join(rest)}"
1271
1272
1273def _is_not_suffix(segment: str) -> bool:
1274 return not any(
1275 segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post")
1276 )
1277
1278
1279def _numeric_prefix_len(split: list[str]) -> int:
1280 """Count leading numeric components in a :func:`_version_split` result.
1281
1282 >>> _numeric_prefix_len(["0", "1", "2", "a1"])
1283 3
1284 """
1285 count = 0
1286 for segment in split:
1287 if not segment.isdigit():
1288 break
1289 count += 1
1290 return count
1291
1292
1293def _left_pad(split: list[str], target_numeric_len: int) -> list[str]:
1294 """Pad a :func:`_version_split` result with ``"0"`` segments to reach
1295 ``target_numeric_len`` numeric components. Suffix segments are preserved.
1296
1297 >>> _left_pad(["0", "1", "a1"], 4)
1298 ['0', '1', '0', '0', 'a1']
1299 """
1300 numeric_len = _numeric_prefix_len(split)
1301 pad_needed = target_numeric_len - numeric_len
1302 if pad_needed <= 0:
1303 return split
1304 return [*split[:numeric_len], *(["0"] * pad_needed), *split[numeric_len:]]
1305
1306
1307def _operator_cost(op_entry: tuple[CallableOperator, str, str]) -> int:
1308 """Sort key for Cost Based Ordering of specifier operators in _filter_versions.
1309
1310 Operators run sequentially on a shrinking candidate set, so operators that
1311 reject the most versions should run first to minimize work for later ones.
1312
1313 Tier 0: Exact equality (==, ===), likely to narrow candidates to one version
1314 Tier 1: Range checks (>=, <=, >, <), cheap and usually reject a large portion
1315 Tier 2: Wildcard equality (==.*) and compatible release (~=), more expensive
1316 Tier 3: Exact !=, cheap but rarely rejects
1317 Tier 4: Wildcard !=.*, expensive and rarely rejects
1318 """
1319 _, ver, op = op_entry
1320 if op == "==":
1321 return 0 if not ver.endswith(".*") else 2
1322 if op in (">=", "<=", ">", "<"):
1323 return 1
1324 if op == "~=":
1325 return 2
1326 if op == "!=":
1327 return 3 if not ver.endswith(".*") else 4
1328 if op == "===":
1329 return 0
1330
1331 raise ValueError(f"Unknown operator: {op!r}") # pragma: no cover
1332
1333
1334class SpecifierSet(BaseSpecifier):
1335 """This class abstracts handling of a set of version specifiers.
1336
1337 It can be passed a single specifier (``>=3.0``), a comma-separated list of
1338 specifiers (``>=3.0,!=3.1``), or no specifier at all.
1339
1340 Instances are safe to serialize with :mod:`pickle`. They use a stable
1341 format so the same pickle can be loaded in future packaging
1342 releases.
1343
1344 .. versionchanged:: 26.2
1345
1346 Added a stable pickle format. Pickles created with
1347 packaging 26.2+ can be unpickled with future releases.
1348 Backward compatibility with pickles from
1349 packaging < 26.2 is supported but may be removed in a future
1350 release.
1351 """
1352
1353 __slots__ = (
1354 "_canonicalized",
1355 "_has_arbitrary",
1356 "_is_unsatisfiable",
1357 "_prereleases",
1358 "_resolved_ops",
1359 "_specs",
1360 )
1361
1362 def __init__(
1363 self,
1364 specifiers: str | Iterable[Specifier] = "",
1365 prereleases: bool | None = None,
1366 ) -> None:
1367 """Initialize a SpecifierSet instance.
1368
1369 :param specifiers:
1370 The string representation of a specifier or a comma-separated list of
1371 specifiers which will be parsed and normalized before use.
1372 May also be an iterable of ``Specifier`` instances, which will be used
1373 as is.
1374 :param prereleases:
1375 This tells the SpecifierSet if it should accept prerelease versions if
1376 applicable or not. The default of ``None`` will autodetect it from the
1377 given specifiers.
1378
1379 :raises InvalidSpecifier:
1380 If the given ``specifiers`` are not parseable than this exception will be
1381 raised.
1382 """
1383
1384 if isinstance(specifiers, str):
1385 # Split on `,` to break each individual specifier into its own item, and
1386 # strip each item to remove leading/trailing whitespace.
1387 split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
1388
1389 self._specs: tuple[Specifier, ...] = tuple(map(Specifier, split_specifiers))
1390 # Fast substring check; avoids iterating parsed specs.
1391 self._has_arbitrary = "===" in specifiers
1392 else:
1393 self._specs = tuple(specifiers)
1394 # Substring check works for both Specifier objects and plain
1395 # strings (setuptools passes lists of strings).
1396 self._has_arbitrary = any("===" in str(s) for s in self._specs)
1397
1398 self._canonicalized = len(self._specs) <= 1
1399 self._resolved_ops: list[tuple[CallableOperator, str, str]] | None = None
1400
1401 # Store our prereleases value so we can use it later to determine if
1402 # we accept prereleases or not.
1403 self._prereleases = prereleases
1404
1405 self._is_unsatisfiable: bool | None = None
1406
1407 def _canonical_specs(self) -> tuple[Specifier, ...]:
1408 """Deduplicate, sort, and cache specs for order-sensitive operations."""
1409 if not self._canonicalized:
1410 self._specs = tuple(dict.fromkeys(sorted(self._specs, key=str)))
1411 self._canonicalized = True
1412 self._resolved_ops = None
1413 self._is_unsatisfiable = None
1414 return self._specs
1415
1416 @property
1417 def prereleases(self) -> bool | None:
1418 # If we have been given an explicit prerelease modifier, then we'll
1419 # pass that through here.
1420 if self._prereleases is not None:
1421 return self._prereleases
1422
1423 # If we don't have any specifiers, and we don't have a forced value,
1424 # then we'll just return None since we don't know if this should have
1425 # pre-releases or not.
1426 if not self._specs:
1427 return None
1428
1429 # Otherwise we'll see if any of the given specifiers accept
1430 # prereleases, if any of them do we'll return True, otherwise False.
1431 if any(s.prereleases for s in self._specs):
1432 return True
1433
1434 return None
1435
1436 @prereleases.setter
1437 def prereleases(self, value: bool | None) -> None:
1438 self._prereleases = value
1439 self._is_unsatisfiable = None
1440
1441 def __getstate__(self) -> tuple[tuple[Specifier, ...], bool | None]:
1442 # Return state as a 2-item tuple for compactness:
1443 # (specs, prereleases)
1444 # Cache members are excluded and will be recomputed on demand.
1445 return (self._specs, self._prereleases)
1446
1447 def __setstate__(self, state: object) -> None:
1448 # Always discard cached values - they will be recomputed on demand.
1449 self._resolved_ops = None
1450 self._is_unsatisfiable = None
1451
1452 if isinstance(state, tuple):
1453 if len(state) == 2:
1454 # New format (26.2+): (specs, prereleases)
1455 specs, prereleases = state
1456 if (
1457 isinstance(specs, tuple)
1458 and all(isinstance(s, Specifier) for s in specs)
1459 and _validate_pre(prereleases)
1460 ):
1461 self._specs = specs
1462 self._prereleases = prereleases
1463 self._canonicalized = len(specs) <= 1
1464 self._has_arbitrary = any("===" in str(s) for s in specs)
1465 return
1466 if len(state) == 2 and isinstance(state[1], dict):
1467 # Format (packaging 26.0-26.1): (None, {slot: value}).
1468 _, slot_dict = state
1469 specs = slot_dict.get("_specs", ())
1470 prereleases = slot_dict.get("_prereleases")
1471 # Convert frozenset to tuple (26.0 stored as frozenset)
1472 if isinstance(specs, frozenset):
1473 specs = tuple(sorted(specs, key=str))
1474 if (
1475 isinstance(specs, tuple)
1476 and all(isinstance(s, Specifier) for s in specs)
1477 and _validate_pre(prereleases)
1478 ):
1479 self._specs = specs
1480 self._prereleases = prereleases
1481 self._canonicalized = len(self._specs) <= 1
1482 self._has_arbitrary = any("===" in str(s) for s in self._specs)
1483 return
1484 if isinstance(state, dict):
1485 # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
1486 specs = state.get("_specs", ())
1487 prereleases = state.get("_prereleases")
1488 # Convert frozenset to tuple (26.0 stored as frozenset)
1489 if isinstance(specs, frozenset):
1490 specs = tuple(sorted(specs, key=str))
1491 if (
1492 isinstance(specs, tuple)
1493 and all(isinstance(s, Specifier) for s in specs)
1494 and _validate_pre(prereleases)
1495 ):
1496 self._specs = specs
1497 self._prereleases = prereleases
1498 self._canonicalized = len(self._specs) <= 1
1499 self._has_arbitrary = any("===" in str(s) for s in self._specs)
1500 return
1501
1502 raise TypeError(f"Cannot restore SpecifierSet from {state!r}")
1503
1504 def __repr__(self) -> str:
1505 """A representation of the specifier set that shows all internal state.
1506
1507 Note that the ordering of the individual specifiers within the set may not
1508 match the input string.
1509
1510 >>> SpecifierSet('>=1.0.0,!=2.0.0')
1511 <SpecifierSet('!=2.0.0,>=1.0.0')>
1512 >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)
1513 <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>
1514 >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)
1515 <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>
1516 """
1517 pre = (
1518 f", prereleases={self.prereleases!r}"
1519 if self._prereleases is not None
1520 else ""
1521 )
1522
1523 return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
1524
1525 def __str__(self) -> str:
1526 """A string representation of the specifier set that can be round-tripped.
1527
1528 Note that the ordering of the individual specifiers within the set may not
1529 match the input string.
1530
1531 >>> str(SpecifierSet(">=1.0.0,!=1.0.1"))
1532 '!=1.0.1,>=1.0.0'
1533 >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False))
1534 '!=1.0.1,>=1.0.0'
1535 """
1536 return ",".join(str(s) for s in self._canonical_specs())
1537
1538 def __hash__(self) -> int:
1539 return hash(self._canonical_specs())
1540
1541 def __and__(self, other: SpecifierSet | str) -> SpecifierSet:
1542 """Return a SpecifierSet which is a combination of the two sets.
1543
1544 :param other: The other object to combine with.
1545
1546 >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1'
1547 <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
1548 >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
1549 <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
1550 """
1551 if isinstance(other, str):
1552 other = SpecifierSet(other)
1553 elif not isinstance(other, SpecifierSet):
1554 return NotImplemented
1555
1556 specifier = SpecifierSet()
1557 specifier._specs = self._specs + other._specs
1558 specifier._canonicalized = len(specifier._specs) <= 1
1559 specifier._has_arbitrary = self._has_arbitrary or other._has_arbitrary
1560 specifier._resolved_ops = None
1561
1562 # Combine prerelease settings: use common or non-None value
1563 if self._prereleases is None or self._prereleases == other._prereleases:
1564 specifier._prereleases = other._prereleases
1565 elif other._prereleases is None:
1566 specifier._prereleases = self._prereleases
1567 else:
1568 raise ValueError(
1569 "Cannot combine SpecifierSets with True and False prerelease overrides."
1570 )
1571
1572 return specifier
1573
1574 def __eq__(self, other: object) -> bool:
1575 """Whether or not the two SpecifierSet-like objects are equal.
1576
1577 :param other: The other object to check against.
1578
1579 The value of :attr:`prereleases` is ignored.
1580
1581 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
1582 True
1583 >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
1584 ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
1585 True
1586 >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"
1587 True
1588 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0")
1589 False
1590 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2")
1591 False
1592 """
1593 if isinstance(other, (str, Specifier)):
1594 other = SpecifierSet(str(other))
1595 elif not isinstance(other, SpecifierSet):
1596 return NotImplemented
1597
1598 return self._canonical_specs() == other._canonical_specs()
1599
1600 def __len__(self) -> int:
1601 """Returns the number of specifiers in this specifier set."""
1602 return len(self._specs)
1603
1604 def __iter__(self) -> Iterator[Specifier]:
1605 """
1606 Returns an iterator over all the underlying :class:`Specifier` instances
1607 in this specifier set.
1608
1609 >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str)
1610 [<Specifier('!=1.0.1')>, <Specifier('>=1.0.0')>]
1611 """
1612 return iter(self._specs)
1613
1614 def _get_ranges(self) -> Sequence[_VersionRange]:
1615 """Intersect all specifiers into a single list of version ranges.
1616
1617 Returns an empty list when unsatisfiable. ``===`` specs are
1618 modeled as full range; string matching is checked separately
1619 by :meth:`_check_arbitrary_unsatisfiable`.
1620 """
1621 specs = self._specs
1622
1623 result: Sequence[_VersionRange] | None = None
1624 for s in specs:
1625 if result is None:
1626 result = s._to_ranges()
1627 else:
1628 result = _intersect_ranges(result, s._to_ranges())
1629 if not result:
1630 break
1631
1632 if result is None: # pragma: no cover
1633 raise RuntimeError("_get_ranges called with no specs")
1634 return result
1635
1636 def is_unsatisfiable(self) -> bool:
1637 """Check whether this specifier set can never be satisfied.
1638
1639 Returns True if no version can satisfy all specifiers simultaneously.
1640
1641 >>> SpecifierSet(">=2.0,<1.0").is_unsatisfiable()
1642 True
1643 >>> SpecifierSet(">=1.0,<2.0").is_unsatisfiable()
1644 False
1645 >>> SpecifierSet("").is_unsatisfiable()
1646 False
1647 >>> SpecifierSet("==1.0,!=1.0").is_unsatisfiable()
1648 True
1649 """
1650 cached = self._is_unsatisfiable
1651 if cached is not None:
1652 return cached
1653
1654 if not self._specs:
1655 self._is_unsatisfiable = False
1656 return False
1657
1658 result = not self._get_ranges()
1659
1660 if not result:
1661 result = self._check_arbitrary_unsatisfiable()
1662
1663 if not result and self.prereleases is False:
1664 result = self._check_prerelease_only_ranges()
1665
1666 self._is_unsatisfiable = result
1667 return result
1668
1669 def _check_prerelease_only_ranges(self) -> bool:
1670 """With prereleases=False, check if every range contains only
1671 pre-release versions (which would be excluded from matching)."""
1672 for lower, upper in self._get_ranges():
1673 nearest = _nearest_non_prerelease(lower.version)
1674 if nearest is None:
1675 return False
1676 if upper.version is None or nearest < upper.version:
1677 return False
1678 if nearest == upper.version and upper.inclusive:
1679 return False
1680 return True
1681
1682 def _check_arbitrary_unsatisfiable(self) -> bool:
1683 """Check === (arbitrary equality) specs for unsatisfiability.
1684
1685 === uses case-insensitive string comparison, so the only candidate
1686 that can match ``===V`` is the literal string V. This method
1687 checks whether that candidate is excluded by other specifiers.
1688 """
1689 arbitrary = [s for s in self._specs if s.operator == "==="]
1690 if not arbitrary:
1691 return False
1692
1693 # Multiple === must agree on the same string (case-insensitive).
1694 first = arbitrary[0].version.lower()
1695 if any(s.version.lower() != first for s in arbitrary[1:]):
1696 return True
1697
1698 # The sole candidate is the === version string. Check whether
1699 # it can satisfy every standard spec.
1700 candidate = _coerce_version(arbitrary[0].version)
1701
1702 # With prereleases=False, a prerelease candidate is excluded
1703 # by contains() before the === string check even runs.
1704 if (
1705 self.prereleases is False
1706 and candidate is not None
1707 and candidate.is_prerelease
1708 ):
1709 return True
1710
1711 standard = [s for s in self._specs if s.operator != "==="]
1712 if not standard:
1713 return False
1714
1715 if candidate is None:
1716 # Unparsable string cannot satisfy any standard spec.
1717 return True
1718
1719 return not all(s.contains(candidate) for s in standard)
1720
1721 def __contains__(self, item: UnparsedVersion) -> bool:
1722 """Return whether or not the item is contained in this specifier.
1723
1724 :param item: The item to check for.
1725
1726 This is used for the ``in`` operator and behaves the same as
1727 :meth:`contains` with no ``prereleases`` argument passed.
1728
1729 >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1")
1730 True
1731 >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1")
1732 True
1733 >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1")
1734 False
1735 >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1")
1736 True
1737 >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)
1738 True
1739 """
1740 return self.contains(item)
1741
1742 def contains(
1743 self,
1744 item: UnparsedVersion,
1745 prereleases: bool | None = None,
1746 installed: bool | None = None,
1747 ) -> bool:
1748 """Return whether or not the item is contained in this SpecifierSet.
1749
1750 :param item:
1751 The item to check for, which can be a version string or a
1752 :class:`Version` instance.
1753 :param prereleases:
1754 Whether or not to match prereleases with this SpecifierSet. If set to
1755 ``None`` (the default), it will follow the recommendation from :pep:`440`
1756 and match prereleases, as there are no other versions.
1757 :param installed:
1758 Whether or not the item is installed. If set to ``True``, it will
1759 accept prerelease versions even if the specifier does not allow them.
1760
1761 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3")
1762 True
1763 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3"))
1764 True
1765 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1")
1766 False
1767 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1")
1768 True
1769 >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False).contains("1.3.0a1")
1770 False
1771 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True)
1772 True
1773 """
1774 version = _coerce_version(item)
1775
1776 if version is not None and installed and version.is_prerelease:
1777 prereleases = True
1778
1779 # When item is a string and === is involved, keep it as-is
1780 # so the comparison isn't done against the normalized form.
1781 if version is None or (self._has_arbitrary and not isinstance(item, Version)):
1782 check_item = item
1783 else:
1784 check_item = version
1785 return bool(list(self.filter([check_item], prereleases=prereleases)))
1786
1787 @typing.overload
1788 def filter(
1789 self,
1790 iterable: Iterable[UnparsedVersionVar],
1791 prereleases: bool | None = None,
1792 key: None = ...,
1793 ) -> Iterator[UnparsedVersionVar]: ...
1794
1795 @typing.overload
1796 def filter(
1797 self,
1798 iterable: Iterable[T],
1799 prereleases: bool | None = None,
1800 key: Callable[[T], UnparsedVersion] = ...,
1801 ) -> Iterator[T]: ...
1802
1803 def filter(
1804 self,
1805 iterable: Iterable[Any],
1806 prereleases: bool | None = None,
1807 key: Callable[[Any], UnparsedVersion] | None = None,
1808 ) -> Iterator[Any]:
1809 """Filter items in the given iterable, that match the specifiers in this set.
1810
1811 :param iterable:
1812 An iterable that can contain version strings and :class:`Version` instances.
1813 The items in the iterable will be filtered according to the specifier.
1814 :param prereleases:
1815 Whether or not to allow prereleases in the returned iterator. If set to
1816 ``None`` (the default), it will follow the recommendation from :pep:`440`
1817 and match prereleases if there are no other versions.
1818 :param key:
1819 A callable that takes a single argument (an item from the iterable) and
1820 returns a version string or :class:`Version` instance to be used for
1821 filtering.
1822
1823 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
1824 ['1.3']
1825 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")]))
1826 ['1.3', <Version('1.4')>]
1827 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"]))
1828 ['1.5a1']
1829 >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
1830 ['1.3', '1.5a1']
1831 >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
1832 ['1.3', '1.5a1']
1833 >>> list(SpecifierSet(">=1.2.3").filter(
1834 ... [{"ver": "1.2"}, {"ver": "1.3"}],
1835 ... key=lambda x: x["ver"]))
1836 [{'ver': '1.3'}]
1837
1838 An "empty" SpecifierSet will filter items based on the presence of prerelease
1839 versions in the set.
1840
1841 >>> list(SpecifierSet("").filter(["1.3", "1.5a1"]))
1842 ['1.3']
1843 >>> list(SpecifierSet("").filter(["1.5a1"]))
1844 ['1.5a1']
1845 >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"]))
1846 ['1.3', '1.5a1']
1847 >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True))
1848 ['1.3', '1.5a1']
1849 """
1850 # Determine if we're forcing a prerelease or not, if we're not forcing
1851 # one for this particular filter call, then we'll use whatever the
1852 # SpecifierSet thinks for whether or not we should support prereleases.
1853 if prereleases is None and self.prereleases is not None:
1854 prereleases = self.prereleases
1855
1856 # Filter versions that match all specifiers using Cost Based Ordering.
1857 if self._specs:
1858 # When prereleases is None, we need to let all versions through
1859 # the individual filters, then decide about prereleases at the end
1860 # based on whether any non-prereleases matched ALL specs.
1861
1862 # Fast path: single specifier, delegate directly.
1863 if len(self._specs) == 1:
1864 filtered = self._specs[0].filter(
1865 iterable,
1866 prereleases=True if prereleases is None else prereleases,
1867 key=key,
1868 )
1869 else:
1870 filtered = self._filter_versions(
1871 iterable,
1872 key,
1873 prereleases=True if prereleases is None else prereleases,
1874 )
1875
1876 if prereleases is not None:
1877 return filtered
1878
1879 return _pep440_filter_prereleases(filtered, key)
1880
1881 # Handle Empty SpecifierSet.
1882 if prereleases is True:
1883 return iter(iterable)
1884
1885 if prereleases is False:
1886 return (
1887 item
1888 for item in iterable
1889 if (
1890 (version := _coerce_version(item if key is None else key(item)))
1891 is None
1892 or not version.is_prerelease
1893 )
1894 )
1895
1896 # PEP 440: exclude prereleases unless no final releases matched
1897 return _pep440_filter_prereleases(iterable, key)
1898
1899 def _filter_versions(
1900 self,
1901 iterable: Iterable[Any],
1902 key: Callable[[Any], UnparsedVersion] | None,
1903 prereleases: bool | None = None,
1904 ) -> Iterator[Any]:
1905 """Filter versions against all specifiers in a single pass.
1906
1907 Uses Cost Based Ordering: specifiers are sorted by _operator_cost so
1908 that cheap range operators reject versions early, avoiding expensive
1909 wildcard or compatible operators on versions that would have been
1910 rejected anyway.
1911 """
1912 # Pre-resolve operators and sort (cached after first call).
1913 if self._resolved_ops is None:
1914 self._resolved_ops = sorted(
1915 (
1916 (spec._get_operator(spec.operator), spec.version, spec.operator)
1917 for spec in self._specs
1918 ),
1919 key=_operator_cost,
1920 )
1921 ops = self._resolved_ops
1922 exclude_prereleases = prereleases is False
1923
1924 for item in iterable:
1925 parsed = _coerce_version(item if key is None else key(item))
1926
1927 if parsed is None:
1928 # Only === can match non-parseable versions.
1929 if all(
1930 op == "===" and str(item).lower() == ver.lower()
1931 for _, ver, op in ops
1932 ):
1933 yield item
1934 elif exclude_prereleases and parsed.is_prerelease:
1935 pass
1936 elif all(
1937 str(item if key is None else key(item)).lower() == ver.lower()
1938 if op == "==="
1939 else op_fn(parsed, ver)
1940 for op_fn, ver, op in ops
1941 ):
1942 # Short-circuits on the first failing operator.
1943 yield item