]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/packaging/specifiers.py
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.
7 from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier
8 from packaging.version import Version
26 from .utils
import canonicalize_version
27 from .version
import Version
29 UnparsedVersion
= Union
[Version
, str]
30 UnparsedVersionVar
= TypeVar("UnparsedVersionVar", bound
=UnparsedVersion
)
31 CallableOperator
= Callable
[[Version
, str], bool]
34 def _coerce_version(version
: UnparsedVersion
) -> Version
:
35 if not isinstance(version
, Version
):
36 version
= Version(version
)
40 class InvalidSpecifier(ValueError):
42 Raised when attempting to create a :class:`Specifier` with a specifier
43 string that is invalid.
45 >>> Specifier("lolwat")
46 Traceback (most recent call last):
48 packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat'
52 class BaseSpecifier(metaclass
=abc
.ABCMeta
):
54 def __str__(self
) -> str:
56 Returns the str representation of this Specifier-like object. This
57 should be representative of the Specifier itself.
61 def __hash__(self
) -> int:
63 Returns a hash value for this Specifier-like object.
67 def __eq__(self
, other
: object) -> bool:
69 Returns a boolean representing whether or not the two Specifier-like
72 :param other: The other object to check against.
77 def prereleases(self
) -> Optional
[bool]:
78 """Whether or not pre-releases as a whole are allowed.
80 This can be set to either ``True`` or ``False`` to explicitly enable or disable
81 prereleases or it can be set to ``None`` (the default) to use default semantics.
85 def prereleases(self
, value
: bool) -> None:
86 """Setter for :attr:`prereleases`.
88 :param value: The value to set.
92 def contains(self
, item
: str, prereleases
: Optional
[bool] = None) -> bool:
94 Determines if the given item is contained within this specifier.
99 self
, iterable
: Iterable
[UnparsedVersionVar
], prereleases
: Optional
[bool] = None
100 ) -> Iterator
[UnparsedVersionVar
]:
102 Takes an iterable of items and filters them so that only items which
103 are contained within this specifier are allowed in it.
107 class Specifier(BaseSpecifier
):
108 """This class abstracts handling of version specifiers.
112 It is generally not required to instantiate this manually. You should instead
113 prefer to work with :class:`SpecifierSet` instead, which can parse
114 comma-separated version specifiers (which is what package metadata contains).
117 _operator_regex_str
= r
"""
118 (?P<operator>(~=|==|!=|<=|>=|<|>|===))
120 _version_regex_str
= r
"""
123 # The identity operators allow for an escape hatch that will
124 # do an exact string match of the version you wish to install.
125 # This will not be parsed by PEP 440 and we cannot determine
126 # any semantic meaning from it. This operator is discouraged
127 # but included entirely as an escape hatch.
128 (?<====) # Only match for the identity operator
130 [^\s;)]* # The arbitrary version can be just about anything,
131 # we match everything except for whitespace, a
132 # semi-colon for marker support, and a closing paren
133 # since versions can be enclosed in them.
137 # The (non)equality operators allow for wild card and local
138 # versions to be specified so we have to define these two
139 # operators separately to enable that.
140 (?<===|!=) # Only match for equals and not equals
145 [0-9]+(?:\.[0-9]+)* # release
147 # You cannot use a wild card and a pre-release, post-release, a dev or
148 # local version together so group them with a | and make them optional.
150 \.\* # Wild card syntax of .*
154 (alpha|beta|preview|pre|a|b|c|rc)
159 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
161 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
162 (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
167 # The compatible operator requires at least two digits in the
169 (?<=~=) # Only match for the compatible operator
174 [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
177 (alpha|beta|preview|pre|a|b|c|rc)
182 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
184 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
188 # All other operators only allow a sub set of what the
189 # (non)equality operators do. Specifically they do not allow
190 # local versions to be specified nor do they allow the prefix
191 # matching wild cards.
192 (?<!==|!=|~=) # We have special cases for these
193 # operators so we want to make sure they
199 [0-9]+(?:\.[0-9]+)* # release
202 (alpha|beta|preview|pre|a|b|c|rc)
207 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
209 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
215 r
"^\s*" + _operator_regex_str
+ _version_regex_str
+ r
"\s*$",
216 re
.VERBOSE | re
.IGNORECASE
,
223 "<=": "less_than_equal",
224 ">=": "greater_than_equal",
230 def __init__(self
, spec
: str = "", prereleases
: Optional
[bool] = None) -> None:
231 """Initialize a Specifier instance.
234 The string representation of a specifier which will be parsed and
235 normalized before use.
237 This tells the specifier if it should accept prerelease versions if
238 applicable or not. The default of ``None`` will autodetect it from the
240 :raises InvalidSpecifier:
241 If the given specifier is invalid (i.e. bad syntax).
243 match
= self
._regex
.search(spec
)
245 raise InvalidSpecifier(f
"Invalid specifier: '{spec}'")
247 self
._spec
: Tuple
[str, str] = (
248 match
.group("operator").strip(),
249 match
.group("version").strip(),
252 # Store whether or not this Specifier should accept prereleases
253 self
._prereleases
= prereleases
255 # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515
256 @property # type: ignore[override]
257 def prereleases(self
) -> bool:
258 # If there is an explicit prereleases set for this, then we'll just
260 if self
._prereleases
is not None:
261 return self
._prereleases
263 # Look at all of our specifiers and determine if they are inclusive
264 # operators, and if they are if they are including an explicit
266 operator
, version
= self
._spec
267 if operator
in ["==", ">=", "<=", "~=", "==="]:
268 # The == specifier can include a trailing .*, if it does we
269 # want to remove before parsing.
270 if operator
== "==" and version
.endswith(".*"):
271 version
= version
[:-2]
273 # Parse the version, and if it is a pre-release than this
274 # specifier allows pre-releases.
275 if Version(version
).is_prerelease
:
281 def prereleases(self
, value
: bool) -> None:
282 self
._prereleases
= value
285 def operator(self
) -> str:
286 """The operator of this specifier.
288 >>> Specifier("==1.2.3").operator
294 def version(self
) -> str:
295 """The version of this specifier.
297 >>> Specifier("==1.2.3").version
302 def __repr__(self
) -> str:
303 """A representation of the Specifier that shows all internal state.
305 >>> Specifier('>=1.0.0')
306 <Specifier('>=1.0.0')>
307 >>> Specifier('>=1.0.0', prereleases=False)
308 <Specifier('>=1.0.0', prereleases=False)>
309 >>> Specifier('>=1.0.0', prereleases=True)
310 <Specifier('>=1.0.0', prereleases=True)>
313 f
", prereleases={self.prereleases!r}"
314 if self
._prereleases
is not None
318 return f
"<{self.__class__.__name__}({str(self)!r}{pre})>"
320 def __str__(self
) -> str:
321 """A string representation of the Specifier that can be round-tripped.
323 >>> str(Specifier('>=1.0.0'))
325 >>> str(Specifier('>=1.0.0', prereleases=False))
328 return "{}{}".format(*self
._spec
)
331 def _canonical_spec(self
) -> Tuple
[str, str]:
332 canonical_version
= canonicalize_version(
334 strip_trailing_zero
=(self
._spec
[0] != "~="),
336 return self
._spec
[0], canonical_version
338 def __hash__(self
) -> int:
339 return hash(self
._canonical
_spec
)
341 def __eq__(self
, other
: object) -> bool:
342 """Whether or not the two Specifier-like objects are equal.
344 :param other: The other object to check against.
346 The value of :attr:`prereleases` is ignored.
348 >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0")
350 >>> (Specifier("==1.2.3", prereleases=False) ==
351 ... Specifier("==1.2.3", prereleases=True))
353 >>> Specifier("==1.2.3") == "==1.2.3"
355 >>> Specifier("==1.2.3") == Specifier("==1.2.4")
357 >>> Specifier("==1.2.3") == Specifier("~=1.2.3")
360 if isinstance(other
, str):
362 other
= self
.__class
__(str(other
))
363 except InvalidSpecifier
:
364 return NotImplemented
365 elif not isinstance(other
, self
.__class
__):
366 return NotImplemented
368 return self
._canonical
_spec
== other
._canonical
_spec
370 def _get_operator(self
, op
: str) -> CallableOperator
:
371 operator_callable
: CallableOperator
= getattr(
372 self
, f
"_compare_{self._operators[op]}"
374 return operator_callable
376 def _compare_compatible(self
, prospective
: Version
, spec
: str) -> bool:
378 # Compatible releases have an equivalent combination of >= and ==. That
379 # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
380 # implement this in terms of the other specifiers instead of
381 # implementing it ourselves. The only thing we need to do is construct
382 # the other specifiers.
384 # We want everything but the last item in the version, but we want to
385 # ignore suffix segments.
387 list(itertools
.takewhile(_is_not_suffix
, _version_split(spec
)))[:-1]
390 # Add the prefix notation to the end of our string
393 return self
._get
_operator
(">=")(prospective
, spec
) and self
._get
_operator
("==")(
397 def _compare_equal(self
, prospective
: Version
, spec
: str) -> bool:
399 # We need special logic to handle prefix matching
400 if spec
.endswith(".*"):
401 # In the case of prefix matching we want to ignore local segment.
402 normalized_prospective
= canonicalize_version(
403 prospective
.public
, strip_trailing_zero
=False
405 # Get the normalized version string ignoring the trailing .*
406 normalized_spec
= canonicalize_version(spec
[:-2], strip_trailing_zero
=False)
407 # Split the spec out by dots, and pretend that there is an implicit
408 # dot in between a release segment and a pre-release segment.
409 split_spec
= _version_split(normalized_spec
)
411 # Split the prospective version out by dots, and pretend that there
412 # is an implicit dot in between a release segment and a pre-release
414 split_prospective
= _version_split(normalized_prospective
)
416 # 0-pad the prospective version before shortening it to get the correct
418 padded_prospective
, _
= _pad_version(split_prospective
, split_spec
)
420 # Shorten the prospective version to be the same length as the spec
421 # so that we can determine if the specifier is a prefix of the
422 # prospective version or not.
423 shortened_prospective
= padded_prospective
[: len(split_spec
)]
425 return shortened_prospective
== split_spec
427 # Convert our spec string into a Version
428 spec_version
= Version(spec
)
430 # If the specifier does not have a local segment, then we want to
431 # act as if the prospective version also does not have a local
433 if not spec_version
.local
:
434 prospective
= Version(prospective
.public
)
436 return prospective
== spec_version
438 def _compare_not_equal(self
, prospective
: Version
, spec
: str) -> bool:
439 return not self
._compare
_equal
(prospective
, spec
)
441 def _compare_less_than_equal(self
, prospective
: Version
, spec
: str) -> bool:
443 # NB: Local version identifiers are NOT permitted in the version
444 # specifier, so local version labels can be universally removed from
445 # the prospective version.
446 return Version(prospective
.public
) <= Version(spec
)
448 def _compare_greater_than_equal(self
, prospective
: Version
, spec
: str) -> bool:
450 # NB: Local version identifiers are NOT permitted in the version
451 # specifier, so local version labels can be universally removed from
452 # the prospective version.
453 return Version(prospective
.public
) >= Version(spec
)
455 def _compare_less_than(self
, prospective
: Version
, spec_str
: str) -> bool:
457 # Convert our spec to a Version instance, since we'll want to work with
459 spec
= Version(spec_str
)
461 # Check to see if the prospective version is less than the spec
462 # version. If it's not we can short circuit and just return False now
463 # instead of doing extra unneeded work.
464 if not prospective
< spec
:
467 # This special case is here so that, unless the specifier itself
468 # includes is a pre-release version, that we do not accept pre-release
469 # versions for the version mentioned in the specifier (e.g. <3.1 should
470 # not match 3.1.dev0, but should match 3.0.dev0).
471 if not spec
.is_prerelease
and prospective
.is_prerelease
:
472 if Version(prospective
.base_version
) == Version(spec
.base_version
):
475 # If we've gotten to here, it means that prospective version is both
476 # less than the spec version *and* it's not a pre-release of the same
477 # version in the spec.
480 def _compare_greater_than(self
, prospective
: Version
, spec_str
: str) -> bool:
482 # Convert our spec to a Version instance, since we'll want to work with
484 spec
= Version(spec_str
)
486 # Check to see if the prospective version is greater than the spec
487 # version. If it's not we can short circuit and just return False now
488 # instead of doing extra unneeded work.
489 if not prospective
> spec
:
492 # This special case is here so that, unless the specifier itself
493 # includes is a post-release version, that we do not accept
494 # post-release versions for the version mentioned in the specifier
495 # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
496 if not spec
.is_postrelease
and prospective
.is_postrelease
:
497 if Version(prospective
.base_version
) == Version(spec
.base_version
):
500 # Ensure that we do not allow a local version of the version mentioned
501 # in the specifier, which is technically greater than, to match.
502 if prospective
.local
is not None:
503 if Version(prospective
.base_version
) == Version(spec
.base_version
):
506 # If we've gotten to here, it means that prospective version is both
507 # greater than the spec version *and* it's not a pre-release of the
508 # same version in the spec.
511 def _compare_arbitrary(self
, prospective
: Version
, spec
: str) -> bool:
512 return str(prospective
).lower() == str(spec
).lower()
514 def __contains__(self
, item
: Union
[str, Version
]) -> bool:
515 """Return whether or not the item is contained in this specifier.
517 :param item: The item to check for.
519 This is used for the ``in`` operator and behaves the same as
520 :meth:`contains` with no ``prereleases`` argument passed.
522 >>> "1.2.3" in Specifier(">=1.2.3")
524 >>> Version("1.2.3") in Specifier(">=1.2.3")
526 >>> "1.0.0" in Specifier(">=1.2.3")
528 >>> "1.3.0a1" in Specifier(">=1.2.3")
530 >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)
533 return self
.contains(item
)
536 self
, item
: UnparsedVersion
, prereleases
: Optional
[bool] = None
538 """Return whether or not the item is contained in this specifier.
541 The item to check for, which can be a version string or a
542 :class:`Version` instance.
544 Whether or not to match prereleases with this Specifier. If set to
545 ``None`` (the default), it uses :attr:`prereleases` to determine
546 whether or not prereleases are allowed.
548 >>> Specifier(">=1.2.3").contains("1.2.3")
550 >>> Specifier(">=1.2.3").contains(Version("1.2.3"))
552 >>> Specifier(">=1.2.3").contains("1.0.0")
554 >>> Specifier(">=1.2.3").contains("1.3.0a1")
556 >>> Specifier(">=1.2.3", prereleases=True).contains("1.3.0a1")
558 >>> Specifier(">=1.2.3").contains("1.3.0a1", prereleases=True)
562 # Determine if prereleases are to be allowed or not.
563 if prereleases
is None:
564 prereleases
= self
.prereleases
566 # Normalize item to a Version, this allows us to have a shortcut for
567 # "2.0" in Specifier(">=2")
568 normalized_item
= _coerce_version(item
)
570 # Determine if we should be supporting prereleases in this specifier
571 # or not, if we do not support prereleases than we can short circuit
572 # logic if this version is a prereleases.
573 if normalized_item
.is_prerelease
and not prereleases
:
576 # Actually do the comparison to determine if this item is contained
577 # within this Specifier or not.
578 operator_callable
: CallableOperator
= self
._get
_operator
(self
.operator
)
579 return operator_callable(normalized_item
, self
.version
)
582 self
, iterable
: Iterable
[UnparsedVersionVar
], prereleases
: Optional
[bool] = None
583 ) -> Iterator
[UnparsedVersionVar
]:
584 """Filter items in the given iterable, that match the specifier.
587 An iterable that can contain version strings and :class:`Version` instances.
588 The items in the iterable will be filtered according to the specifier.
590 Whether or not to allow prereleases in the returned iterator. If set to
591 ``None`` (the default), it will be intelligently decide whether to allow
592 prereleases or not (based on the :attr:`prereleases` attribute, and
593 whether the only versions matching are prereleases).
595 This method is smarter than just ``filter(Specifier().contains, [...])``
596 because it implements the rule from :pep:`440` that a prerelease item
597 SHOULD be accepted if no other versions match the given specifier.
599 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
601 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")]))
602 ['1.2.3', '1.3', <Version('1.4')>]
603 >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"]))
605 >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
607 >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
612 found_prereleases
= []
614 kw
= {"prereleases": prereleases
if prereleases
is not None else True}
616 # Attempt to iterate over all the values in the iterable and if any of
617 # them match, yield them.
618 for version
in iterable
:
619 parsed_version
= _coerce_version(version
)
621 if self
.contains(parsed_version
, **kw
):
622 # If our version is a prerelease, and we were not set to allow
623 # prereleases, then we'll store it for later in case nothing
624 # else matches this specifier.
625 if parsed_version
.is_prerelease
and not (
626 prereleases
or self
.prereleases
628 found_prereleases
.append(version
)
629 # Either this is not a prerelease, or we should have been
630 # accepting prereleases from the beginning.
635 # Now that we've iterated over everything, determine if we've yielded
636 # any values, and if we have not and we have any prereleases stored up
637 # then we will go ahead and yield the prereleases.
638 if not yielded
and found_prereleases
:
639 for version
in found_prereleases
:
643 _prefix_regex
= re
.compile(r
"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
646 def _version_split(version
: str) -> List
[str]:
647 result
: List
[str] = []
648 for item
in version
.split("."):
649 match
= _prefix_regex
.search(item
)
651 result
.extend(match
.groups())
657 def _is_not_suffix(segment
: str) -> bool:
659 segment
.startswith(prefix
) for prefix
in ("dev", "a", "b", "rc", "post")
663 def _pad_version(left
: List
[str], right
: List
[str]) -> Tuple
[List
[str], List
[str]]:
664 left_split
, right_split
= [], []
666 # Get the release segment of our versions
667 left_split
.append(list(itertools
.takewhile(lambda x
: x
.isdigit(), left
)))
668 right_split
.append(list(itertools
.takewhile(lambda x
: x
.isdigit(), right
)))
670 # Get the rest of our versions
671 left_split
.append(left
[len(left_split
[0]) :])
672 right_split
.append(right
[len(right_split
[0]) :])
675 left_split
.insert(1, ["0"] * max(0, len(right_split
[0]) - len(left_split
[0])))
676 right_split
.insert(1, ["0"] * max(0, len(left_split
[0]) - len(right_split
[0])))
678 return (list(itertools
.chain(*left_split
)), list(itertools
.chain(*right_split
)))
681 class SpecifierSet(BaseSpecifier
):
682 """This class abstracts handling of a set of version specifiers.
684 It can be passed a single specifier (``>=3.0``), a comma-separated list of
685 specifiers (``>=3.0,!=3.1``), or no specifier at all.
689 self
, specifiers
: str = "", prereleases
: Optional
[bool] = None
691 """Initialize a SpecifierSet instance.
694 The string representation of a specifier or a comma-separated list of
695 specifiers which will be parsed and normalized before use.
697 This tells the SpecifierSet if it should accept prerelease versions if
698 applicable or not. The default of ``None`` will autodetect it from the
701 :raises InvalidSpecifier:
702 If the given ``specifiers`` are not parseable than this exception will be
706 # Split on `,` to break each individual specifier into it's own item, and
707 # strip each item to remove leading/trailing whitespace.
708 split_specifiers
= [s
.strip() for s
in specifiers
.split(",") if s
.strip()]
710 # Parsed each individual specifier, attempting first to make it a
712 parsed
: Set
[Specifier
] = set()
713 for specifier
in split_specifiers
:
714 parsed
.add(Specifier(specifier
))
716 # Turn our parsed specifiers into a frozen set and save them for later.
717 self
._specs
= frozenset(parsed
)
719 # Store our prereleases value so we can use it later to determine if
720 # we accept prereleases or not.
721 self
._prereleases
= prereleases
724 def prereleases(self
) -> Optional
[bool]:
725 # If we have been given an explicit prerelease modifier, then we'll
726 # pass that through here.
727 if self
._prereleases
is not None:
728 return self
._prereleases
730 # If we don't have any specifiers, and we don't have a forced value,
731 # then we'll just return None since we don't know if this should have
732 # pre-releases or not.
736 # Otherwise we'll see if any of the given specifiers accept
737 # prereleases, if any of them do we'll return True, otherwise False.
738 return any(s
.prereleases
for s
in self
._specs
)
741 def prereleases(self
, value
: bool) -> None:
742 self
._prereleases
= value
744 def __repr__(self
) -> str:
745 """A representation of the specifier set that shows all internal state.
747 Note that the ordering of the individual specifiers within the set may not
748 match the input string.
750 >>> SpecifierSet('>=1.0.0,!=2.0.0')
751 <SpecifierSet('!=2.0.0,>=1.0.0')>
752 >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)
753 <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>
754 >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)
755 <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>
758 f
", prereleases={self.prereleases!r}"
759 if self
._prereleases
is not None
763 return f
"<SpecifierSet({str(self)!r}{pre})>"
765 def __str__(self
) -> str:
766 """A string representation of the specifier set that can be round-tripped.
768 Note that the ordering of the individual specifiers within the set may not
769 match the input string.
771 >>> str(SpecifierSet(">=1.0.0,!=1.0.1"))
773 >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False))
776 return ",".join(sorted(str(s
) for s
in self
._specs
))
778 def __hash__(self
) -> int:
779 return hash(self
._specs
)
781 def __and__(self
, other
: Union
["SpecifierSet", str]) -> "SpecifierSet":
782 """Return a SpecifierSet which is a combination of the two sets.
784 :param other: The other object to combine with.
786 >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1'
787 <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
788 >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
789 <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
791 if isinstance(other
, str):
792 other
= SpecifierSet(other
)
793 elif not isinstance(other
, SpecifierSet
):
794 return NotImplemented
796 specifier
= SpecifierSet()
797 specifier
._specs
= frozenset(self
._specs | other
._specs
)
799 if self
._prereleases
is None and other
._prereleases
is not None:
800 specifier
._prereleases
= other
._prereleases
801 elif self
._prereleases
is not None and other
._prereleases
is None:
802 specifier
._prereleases
= self
._prereleases
803 elif self
._prereleases
== other
._prereleases
:
804 specifier
._prereleases
= self
._prereleases
807 "Cannot combine SpecifierSets with True and False prerelease "
813 def __eq__(self
, other
: object) -> bool:
814 """Whether or not the two SpecifierSet-like objects are equal.
816 :param other: The other object to check against.
818 The value of :attr:`prereleases` is ignored.
820 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
822 >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
823 ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
825 >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"
827 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0")
829 >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2")
832 if isinstance(other
, (str, Specifier
)):
833 other
= SpecifierSet(str(other
))
834 elif not isinstance(other
, SpecifierSet
):
835 return NotImplemented
837 return self
._specs
== other
._specs
839 def __len__(self
) -> int:
840 """Returns the number of specifiers in this specifier set."""
841 return len(self
._specs
)
843 def __iter__(self
) -> Iterator
[Specifier
]:
845 Returns an iterator over all the underlying :class:`Specifier` instances
846 in this specifier set.
848 >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str)
849 [<Specifier('!=1.0.1')>, <Specifier('>=1.0.0')>]
851 return iter(self
._specs
)
853 def __contains__(self
, item
: UnparsedVersion
) -> bool:
854 """Return whether or not the item is contained in this specifier.
856 :param item: The item to check for.
858 This is used for the ``in`` operator and behaves the same as
859 :meth:`contains` with no ``prereleases`` argument passed.
861 >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1")
863 >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1")
865 >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1")
867 >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1")
869 >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)
872 return self
.contains(item
)
876 item
: UnparsedVersion
,
877 prereleases
: Optional
[bool] = None,
878 installed
: Optional
[bool] = None,
880 """Return whether or not the item is contained in this SpecifierSet.
883 The item to check for, which can be a version string or a
884 :class:`Version` instance.
886 Whether or not to match prereleases with this SpecifierSet. If set to
887 ``None`` (the default), it uses :attr:`prereleases` to determine
888 whether or not prereleases are allowed.
890 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3")
892 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3"))
894 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1")
896 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1")
898 >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True).contains("1.3.0a1")
900 >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True)
903 # Ensure that our item is a Version instance.
904 if not isinstance(item
, Version
):
907 # Determine if we're forcing a prerelease or not, if we're not forcing
908 # one for this particular filter call, then we'll use whatever the
909 # SpecifierSet thinks for whether or not we should support prereleases.
910 if prereleases
is None:
911 prereleases
= self
.prereleases
913 # We can determine if we're going to allow pre-releases by looking to
914 # see if any of the underlying items supports them. If none of them do
915 # and this item is a pre-release then we do not allow it and we can
916 # short circuit that here.
917 # Note: This means that 1.0.dev1 would not be contained in something
918 # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
919 if not prereleases
and item
.is_prerelease
:
922 if installed
and item
.is_prerelease
:
923 item
= Version(item
.base_version
)
925 # We simply dispatch to the underlying specs here to make sure that the
926 # given version is contained within all of them.
927 # Note: This use of all() here means that an empty set of specifiers
928 # will always return True, this is an explicit design decision.
929 return all(s
.contains(item
, prereleases
=prereleases
) for s
in self
._specs
)
932 self
, iterable
: Iterable
[UnparsedVersionVar
], prereleases
: Optional
[bool] = None
933 ) -> Iterator
[UnparsedVersionVar
]:
934 """Filter items in the given iterable, that match the specifiers in this set.
937 An iterable that can contain version strings and :class:`Version` instances.
938 The items in the iterable will be filtered according to the specifier.
940 Whether or not to allow prereleases in the returned iterator. If set to
941 ``None`` (the default), it will be intelligently decide whether to allow
942 prereleases or not (based on the :attr:`prereleases` attribute, and
943 whether the only versions matching are prereleases).
945 This method is smarter than just ``filter(SpecifierSet(...).contains, [...])``
946 because it implements the rule from :pep:`440` that a prerelease item
947 SHOULD be accepted if no other versions match the given specifier.
949 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
951 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")]))
952 ['1.3', <Version('1.4')>]
953 >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"]))
955 >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
957 >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
960 An "empty" SpecifierSet will filter items based on the presence of prerelease
963 >>> list(SpecifierSet("").filter(["1.3", "1.5a1"]))
965 >>> list(SpecifierSet("").filter(["1.5a1"]))
967 >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"]))
969 >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True))
972 # Determine if we're forcing a prerelease or not, if we're not forcing
973 # one for this particular filter call, then we'll use whatever the
974 # SpecifierSet thinks for whether or not we should support prereleases.
975 if prereleases
is None:
976 prereleases
= self
.prereleases
978 # If we have any specifiers, then we want to wrap our iterable in the
979 # filter method for each one, this will act as a logical AND amongst
982 for spec
in self
._specs
:
983 iterable
= spec
.filter(iterable
, prereleases
=bool(prereleases
))
984 return iter(iterable
)
985 # If we do not have any specifiers, then we need to have a rough filter
986 # which will filter out any pre-releases, unless there are no final
989 filtered
: List
[UnparsedVersionVar
] = []
990 found_prereleases
: List
[UnparsedVersionVar
] = []
992 for item
in iterable
:
993 parsed_version
= _coerce_version(item
)
995 # Store any item which is a pre-release for later unless we've
996 # already found a final version or we are accepting prereleases
997 if parsed_version
.is_prerelease
and not prereleases
:
999 found_prereleases
.append(item
)
1001 filtered
.append(item
)
1003 # If we've found no items except for pre-releases, then we'll go
1004 # ahead and use the pre-releases
1005 if not filtered
and found_prereleases
and prereleases
is None:
1006 return iter(found_prereleases
)
1008 return iter(filtered
)