Files
HP_InHand_IG502/APPS_UNCOMPILED/lib/packaging/specifiers.py
2025-04-30 08:48:49 -05:00

484 lines
20 KiB
Python

# uncompyle6 version 3.9.2
# Python bytecode version base 3.7.0 (3394)
# Decompiled from: Python 3.8.19 (default, Mar 20 2024, 15:27:52)
# [Clang 14.0.6 ]
# Embedded file name: /var/user/app/device_supervisorbak/device_supervisor/lib/packaging/specifiers.py
# Compiled at: 2024-04-18 03:12:56
# Size of source mod 2**32: 32208 bytes
from __future__ import absolute_import, division, print_function
import abc, functools, itertools, re, warnings
from ._compat import string_types, with_metaclass
from ._typing import TYPE_CHECKING
from .utils import canonicalize_version
from .version import Version, LegacyVersion, parse
if TYPE_CHECKING:
from typing import List, Dict, Union, Iterable, Iterator, Optional, Callable, Tuple
ParsedVersion = Union[(Version, LegacyVersion)]
UnparsedVersion = Union[(Version, LegacyVersion, str)]
CallableOperator = Callable[([ParsedVersion, str], bool)]
class InvalidSpecifier(ValueError):
__doc__ = "\n An invalid specifier was found, users should refer to PEP 440.\n "
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod
def __str__(self):
"""
Returns the str representation of this Specifier like object. This
should be representative of the Specifier itself.
"""
pass
@abc.abstractmethod
def __hash__(self):
"""
Returns a hash value for this Specifier like object.
"""
pass
@abc.abstractmethod
def __eq__(self, other):
"""
Returns a boolean representing whether or not the two Specifier like
objects are equal.
"""
pass
@abc.abstractmethod
def __ne__(self, other):
"""
Returns a boolean representing whether or not the two Specifier like
objects are not equal.
"""
pass
@abc.abstractproperty
def prereleases(self):
"""
Returns whether or not pre-releases as a whole are allowed by this
specifier.
"""
pass
@prereleases.setter
def prereleases(self, value):
"""
Sets whether or not pre-releases as a whole are allowed by this
specifier.
"""
pass
@abc.abstractmethod
def contains(self, item, prereleases=None):
"""
Determines if the given item is contained within this specifier.
"""
pass
@abc.abstractmethod
def filter(self, iterable, prereleases=None):
"""
Takes an iterable of items and filters them so that only items which
are contained within this specifier are allowed in it.
"""
pass
class _IndividualSpecifier(BaseSpecifier):
_operators = {}
def __init__(self, spec='', prereleases=None):
match = self._regex.search(spec)
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
self._spec = (
match.group("operator").strip(),
match.group("version").strip())
self._prereleases = prereleases
def __repr__(self):
pre = ", prereleases={0!r}".format(self.prereleases) if self._prereleases is not None else ""
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
def __str__(self):
return ("{0}{1}".format)(*self._spec)
@property
def _canonical_spec(self):
return (
self._spec[0], canonicalize_version(self._spec[1]))
def __hash__(self):
return hash(self._canonical_spec)
def __eq__(self, other):
if isinstance(other, string_types):
try:
other = self.__class__(str(other))
except InvalidSpecifier:
return NotImplemented
else:
if not isinstance(other, self.__class__):
return NotImplemented
return self._canonical_spec == other._canonical_spec
def __ne__(self, other):
if isinstance(other, string_types):
try:
other = self.__class__(str(other))
except InvalidSpecifier:
return NotImplemented
else:
if not isinstance(other, self.__class__):
return NotImplemented
return self._spec != other._spec
def _get_operator(self, op):
operator_callable = getattr(self, "_compare_{0}".format(self._operators[op]))
return operator_callable
def _coerce_version(self, version):
if not isinstance(version, (LegacyVersion, Version)):
version = parse(version)
return version
@property
def operator(self):
return self._spec[0]
@property
def version(self):
return self._spec[1]
@property
def prereleases(self):
return self._prereleases
@prereleases.setter
def prereleases(self, value):
self._prereleases = value
def __contains__(self, item):
return self.contains(item)
def contains(self, item, prereleases=None):
if prereleases is None:
prereleases = self.prereleases
normalized_item = self._coerce_version(item)
if normalized_item.is_prerelease:
if not prereleases:
return False
operator_callable = self._get_operator(self.operator)
return operator_callable(normalized_item, self.version)
def filter(self, iterable, prereleases=None):
yielded = False
found_prereleases = []
kw = {"prereleases": (prereleases if prereleases is not None else True)}
for version in iterable:
parsed_version = self._coerce_version(version)
if (self.contains)(parsed_version, **kw):
if parsed_version.is_prerelease:
if not prereleases:
if not self.prereleases:
found_prereleases.append(version)
yielded = True
yield version
if not yielded:
if found_prereleases:
for version in found_prereleases:
yield version
class LegacySpecifier(_IndividualSpecifier):
_regex_str = '\n (?P<operator>(==|!=|<=|>=|<|>))\n \\s*\n (?P<version>\n [^,;\\s)]* # Since this is a "legacy" specifier, and the version\n # string can be just about anything, we match everything\n # except for whitespace, a semi-colon for marker support,\n # a closing paren since versions can be enclosed in\n # them, and a comma since it\'s a version separator.\n )\n '
_regex = re.compile("^\\s*" + _regex_str + "\\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
'==': '"equal"',
'!=': '"not_equal"',
'<=': '"less_than_equal"',
'>=': '"greater_than_equal"',
'<': '"less_than"',
'>': '"greater_than"'}
def __init__(self, spec='', prereleases=None):
super(LegacySpecifier, self).__init__(spec, prereleases)
warnings.warn("Creating a LegacyVersion has been deprecated and will be removed in the next major release", DeprecationWarning)
def _coerce_version(self, version):
if not isinstance(version, LegacyVersion):
version = LegacyVersion(str(version))
return version
def _compare_equal(self, prospective, spec):
return prospective == self._coerce_version(spec)
def _compare_not_equal(self, prospective, spec):
return prospective != self._coerce_version(spec)
def _compare_less_than_equal(self, prospective, spec):
return prospective <= self._coerce_version(spec)
def _compare_greater_than_equal(self, prospective, spec):
return prospective >= self._coerce_version(spec)
def _compare_less_than(self, prospective, spec):
return prospective < self._coerce_version(spec)
def _compare_greater_than(self, prospective, spec):
return prospective > self._coerce_version(spec)
def _require_version_compare(fn):
@functools.wraps(fn)
def wrapped(self, prospective, spec):
if not isinstance(prospective, Version):
return False
return fn(self, prospective, spec)
return wrapped
class Specifier(_IndividualSpecifier):
_regex_str = "\n (?P<operator>(~=|==|!=|<=|>=|<|>|===))\n (?P<version>\n (?:\n # The identity operators allow for an escape hatch that will\n # do an exact string match of the version you wish to install.\n # This will not be parsed by PEP 440 and we cannot determine\n # any semantic meaning from it. This operator is discouraged\n # but included entirely as an escape hatch.\n (?<====) # Only match for the identity operator\n \\s*\n [^\\s]* # We just match everything, except for whitespace\n # since we are only testing for strict identity.\n )\n |\n (?:\n # The (non)equality operators allow for wild card and local\n # versions to be specified so we have to define these two\n # operators separately to enable that.\n (?<===|!=) # Only match for equals and not equals\n\n \\s*\n v?\n (?:[0-9]+!)? # epoch\n [0-9]+(?:\\.[0-9]+)* # release\n (?: # pre release\n [-_\\.]?\n (a|b|c|rc|alpha|beta|pre|preview)\n [-_\\.]?\n [0-9]*\n )?\n (?: # post release\n (?:-[0-9]+)|(?:[-_\\.]?(post|rev|r)[-_\\.]?[0-9]*)\n )?\n\n # You cannot use a wild card and a dev or local version\n # together so group them with a | and make them optional.\n (?:\n (?:[-_\\.]?dev[-_\\.]?[0-9]*)? # dev release\n (?:\\+[a-z0-9]+(?:[-_\\.][a-z0-9]+)*)? # local\n |\n \\.\\* # Wild card syntax of .*\n )?\n )\n |\n (?:\n # The compatible operator requires at least two digits in the\n # release segment.\n (?<=~=) # Only match for the compatible operator\n\n \\s*\n v?\n (?:[0-9]+!)? # epoch\n [0-9]+(?:\\.[0-9]+)+ # release (We have a + instead of a *)\n (?: # pre release\n [-_\\.]?\n (a|b|c|rc|alpha|beta|pre|preview)\n [-_\\.]?\n [0-9]*\n )?\n (?: # post release\n (?:-[0-9]+)|(?:[-_\\.]?(post|rev|r)[-_\\.]?[0-9]*)\n )?\n (?:[-_\\.]?dev[-_\\.]?[0-9]*)? # dev release\n )\n |\n (?:\n # All other operators only allow a sub set of what the\n # (non)equality operators do. Specifically they do not allow\n # local versions to be specified nor do they allow the prefix\n # matching wild cards.\n (?<!==|!=|~=) # We have special cases for these\n # operators so we want to make sure they\n # don't match here.\n\n \\s*\n v?\n (?:[0-9]+!)? # epoch\n [0-9]+(?:\\.[0-9]+)* # release\n (?: # pre release\n [-_\\.]?\n (a|b|c|rc|alpha|beta|pre|preview)\n [-_\\.]?\n [0-9]*\n )?\n (?: # post release\n (?:-[0-9]+)|(?:[-_\\.]?(post|rev|r)[-_\\.]?[0-9]*)\n )?\n (?:[-_\\.]?dev[-_\\.]?[0-9]*)? # dev release\n )\n )\n "
_regex = re.compile("^\\s*" + _regex_str + "\\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
'~=': '"compatible"',
'==': '"equal"',
'!=': '"not_equal"',
'<=': '"less_than_equal"',
'>=': '"greater_than_equal"',
'<': '"less_than"',
'>': '"greater_than"',
'===': '"arbitrary"'}
@_require_version_compare
def _compare_compatible(self, prospective, spec):
prefix = ".".join(list(itertools.takewhile(lambda x: not x.startswith("post") and not x.startswith("dev"), _version_split(spec)))[None[:-1]])
prefix += ".*"
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(prospective, prefix)
@_require_version_compare
def _compare_equal(self, prospective, spec):
if spec.endswith(".*"):
prospective = Version(prospective.public)
split_spec = _version_split(spec[None[:-2]])
split_prospective = _version_split(str(prospective))
shortened_prospective = split_prospective[None[:len(split_spec)]]
padded_spec, padded_prospective = _pad_version(split_spec, shortened_prospective)
return padded_prospective == padded_spec
spec_version = Version(spec)
if not spec_version.local:
prospective = Version(prospective.public)
return prospective == spec_version
@_require_version_compare
def _compare_not_equal(self, prospective, spec):
return not self._compare_equal(prospective, spec)
@_require_version_compare
def _compare_less_than_equal(self, prospective, spec):
return Version(prospective.public) <= Version(spec)
@_require_version_compare
def _compare_greater_than_equal(self, prospective, spec):
return Version(prospective.public) >= Version(spec)
@_require_version_compare
def _compare_less_than(self, prospective, spec_str):
spec = Version(spec_str)
if not prospective < spec:
return False
if not spec.is_prerelease:
if prospective.is_prerelease:
if Version(prospective.base_version) == Version(spec.base_version):
return False
return True
@_require_version_compare
def _compare_greater_than(self, prospective, spec_str):
spec = Version(spec_str)
if not prospective > spec:
return False
if not spec.is_postrelease:
if prospective.is_postrelease:
if Version(prospective.base_version) == Version(spec.base_version):
return False
if prospective.local is not None:
if Version(prospective.base_version) == Version(spec.base_version):
return False
return True
def _compare_arbitrary(self, prospective, spec):
return str(prospective).lower() == str(spec).lower()
@property
def prereleases(self):
if self._prereleases is not None:
return self._prereleases
operator, version = self._spec
if operator in ('==', '>=', '<=', '~=', '==='):
if operator == "==":
if version.endswith(".*"):
version = version[None[:-2]]
if parse(version).is_prerelease:
return True
return False
@prereleases.setter
def prereleases(self, value):
self._prereleases = value
_prefix_regex = re.compile("^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
def _version_split(version):
result = []
for item in version.split("."):
match = _prefix_regex.search(item)
if match:
result.extend(match.groups())
else:
result.append(item)
return result
def _pad_version(left, right):
left_split, right_split = [], []
left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
left_split.append(left[len(left_split[0])[:None]])
right_split.append(right[len(right_split[0])[:None]])
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
return (
list((itertools.chain)(*left_split)), list((itertools.chain)(*right_split)))
class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers='', prereleases=None):
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
parsed = set()
for specifier in split_specifiers:
try:
parsed.add(Specifier(specifier))
except InvalidSpecifier:
parsed.add(LegacySpecifier(specifier))
self._specs = frozenset(parsed)
self._prereleases = prereleases
def __repr__(self):
pre = ", prereleases={0!r}".format(self.prereleases) if self._prereleases is not None else ""
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
def __str__(self):
return ",".join(sorted((str(s) for s in self._specs)))
def __hash__(self):
return hash(self._specs)
def __and__(self, other):
if isinstance(other, string_types):
other = SpecifierSet(other)
else:
if not isinstance(other, SpecifierSet):
return NotImplemented
else:
specifier = SpecifierSet()
specifier._specs = frozenset(self._specs | other._specs)
if self._prereleases is None and other._prereleases is not None:
specifier._prereleases = other._prereleases
else:
if self._prereleases is not None and other._prereleases is None:
specifier._prereleases = self._prereleases
else:
if self._prereleases == other._prereleases:
specifier._prereleases = self._prereleases
else:
raise ValueError("Cannot combine SpecifierSets with True and False prerelease overrides.")
return specifier
def __eq__(self, other):
if isinstance(other, (string_types, _IndividualSpecifier)):
other = SpecifierSet(str(other))
else:
if not isinstance(other, SpecifierSet):
return NotImplemented
return self._specs == other._specs
def __ne__(self, other):
if isinstance(other, (string_types, _IndividualSpecifier)):
other = SpecifierSet(str(other))
else:
if not isinstance(other, SpecifierSet):
return NotImplemented
return self._specs != other._specs
def __len__(self):
return len(self._specs)
def __iter__(self):
return iter(self._specs)
@property
def prereleases(self):
if self._prereleases is not None:
return self._prereleases
else:
return self._specs or None
return any((s.prereleases for s in self._specs))
@prereleases.setter
def prereleases(self, value):
self._prereleases = value
def __contains__(self, item):
return self.contains(item)
def contains(self, item, prereleases=None):
if not isinstance(item, (LegacyVersion, Version)):
item = parse(item)
elif prereleases is None:
prereleases = self.prereleases
if not prereleases:
if item.is_prerelease:
return False
return all((s.contains(item, prereleases=prereleases) for s in self._specs))
def filter(self, iterable, prereleases=None):
if prereleases is None:
prereleases = self.prereleases
elif self._specs:
for spec in self._specs:
iterable = spec.filter(iterable, prereleases=(bool(prereleases)))
return iterable
filtered = []
found_prereleases = []
for item in iterable:
if not isinstance(item, (LegacyVersion, Version)):
parsed_version = parse(item)
else:
parsed_version = item
if isinstance(parsed_version, LegacyVersion):
continue
if parsed_version.is_prerelease:
prereleases or filtered or found_prereleases.append(item)
else:
filtered.append(item)
if not filtered:
if found_prereleases:
if prereleases is None:
return found_prereleases
return filtered