Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
specifiers.py1944 linesDownload Raw Back to packaging
1# This file is dual licensed under the terms of the Apache License, Version2# 2.0, and the BSD License. See the LICENSE file in the root of this repository3# for complete details.4"""5.. testsetup::6 7    from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier8    from packaging.version import Version9"""10 11from __future__ import annotations12 13import abc14import enum15import functools16import itertools17import re18import sys19import typing20from 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_version33from .version import InvalidVersion, Version34 35if sys.version_info >= (3, 10):36    from typing import TypeGuard  # pragma: no cover37elif TYPE_CHECKING:38    from typing_extensions import TypeGuard39 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) == 256        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 -= 179    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.post086    AFTER_POSTS = enum.auto()  # after V.postN, before next release87 88 89@functools.total_ordering90class _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`` excludes95    ``1.0.post0``.  No real :class:`Version` falls on those boundaries,96    so this class creates values that sort between the real versions97    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 before104    V.post0.  Upper bound of ``<=V``, ``==V``, ``!=V``.105 106    ``AFTER_POSTS`` sits after every V.postN, but before the next107    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 = version115        self._kind = kind116        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.version121        if not (122            other.epoch == v.epoch123            and _trim_release(other.release) == self._trimmed_release124            and other.pre == v.pre125        ):126            return False127        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.dev130        # Post family: same base + any post-release (or identical).131        return other.dev == v.dev or other.post is not None132 133    def __eq__(self, other: object) -> bool:134        if isinstance(other, _BoundaryVersion):135            return self.version == other.version and self._kind == other._kind136        return NotImplemented137 138    def __lt__(self, other: _BoundaryVersion | Version) -> bool:139        if isinstance(other, _BoundaryVersion):140            if self.version != other.version:141                return self.version < other.version142            return self._kind.value < other._kind.value143        return not self._is_family(other) and self.version < other144 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_ordering153class _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 inclusive158    bound starts earlier.159    """160 161    __slots__ = ("inclusive", "version")162 163    def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:164        self.version = version165        self.inclusive = inclusive166 167    def __eq__(self, other: object) -> bool:168        if not isinstance(other, _LowerBound):169            return NotImplemented  # pragma: no cover170        return self.version == other.version and self.inclusive == other.inclusive171 172    def __lt__(self, other: _LowerBound) -> bool:173        if not isinstance(other, _LowerBound):  # pragma: no cover174            return NotImplemented175        # -inf < anything (except -inf).176        if self.version is None:177            return other.version is not None178        if other.version is None:179            return False180        if self.version != other.version:181            return self.version < other.version182        # [v < (v: inclusive starts earlier.183        return self.inclusive and not other.inclusive184 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_ordering194class _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 exclusive199    bound ends earlier.200    """201 202    __slots__ = ("inclusive", "version")203 204    def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:205        self.version = version206        self.inclusive = inclusive207 208    def __eq__(self, other: object) -> bool:209        if not isinstance(other, _UpperBound):210            return NotImplemented  # pragma: no cover211        return self.version == other.version and self.inclusive == other.inclusive212 213    def __lt__(self, other: _UpperBound) -> bool:214        if not isinstance(other, _UpperBound):  # pragma: no cover215            return NotImplemented216        # Nothing < +inf (except +inf itself).217        if self.version is None:218            return False219        if other.version is None:220            return True221        if self.version != other.version:222            return self.version < other.version223        # v) < v]: exclusive ends earlier.224        return not self.inclusive and other.inclusive225 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 a238    #: (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 False250    if lower.version == upper.version:251        return not (lower.inclusive and upper.inclusive)252    return lower.version > upper.version253 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 = 0262    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 += 1275        else:276            right_index += 1277 278    return result279 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 None298    return version299 300 301def _public_version(version: Version) -> Version:302    if version.local is None:303        return version304    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 None329    if isinstance(v, _BoundaryVersion):330        inner = v.version331        if inner.is_prerelease:332            # AFTER_LOCALS(1.0a1) -> nearest non-pre is 1.0333            return inner.__replace__(pre=None, dev=None, local=None)334        # AFTER_LOCALS(1.0) -> nearest non-pre is 1.0.post0335        # AFTER_LOCALS(1.0.post0) -> nearest non-pre is 1.0.post1336        k = (inner.post + 1) if inner.post is not None else 0337        return inner.__replace__(post=k, local=None)338    if not v.is_prerelease:339        return v340    # 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 specifier347    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    @property361    def _str(self) -> str:362        """Internal property for match_args"""363        return str(self)364 365    @abc.abstractmethod366    def __str__(self) -> str:367        """368        Returns the str representation of this Specifier-like object. This369        should be representative of the Specifier itself.370        """371 372    @abc.abstractmethod373    def __hash__(self) -> int:374        """375        Returns a hash value for this Specifier-like object.376        """377 378    @abc.abstractmethod379    def __eq__(self, other: object) -> bool:380        """381        Returns a boolean representing whether or not the two Specifier-like382        objects are equal.383 384        :param other: The other object to check against.385        """386 387    @property388    @abc.abstractmethod389    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 disable393        prereleases or it can be set to ``None`` (the default) to use default semantics.394        """395 396    @prereleases.setter  # noqa: B027397    def prereleases(self, value: bool) -> None:398        """Setter for :attr:`prereleases`.399 400        :param value: The value to set.401        """402 403    @abc.abstractmethod404    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.overload410    def filter(411        self,412        iterable: Iterable[UnparsedVersionVar],413        prereleases: bool | None = None,414        key: None = ...,415    ) -> Iterator[UnparsedVersionVar]: ...416 417    @typing.overload418    def filter(419        self,420        iterable: Iterable[T],421        prereleases: bool | None = None,422        key: Callable[[T], UnparsedVersion] = ...,423    ) -> Iterator[T]: ...424 425    @abc.abstractmethod426    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 which434        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 instead444        prefer to work with :class:`SpecifierSet` instead, which can parse445        comma-separated version specifiers (which is what package metadata contains).446 447    Instances are safe to serialize with :mod:`pickle`. They use a stable448    format so the same pickle can be loaded in future packaging releases.449 450    .. versionchanged:: 26.2451 452        Added a stable pickle format. Pickles created with packaging 26.2+ can453        be unpickled with future releases.  Backward compatibility with pickles454        from packaging < 26.2 is supported but may be removed in a future455        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 will470                # do an exact string match of the version you wish to install.471                # This will not be parsed by PEP 440 and we cannot determine472                # any semantic meaning from it. This operator is discouraged473                # but included entirely as an escape hatch.474                ===  # Only match for the identity operator475                \s*476                [^\s;)]*  # The arbitrary version can be just about anything,477                          # we match everything except for whitespace, a478                          # semi-colon for marker support, and a closing paren479                          # since versions can be enclosed in them.480            )481            |482            (?:483                # The (non)equality operators allow for wild card and local484                # versions to be specified so we have to define these two485                # operators separately to enable that.486                (?:==|!=)            # Only match for equals and not equals487 488                \s*489                v?490                (?:[0-9]+!)?          # epoch491                [0-9]+(?:\.[0-9]+)*   # release492 493                # You cannot use a wild card and a pre-release, post-release, a dev or494                # local version together so group them with a | and make them optional.495                (?:496                    \.\*  # Wild card syntax of .*497                    |498                    (?a:                                  # pre release499                        [-_\.]?500                        (alpha|beta|preview|pre|a|b|c|rc)501                        [-_\.]?502                        [0-9]*503                    )?504                    (?a:                                  # post release505                        (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)506                    )?507                    (?a:[-_\.]?dev[-_\.]?[0-9]*)?         # dev release508                    (?a:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local509                )?510            )511            |512            (?:513                # The compatible operator requires at least two digits in the514                # release segment.515                (?:~=)               # Only match for the compatible operator516 517                \s*518                v?519                (?:[0-9]+!)?          # epoch520                [0-9]+(?:\.[0-9]+)+   # release  (We have a + instead of a *)521                (?:                   # pre release522                    [-_\.]?523                    (alpha|beta|preview|pre|a|b|c|rc)524                    [-_\.]?525                    [0-9]*526                )?527                (?:                                   # post release528                    (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)529                )?530                (?:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release531            )532            |533            (?:534                # All other operators only allow a sub set of what the535                # (non)equality operators do. Specifically they do not allow536                # local versions to be specified nor do they allow the prefix537                # matching wild cards.538                (?:<=|>=|<|>)539 540                \s*541                v?542                (?:[0-9]+!)?          # epoch543                [0-9]+(?:\.[0-9]+)*   # release544                (?a:                   # pre release545                    [-_\.]?546                    (alpha|beta|preview|pre|a|b|c|rc)547                    [-_\.]?548                    [0-9]*549                )?550                (?a:                                   # post release551                    (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)552                )?553                (?a:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release554            )555        )556        """557 558    _regex = re.compile(559        r"\s*" + _specifier_regex_str + r"\s*", re.VERBOSE | re.IGNORECASE560    )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 and578            normalized before use.579        :param prereleases:580            This tells the specifier if it should accept prerelease versions if581            applicable or not. The default of ``None`` will autodetect it from the582            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 prereleases600        self._prereleases = prereleases601 602        # Specifier version cache603        self._spec_version: tuple[str, Version] | None = None604 605        # Populated on first wildcard (==X.*) comparison606        self._wildcard_split: tuple[list[str], int] | None = None607 608        # Version range cache (populated by _to_ranges)609        self._ranges: Sequence[_VersionRange] | None = None610 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 None619 620        self._spec_version = (version, version_specifier)621        return version_specifier622 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 version627        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 None631        return spec_version632 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.  ``===`` is637        modeled as full range (actual check done separately).  Cached.638        """639        if self._ranges is not None:640            return self._ranges641 642        op = self.operator643        ver_str = self.version644 645        if op == "===":646            self._ranges = _FULL_RANGE647            return _FULL_RANGE648 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 = result655        return result656 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 the687                # 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_str712        after_locals = _BoundaryVersion(v, _BoundaryKind.AFTER_LOCALS)713        upper = v if has_local else after_locals714 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 cover731 732    @property733    def prereleases(self) -> bool | None:734        # If there is an explicit prereleases set for this, then we'll just735        # blindly use that.736        if self._prereleases is not None:737            return self._prereleases738 739        # Only the "!=" operator does not imply prereleases when740        # the version in the specifier is a prerelease.741        operator, version_str = self._spec742        if operator == "!=":743            return False744 745        # The == specifier with trailing .* cannot include prereleases746        # e.g. "==1.0a1.*" is not valid.747        if operator == "==" and version_str.endswith(".*"):748            return False749 750        # "===" can have arbitrary string versions, so we cannot parse751        # those, we take prereleases as unknown (None) for those.752        version = self._get_spec_version(version_str)753        if version is None:754            return None755 756        # For all other operators, use the check if spec Version757        # object implies pre-releases.758        return version.is_prerelease759 760    @prereleases.setter761    def prereleases(self, value: bool | None) -> None:762        self._prereleases = value763 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 = None773        self._wildcard_split = None774        self._ranges = None775 776        if isinstance(state, tuple):777            if len(state) == 2:778                # New format (26.2+): ((operator, version), prereleases)779                spec, prereleases = state780                if _validate_spec(spec) and _validate_pre(prereleases):781                    self._spec = spec782                    self._prereleases = prereleases783                    return784            if len(state) == 2 and isinstance(state[1], dict):785                # Format (packaging 26.0-26.1): (None, {slot: value}).786                _, slot_dict = state787                spec = slot_dict.get("_spec")788                prereleases = slot_dict.get("_prereleases", "invalid")789                if _validate_spec(spec) and _validate_pre(prereleases):790                    self._spec = spec791                    self._prereleases = prereleases792                    return793        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 = spec799                self._prereleases = prereleases800                return801 802        raise TypeError(f"Cannot restore Specifier from {state!r}")803 804    @property805    def operator(self) -> str:806        """The operator of this specifier.807 808        >>> Specifier("==1.2.3").operator809        '=='810        """811        return self._spec[0]812 813    @property814    def version(self) -> str:815        """The version of this specifier.816 817        >>> Specifier("==1.2.3").version818        '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 None835            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    @property851    def _canonical_spec(self) -> tuple[str, str]:852        operator, version = self._spec853        if operator == "===" or version.endswith(".*"):854            return operator, version855 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_version863 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        True876        >>> (Specifier("==1.2.3", prereleases=False) ==877        ...  Specifier("==1.2.3", prereleases=True))878        True879        >>> Specifier("==1.2.3") == "==1.2.3"880        True881        >>> Specifier("==1.2.3") == Specifier("==1.2.4")882        False883        >>> Specifier("==1.2.3") == Specifier("~=1.2.3")884        False885        """886        if isinstance(other, str):887            try:888                other = self.__class__(str(other))889            except InvalidSpecifier:890                return NotImplemented891        elif not isinstance(other, self.__class__):892            return NotImplemented893 894        return self._canonical_spec == other._canonical_spec895 896    def _get_operator(self, op: str) -> CallableOperator:897        operator_callable: CallableOperator = getattr(898            self, f"_compare_{self._operators[op]}"899        )900        return operator_callable901 902    def _compare_compatible(self, prospective: Version, spec: str) -> bool:903        # Compatible releases have an equivalent combination of >= and ==. That904        # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to905        # implement this in terms of the other specifiers instead of906        # implementing it ourselves. The only thing we need to do is construct907        # the other specifiers.908 909        # We want everything but the last item in the version, but we want to910        # 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 string916        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_split931        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_split936        return wildcard_split937 938    def _compare_equal(self, prospective: Version, spec: str) -> bool:939        # We need special logic to handle prefix matching940        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=False946            )947            # Split the prospective version out by bangs and dots, and pretend948            # that there is an implicit dot in between a release segment and949            # a pre-release segment.950            split_prospective = _version_split(normalized_prospective)951 952            # 0-pad the prospective version before shortening it to get the correct953            # 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 spec957            # so that we can determine if the specifier is a prefix of the958            # prospective version or not.959            shortened_prospective = padded_prospective[: len(split_spec)]960 961            return shortened_prospective == split_spec962        else:963            # Convert our spec string into a Version964            spec_version = self._require_spec_version(spec)965 966            # If the specifier does not have a local segment, then we want to967            # act as if the prospective version also does not have a local968            # segment.969            if not spec_version.local:970                prospective = _public_version(prospective)971 972            return prospective == spec_version973 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 version979        # specifier, so local version labels can be universally removed from980        # 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 version985        # specifier, so local version labels can be universally removed from986        # 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 with991        # 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 spec995        # version. If it's not we can short circuit and just return False now996        # instead of doing extra unneeded work.997        if not prospective < spec:998            return False999 1000        # The spec says: "<V MUST NOT allow a pre-release of the specified1001        # version unless the specified version is itself a pre-release."1002        if (1003            not spec.is_prerelease1004            and prospective.is_prerelease1005            and prospective >= _earliest_prerelease(spec)1006        ):1007            return False1008 1009        # If we've gotten to here, it means that prospective version is both1010        # less than the spec version *and* it's not a pre-release of the same1011        # version in the spec.1012        return True1013 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 with1016        # 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 spec1020        # version. If it's not we can short circuit and just return False now1021        # instead of doing extra unneeded work.1022        if not prospective > spec:1023            return False1024 1025        # The spec says: ">V MUST NOT allow a post-release of the specified1026        # version unless the specified version is itself a post-release."1027        if (1028            not spec.is_postrelease1029            and prospective.is_postrelease1030            and _post_base(prospective) == spec1031        ):1032            return False1033 1034        # Per the spec: ">V MUST NOT match a local version of the specified1035        # version". A "local version of V" is any version whose public part1036        # equals V. So >1.0a1 must not match 1.0a1+local, but must still1037        # match 1.0a2+local.1038        if prospective.local is not None and _public_version(prospective) == spec:1039            return False1040 1041        # If we've gotten to here, it means that prospective version is both1042        # greater than the spec version *and* it's not a pre-release of the1043        # same version in the spec.1044        return True1045 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 as1055        :meth:`contains` with no ``prereleases`` argument passed.1056 1057        >>> "1.2.3" in Specifier(">=1.2.3")1058        True1059        >>> Version("1.2.3") in Specifier(">=1.2.3")1060        True1061        >>> "1.0.0" in Specifier(">=1.2.3")1062        False1063        >>> "1.3.0a1" in Specifier(">=1.2.3")1064        True1065        >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)1066        True1067        """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 a1075            :class:`Version` instance.1076        :param prereleases:1077            Whether or not to match prereleases with this Specifier. If set to1078            ``None`` (the default), it will follow the recommendation from1079            :pep:`440` and match prereleases, as there are no other versions.1080 1081        >>> Specifier(">=1.2.3").contains("1.2.3")1082        True1083        >>> Specifier(">=1.2.3").contains(Version("1.2.3"))1084        True1085        >>> Specifier(">=1.2.3").contains("1.0.0")1086        False1087        >>> Specifier(">=1.2.3").contains("1.3.0a1")1088        True1089        >>> Specifier(">=1.2.3", prereleases=False).contains("1.3.0a1")1090        False1091        >>> Specifier(">=1.2.3").contains("1.3.0a1")1092        True1093        """1094 1095        return bool(list(self.filter([item], prereleases=prereleases)))1096 1097    @typing.overload1098    def filter(1099        self,1100        iterable: Iterable[UnparsedVersionVar],1101        prereleases: bool | None = None,1102        key: None = ...,1103    ) -> Iterator[UnparsedVersionVar]: ...1104 1105    @typing.overload1106    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 to1126            ``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) and1130            returns a version string or :class:`Version` instance to be used for1131            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 = False1150 1151        # Determine if to include prereleases by default1152        include_prereleases = (1153            prereleases if prereleases is not None else self.prereleases1154        )1155 1156        # Get the matching operator1157        operator_callable = self._get_operator(self.operator)1158 1159        # Filter versions1160        for version in iterable:1161            parsed_version = _coerce_version(version if key is None else key(version))1162            match = False1163            if parsed_version is None:1164                # === operator can match arbitrary (non-version) strings1165                if self.operator == "===" and self._compare_arbitrary(1166                    version, self.version1167                ):1168                    yield version1169            elif self.operator == "===":1170                match = self._compare_arbitrary(1171                    version if key is None else key(version), self.version1172                )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 directly1178                if not parsed_version.is_prerelease or include_prereleases:1179                    found_non_prereleases = True1180                    yield version1181                # Otherwise collect prereleases for potential later use1182                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't1186        # explicitly forbidden, yield the collected prereleases1187        if (1188            not found_non_prereleases1189            and prereleases is None1190            and self._prereleases is not False1191        ):1192            yield from prereleases_versions1193 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] | None1200) -> Iterator[Any]:

Showing the first 1,200 of 1944 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai