diff --git a/lib/packaging/__about__.py b/lib/packaging/__about__.py deleted file mode 100644 index 1391863f..00000000 --- a/lib/packaging/__about__.py +++ /dev/null @@ -1,26 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -__all__ = [ - "__title__", - "__summary__", - "__uri__", - "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", -] - -__title__ = "packaging" -__summary__ = "Core utilities for Python packages" -__uri__ = "https://github.com/pypa/packaging" - -__version__ = "22.0" - -__author__ = "Donald Stufft and individual contributors" -__email__ = "donald@stufft.io" - -__license__ = "BSD-2-Clause or Apache-2.0" -__copyright__ = "2014-2019 %s" % __author__ diff --git a/lib/packaging/__init__.py b/lib/packaging/__init__.py index 3c50c5dc..4112fec0 100644 --- a/lib/packaging/__init__.py +++ b/lib/packaging/__init__.py @@ -2,24 +2,14 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -from .__about__ import ( - __author__, - __copyright__, - __email__, - __license__, - __summary__, - __title__, - __uri__, - __version__, -) +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" -__all__ = [ - "__title__", - "__summary__", - "__uri__", - "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", -] +__version__ = "23.0" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD-2-Clause or Apache-2.0" +__copyright__ = "2014-2019 %s" % __author__ diff --git a/lib/packaging/_elffile.py b/lib/packaging/_elffile.py index 9fb5984b..6fb19b30 100644 --- a/lib/packaging/_elffile.py +++ b/lib/packaging/_elffile.py @@ -53,7 +53,7 @@ class ELFFile: raise ELFInvalid(f"invalid magic: {magic!r}") self.capacity = ident[4] # Format for program header (bitness). - self.encoding = ident[5] # Data structure encoding (endianess). + self.encoding = ident[5] # Data structure encoding (endianness). try: # e_fmt: Format for program header. diff --git a/lib/packaging/_parser.py b/lib/packaging/_parser.py index 4dcf03d1..2bc6a8f9 100644 --- a/lib/packaging/_parser.py +++ b/lib/packaging/_parser.py @@ -43,7 +43,7 @@ MarkerVar = Union[Variable, Value] MarkerItem = Tuple[MarkerVar, Op, MarkerVar] # MarkerAtom = Union[MarkerItem, List["MarkerAtom"]] # MarkerList = List[Union["MarkerList", MarkerAtom, str]] -# mypy does not suport recursive type definition +# mypy does not support recursive type definition # https://github.com/python/mypy/issues/731 MarkerAtom = Any MarkerList = List[Any] @@ -89,7 +89,7 @@ def _parse_requirement_details( tokenizer: Tokenizer, ) -> Tuple[str, str, Optional[MarkerList]]: """ - requirement_details = AT URL (WS requirement_marker)? + requirement_details = AT URL (WS requirement_marker?)? | specifier WS? (requirement_marker)? """ @@ -108,6 +108,10 @@ def _parse_requirement_details( tokenizer.expect("WS", expected="whitespace after URL") + # The input might end after whitespace. + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + marker = _parse_requirement_marker( tokenizer, span_start=url_start, after="URL and whitespace" ) @@ -144,8 +148,7 @@ def _parse_requirement_marker( f"Expected end or semicolon (after {after})", span_start=span_start, ) - else: - tokenizer.read() + tokenizer.read() marker = _parse_marker(tokenizer) tokenizer.consume("WS") @@ -210,20 +213,12 @@ def _parse_specifier(tokenizer: Tokenizer) -> str: def _parse_version_many(tokenizer: Tokenizer) -> str: """ - version_many = (OP VERSION (COMMA OP VERSION)*)? + version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)? """ parsed_specifiers = "" - while tokenizer.check("OP"): + while tokenizer.check("SPECIFIER"): parsed_specifiers += tokenizer.read().text - - # We intentionally do not consume whitespace here, since the regular expression - # for `VERSION` uses a lookback for the operator, to determine what - # corresponding syntax is permitted. - - version_token = tokenizer.expect("VERSION", expected="version after operator") - parsed_specifiers += version_token.text tokenizer.consume("WS") - if not tokenizer.check("COMMA"): break parsed_specifiers += tokenizer.read().text diff --git a/lib/packaging/_tokenizer.py b/lib/packaging/_tokenizer.py index de389cb3..b1fb207c 100644 --- a/lib/packaging/_tokenizer.py +++ b/lib/packaging/_tokenizer.py @@ -35,7 +35,6 @@ class ParserSyntaxError(Exception): DEFAULT_RULES: "Dict[str, Union[str, re.Pattern[str]]]" = { - "LPAREN": r"\s*\(", "LEFT_PARENTHESIS": r"\(", "RIGHT_PARENTHESIS": r"\)", "LEFT_BRACKET": r"\[", @@ -72,7 +71,10 @@ DEFAULT_RULES: "Dict[str, Union[str, re.Pattern[str]]]" = { """, re.VERBOSE, ), - "VERSION": re.compile(Specifier._version_regex_str, re.VERBOSE | re.IGNORECASE), + "SPECIFIER": re.compile( + Specifier._operator_regex_str + Specifier._version_regex_str, + re.VERBOSE | re.IGNORECASE, + ), "AT": r"\@", "URL": r"[^ \t]+", "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", diff --git a/lib/packaging/markers.py b/lib/packaging/markers.py index a5bf35c6..68369c98 100644 --- a/lib/packaging/markers.py +++ b/lib/packaging/markers.py @@ -237,5 +237,9 @@ class Marker: current_environment["extra"] = "" if environment is not None: current_environment.update(environment) + # The API used to allow setting extra to None. We need to handle this + # case for backwards compatibility. + if current_environment["extra"] is None: + current_environment["extra"] = "" return _evaluate_markers(self._markers, current_environment) diff --git a/lib/packaging/specifiers.py b/lib/packaging/specifiers.py index 645214ae..e715ecc8 100644 --- a/lib/packaging/specifiers.py +++ b/lib/packaging/specifiers.py @@ -11,12 +11,23 @@ import abc import itertools import re -from typing import Callable, Iterable, Iterator, List, Optional, Set, Tuple, Union +from typing import ( + Callable, + Iterable, + Iterator, + List, + Optional, + Set, + Tuple, + TypeVar, + Union, +) from .utils import canonicalize_version from .version import Version UnparsedVersion = Union[Version, str] +UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion) CallableOperator = Callable[[Version, str], bool] @@ -85,8 +96,8 @@ class BaseSpecifier(metaclass=abc.ABCMeta): @abc.abstractmethod def filter( - self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterator[UnparsedVersion]: + self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None + ) -> Iterator[UnparsedVersionVar]: """ Takes an iterable of items and filters them so that only items which are contained within this specifier are allowed in it. @@ -140,7 +151,7 @@ class Specifier(BaseSpecifier): | (?: # pre release [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) + (alpha|beta|preview|pre|a|b|c|rc) [-_\.]? [0-9]* )? @@ -163,7 +174,7 @@ class Specifier(BaseSpecifier): [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) (?: # pre release [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) + (alpha|beta|preview|pre|a|b|c|rc) [-_\.]? [0-9]* )? @@ -188,7 +199,7 @@ class Specifier(BaseSpecifier): [0-9]+(?:\.[0-9]+)* # release (?: # pre release [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) + (alpha|beta|preview|pre|a|b|c|rc) [-_\.]? [0-9]* )? @@ -565,8 +576,8 @@ class Specifier(BaseSpecifier): return operator_callable(normalized_item, self.version) def filter( - self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterator[UnparsedVersion]: + self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None + ) -> Iterator[UnparsedVersionVar]: """Filter items in the given iterable, that match the specifier. :param iterable: @@ -606,7 +617,7 @@ class Specifier(BaseSpecifier): if self.contains(parsed_version, **kw): # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later incase nothing + # prereleases, then we'll store it for later in case nothing # else matches this specifier. if parsed_version.is_prerelease and not ( prereleases or self.prereleases @@ -915,8 +926,8 @@ class SpecifierSet(BaseSpecifier): return all(s.contains(item, prereleases=prereleases) for s in self._specs) def filter( - self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterator[UnparsedVersion]: + self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None + ) -> Iterator[UnparsedVersionVar]: """Filter items in the given iterable, that match the specifiers in this set. :param iterable: @@ -972,8 +983,8 @@ class SpecifierSet(BaseSpecifier): # which will filter out any pre-releases, unless there are no final # releases. else: - filtered: List[UnparsedVersion] = [] - found_prereleases: List[UnparsedVersion] = [] + filtered: List[UnparsedVersionVar] = [] + found_prereleases: List[UnparsedVersionVar] = [] for item in iterable: parsed_version = _coerce_version(item) diff --git a/lib/packaging/tags.py b/lib/packaging/tags.py index a0e1ea23..19ccbde3 100644 --- a/lib/packaging/tags.py +++ b/lib/packaging/tags.py @@ -225,10 +225,45 @@ def cpython_tags( yield Tag(interpreter, "abi3", platform_) -def _generic_abi() -> Iterator[str]: - abi = sysconfig.get_config_var("SOABI") - if abi: - yield _normalize_string(abi) +def _generic_abi() -> List[str]: + """ + Return the ABI tag based on EXT_SUFFIX. + """ + # The following are examples of `EXT_SUFFIX`. + # We want to keep the parts which are related to the ABI and remove the + # parts which are related to the platform: + # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 + # - mac: '.cpython-310-darwin.so' => cp310 + # - win: '.cp310-win_amd64.pyd' => cp310 + # - win: '.pyd' => cp37 (uses _cpython_abis()) + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 + # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' + # => graalpy_38_native + + ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) + if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": + raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") + parts = ext_suffix.split(".") + if len(parts) < 3: + # CPython3.7 and earlier uses ".pyd" on Windows. + return _cpython_abis(sys.version_info[:2]) + soabi = parts[1] + if soabi.startswith("cpython"): + # non-windows + abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("cp"): + # windows + abi = soabi.split("-")[0] + elif soabi.startswith("pypy"): + abi = "-".join(soabi.split("-")[:2]) + elif soabi.startswith("graalpy"): + abi = "-".join(soabi.split("-")[:3]) + elif soabi: + # pyston, ironpython, others? + abi = soabi + else: + return [] + return [_normalize_string(abi)] def generic_tags( @@ -252,8 +287,9 @@ def generic_tags( interpreter = "".join([interp_name, interp_version]) if abis is None: abis = _generic_abi() + else: + abis = list(abis) platforms = list(platforms or platform_tags()) - abis = list(abis) if "none" not in abis: abis.append("none") for abi in abis: @@ -463,6 +499,9 @@ def platform_tags() -> Iterator[str]: def interpreter_name() -> str: """ Returns the name of the running interpreter. + + Some implementations have a reserved, two-letter abbreviation which will + be returned when appropriate. """ name = sys.implementation.name return INTERPRETER_SHORT_NAMES.get(name) or name diff --git a/requirements.txt b/requirements.txt index 00beccf9..80de6d04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ IPy==1.01 Mako==1.2.4 MarkupSafe==2.1.1 musicbrainzngs==0.7.1 -packaging==22.0 +packaging==23.0 paho-mqtt==1.6.1 plexapi==4.13.2 portend==3.1.0