24from .utils
import canonicalize_version
25from .version
import LegacyVersion, Version, parse
27ParsedVersion = Union[Version, LegacyVersion]
28UnparsedVersion = Union[Version, LegacyVersion, str]
29VersionTypeVar = TypeVar(
"VersionTypeVar", bound=UnparsedVersion)
30CallableOperator = Callable[[ParsedVersion, str], bool]
35 An invalid specifier was found, users should refer to PEP 440.
43 Returns the str representation of this Specifier like object. This
44 should be representative of the Specifier itself.
50 Returns a hash value for this Specifier like object.
54 def __eq__(self, other: object) -> bool:
56 Returns a boolean representing whether or not the two Specifier like
63 Returns whether or not pre-releases as a whole are allowed by this
70 Sets whether or not pre-releases as a whole are allowed by this
75 def contains(self, item: str, prereleases: Optional[bool] =
None) -> bool:
77 Determines if the given item is contained within this specifier.
82 self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] =
None
83 ) -> Iterable[VersionTypeVar]:
85 Takes an iterable of items and filters them so that only items which
86 are contained within this specifier are allowed in it.
92 _operators: Dict[str, str] = {}
95 def __init__(self, spec: str =
"", prereleases: Optional[bool] =
None) ->
None:
96 match = self.
_regex.search(spec)
100 self.
_spec: Tuple[str, str] = (
110 f
", prereleases={self.prereleases!r}"
115 return f
"<{self.__class__.__name__}({str(self)!r}{pre})>"
122 return self.
_spec[0], canonicalize_version(self.
_spec[1])
131 except InvalidSpecifier:
132 return NotImplemented
134 return NotImplemented
139 operator_callable: CallableOperator =
getattr(
140 self, f
"_compare_{self._operators[op]}"
142 return operator_callable
145 if not isinstance(version, (LegacyVersion, Version)):
146 version = parse(version)
150 def operator(self) -> str:
169 self, item: UnparsedVersion, prereleases: Optional[bool] =
None
173 if prereleases
is None:
192 self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] =
None
193 ) -> Iterable[VersionTypeVar]:
196 found_prereleases = []
198 kw = {
"prereleases": prereleases
if prereleases
is not None else True}
202 for version
in iterable:
222 if not yielded
and found_prereleases:
223 for version
in found_prereleases:
230 (?P<operator>(==|!=|<=|>=|<|>))
233 [^,;\s)]* # Since this is a "legacy" specifier, and the version
234 # string can be just about anything, we match everything
235 # except for whitespace, a semi-colon for marker support,
236 # a closing paren since versions can be enclosed in
237 # them, and a comma since it's a version separator.
246 "<=":
"less_than_equal",
247 ">=":
"greater_than_equal",
252 def __init__(self, spec: str =
"", prereleases: Optional[bool] =
None) ->
None:
256 "Creating a LegacyVersion has been deprecated and will be "
257 "removed in the next major release",
276 self, prospective: LegacyVersion, spec: str
288 fn: Callable[[
"Specifier", ParsedVersion, str], bool]
289) -> Callable[[
"Specifier", ParsedVersion, str], bool]:
291 def wrapped(self:
"Specifier", prospective: ParsedVersion, spec: str) -> bool:
294 return fn(self, prospective, spec)
302 (?P<operator>(~=|==|!=|<=|>=|<|>|===))
305 # The identity operators allow for an escape hatch that will
306 # do an exact string match of the version you wish to install.
307 # This will not be parsed by PEP 440 and we cannot determine
308 # any semantic meaning from it. This operator is discouraged
309 # but included entirely as an escape hatch.
310 (?<====) # Only match for the identity operator
312 [^\s]* # We just match everything, except for whitespace
313 # since we are only testing for strict identity.
317 # The (non)equality operators allow for wild card and local
318 # versions to be specified so we have to define these two
319 # operators separately to enable that.
320 (?<===|!=) # Only match for equals and not equals
325 [0-9]+(?:\.[0-9]+)* # release
328 (a|b|c|rc|alpha|beta|pre|preview)
333 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
336 # You cannot use a wild card and a dev or local version
337 # together so group them with a | and make them optional.
339 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
340 (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
342 \.\* # Wild card syntax of .*
347 # The compatible operator requires at least two digits in the
349 (?<=~=) # Only match for the compatible operator
354 [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
357 (a|b|c|rc|alpha|beta|pre|preview)
362 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
364 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
368 # All other operators only allow a sub set of what the
369 # (non)equality operators do. Specifically they do not allow
370 # local versions to be specified nor do they allow the prefix
371 # matching wild cards.
372 (?<!==|!=|~=) # We have special cases for these
373 # operators so we want to make sure they
379 [0-9]+(?:\.[0-9]+)* # release
382 (a|b|c|rc|alpha|beta|pre|preview)
387 (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
389 (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
400 "<=":
"less_than_equal",
401 ">=":
"greater_than_equal",
407 @_require_version_compare
429 @_require_version_compare
448 shortened_prospective = split_prospective[:
len(split_spec)]
453 split_spec, shortened_prospective
456 return padded_prospective == padded_spec
467 return prospective == spec_version
469 @_require_version_compare
473 @_require_version_compare
481 @_require_version_compare
483 self, prospective: ParsedVersion, spec: str
491 @_require_version_compare
501 if not prospective < spec:
517 @_require_version_compare
527 if not prospective > spec:
550 return str(prospective).
lower() == str(spec).
lower()
563 operator, version = self.
_spec
564 if operator
in [
"==",
">=",
"<=",
"~=",
"==="]:
568 version = version[:-2]
572 if parse(version).is_prerelease:
586 result: List[str] = []
602def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str]]:
603 left_split, right_split = [], []
622 self, specifiers: str =
"", prereleases: Optional[bool] =
None
631 parsed: Set[_IndividualSpecifier] = set()
632 for specifier
in split_specifiers:
635 except InvalidSpecifier:
647 f
", prereleases={self.prereleases!r}"
652 return f
"<SpecifierSet({str(self)!r}{pre})>"
655 return ",".join(sorted(str(s)
for s
in self.
_specs))
660 def __and__(self, other: Union[
"SpecifierSet", str]) ->
"SpecifierSet":
664 return NotImplemented
677 "Cannot combine SpecifierSets with True and False prerelease "
684 if isinstance(other, (str, _IndividualSpecifier)):
687 return NotImplemented
694 def __iter__(self) -> Iterator[_IndividualSpecifier]:
723 self, item: UnparsedVersion, prereleases: Optional[bool] =
None
727 if not isinstance(item, (LegacyVersion, Version)):
733 if prereleases
is None:
752 self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] =
None
753 ) -> Iterable[VersionTypeVar]:
758 if prereleases
is None:
766 iterable =
spec.filter(iterable, prereleases=bool(prereleases))
772 filtered: List[VersionTypeVar] = []
773 found_prereleases: List[VersionTypeVar] = []
775 item: UnparsedVersion
776 parsed_version: Union[Version, LegacyVersion]
778 for item
in iterable:
780 if not isinstance(item, (LegacyVersion, Version)):
781 parsed_version = parse(item)
783 parsed_version = item
799 if not filtered
and found_prereleases
and prereleases
is None:
800 return found_prereleases
bool __eq__(self, object other)
None prereleases(self, bool value)
bool contains(self, str item, Optional[bool] prereleases=None)
Optional[bool] prereleases(self)
bool _compare_greater_than_equal(self, LegacyVersion prospective, str spec)
LegacyVersion _coerce_version(self, UnparsedVersion version)
bool _compare_greater_than(self, LegacyVersion prospective, str spec)
bool _compare_equal(self, LegacyVersion prospective, str spec)
bool _compare_less_than_equal(self, LegacyVersion prospective, str spec)
bool _compare_not_equal(self, LegacyVersion prospective, str spec)
None __init__(self, str spec="", Optional[bool] prereleases=None)
bool _compare_less_than(self, LegacyVersion prospective, str spec)
bool contains(self, UnparsedVersion item, Optional[bool] prereleases=None)
bool __eq__(self, object other)
"SpecifierSet" __and__(self, Union["SpecifierSet", str] other)
None __init__(self, str specifiers="", Optional[bool] prereleases=None)
None prereleases(self, bool value)
Iterator[_IndividualSpecifier] __iter__(self)
Optional[bool] prereleases(self)
bool __contains__(self, UnparsedVersion item)
bool _compare_not_equal(self, ParsedVersion prospective, str spec)
bool _compare_less_than_equal(self, ParsedVersion prospective, str spec)
bool _compare_equal(self, ParsedVersion prospective, str spec)
bool _compare_compatible(self, ParsedVersion prospective, str spec)
bool _compare_arbitrary(self, Version prospective, str spec)
bool _compare_greater_than_equal(self, ParsedVersion prospective, str spec)
bool _compare_less_than(self, ParsedVersion prospective, str spec_str)
bool _compare_greater_than(self, ParsedVersion prospective, str spec_str)
bool contains(self, UnparsedVersion item, Optional[bool] prereleases=None)
bool __eq__(self, object other)
ParsedVersion _coerce_version(self, UnparsedVersion version)
CallableOperator _get_operator(self, str op)
None prereleases(self, bool value)
bool __contains__(self, str item)
None __init__(self, str spec="", Optional[bool] prereleases=None)
Optional[bool] prereleases(self)
Tuple[str, str] _canonical_spec(self)
List[str] _version_split(str version)
bool _is_not_suffix(str segment)
Tuple[List[str], List[str]] _pad_version(List[str] left, List[str] right)
Callable[["Specifier", ParsedVersion, str], bool] _require_version_compare(Callable[["Specifier", ParsedVersion, str], bool] fn)