summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2022-12-10 14:41:36 +0200
committerAlex Grönholm <alex.gronholm@nextday.fi>2022-12-10 14:41:36 +0200
commit861a3a35437aad0d2358a6a89eebe625e80d496b (patch)
tree0680862391e1ad9733ba1526a4615778ddc13186
parent1b1486da8f84445e42814142bcfd1c1ca432b5d8 (diff)
downloadwheel-git-861a3a35437aad0d2358a6a89eebe625e80d496b.tar.gz
Updated vendored packaging lib to v22.0
-rw-r--r--docs/news.rst4
-rw-r--r--src/wheel/vendored/packaging/_manylinux.py167
-rw-r--r--src/wheel/vendored/packaging/_musllinux.py80
-rw-r--r--src/wheel/vendored/packaging/tags.py71
-rw-r--r--src/wheel/vendored/vendor.txt2
5 files changed, 117 insertions, 207 deletions
diff --git a/docs/news.rst b/docs/news.rst
index fa5b8f0..ab0f3c9 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -1,6 +1,10 @@
Release Notes
=============
+**UNRELEASED**
+
+- Updated vendored ``packaging`` to 22.0
+
**0.38.4 (2022-11-09)**
- Fixed ``PKG-INFO`` conversion in ``bdist_wheel`` mangling UTF-8 header values in
diff --git a/src/wheel/vendored/packaging/_manylinux.py b/src/wheel/vendored/packaging/_manylinux.py
index 4934ba8..2f0cc74 100644
--- a/src/wheel/vendored/packaging/_manylinux.py
+++ b/src/wheel/vendored/packaging/_manylinux.py
@@ -1,123 +1,58 @@
-from __future__ import annotations
-
import collections
+import contextlib
import functools
import os
import re
-import struct
import sys
import warnings
-from typing import IO, Iterator, NamedTuple
-
-
-# Python does not provide platform information at sufficient granularity to
-# identify the architecture of the running executable in some cases, so we
-# determine it dynamically by reading the information from the running
-# process. This only applies on Linux, which uses the ELF format.
-class _ELFFileHeader:
- # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
- class _InvalidELFFileHeader(ValueError):
- """
- An invalid ELF file header was found.
- """
-
- ELF_MAGIC_NUMBER = 0x7F454C46
- ELFCLASS32 = 1
- ELFCLASS64 = 2
- ELFDATA2LSB = 1
- ELFDATA2MSB = 2
- EM_386 = 3
- EM_S390 = 22
- EM_ARM = 40
- EM_X86_64 = 62
- EF_ARM_ABIMASK = 0xFF000000
- EF_ARM_ABI_VER5 = 0x05000000
- EF_ARM_ABI_FLOAT_HARD = 0x00000400
-
- def __init__(self, file: IO[bytes]) -> None:
- def unpack(fmt: str) -> int:
- try:
- data = file.read(struct.calcsize(fmt))
- result: tuple[int, ...] = struct.unpack(fmt, data)
- except struct.error:
- raise _ELFFileHeader._InvalidELFFileHeader()
- return result[0]
-
- self.e_ident_magic = unpack(">I")
- if self.e_ident_magic != self.ELF_MAGIC_NUMBER:
- raise _ELFFileHeader._InvalidELFFileHeader()
- self.e_ident_class = unpack("B")
- if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}:
- raise _ELFFileHeader._InvalidELFFileHeader()
- self.e_ident_data = unpack("B")
- if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}:
- raise _ELFFileHeader._InvalidELFFileHeader()
- self.e_ident_version = unpack("B")
- self.e_ident_osabi = unpack("B")
- self.e_ident_abiversion = unpack("B")
- self.e_ident_pad = file.read(7)
- format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H"
- format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I"
- format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q"
- format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q
- self.e_type = unpack(format_h)
- self.e_machine = unpack(format_h)
- self.e_version = unpack(format_i)
- self.e_entry = unpack(format_p)
- self.e_phoff = unpack(format_p)
- self.e_shoff = unpack(format_p)
- self.e_flags = unpack(format_i)
- self.e_ehsize = unpack(format_h)
- self.e_phentsize = unpack(format_h)
- self.e_phnum = unpack(format_h)
- self.e_shentsize = unpack(format_h)
- self.e_shnum = unpack(format_h)
- self.e_shstrndx = unpack(format_h)
-
-
-def _get_elf_header() -> _ELFFileHeader | None:
+from typing import Dict, Generator, Iterator, NamedTuple, Optional, Tuple
+
+from ._elffile import EIClass, EIData, ELFFile, EMachine
+
+EF_ARM_ABIMASK = 0xFF000000
+EF_ARM_ABI_VER5 = 0x05000000
+EF_ARM_ABI_FLOAT_HARD = 0x00000400
+
+
+@contextlib.contextmanager
+def _parse_elf(path: str) -> Generator[Optional[ELFFile], None, None]:
try:
- with open(sys.executable, "rb") as f:
- elf_header = _ELFFileHeader(f)
- except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
- return None
- return elf_header
+ with open(path, "rb") as f:
+ yield ELFFile(f)
+ except (OSError, TypeError, ValueError):
+ yield None
-def _is_linux_armhf() -> bool:
+def _is_linux_armhf(executable: str) -> bool:
# hard-float ABI can be detected from the ELF header of the running
# process
# https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
- elf_header = _get_elf_header()
- if elf_header is None:
- return False
- result = elf_header.e_ident_class == elf_header.ELFCLASS32
- result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB
- result &= elf_header.e_machine == elf_header.EM_ARM
- result &= (
- elf_header.e_flags & elf_header.EF_ARM_ABIMASK
- ) == elf_header.EF_ARM_ABI_VER5
- result &= (
- elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD
- ) == elf_header.EF_ARM_ABI_FLOAT_HARD
- return result
-
-
-def _is_linux_i686() -> bool:
- elf_header = _get_elf_header()
- if elf_header is None:
- return False
- result = elf_header.e_ident_class == elf_header.ELFCLASS32
- result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB
- result &= elf_header.e_machine == elf_header.EM_386
- return result
+ with _parse_elf(executable) as f:
+ return (
+ f is not None
+ and f.capacity == EIClass.C32
+ and f.encoding == EIData.Lsb
+ and f.machine == EMachine.Arm
+ and f.flags & EF_ARM_ABIMASK == EF_ARM_ABI_VER5
+ and f.flags & EF_ARM_ABI_FLOAT_HARD == EF_ARM_ABI_FLOAT_HARD
+ )
+
+
+def _is_linux_i686(executable: str) -> bool:
+ with _parse_elf(executable) as f:
+ return (
+ f is not None
+ and f.capacity == EIClass.C32
+ and f.encoding == EIData.Lsb
+ and f.machine == EMachine.I386
+ )
-def _have_compatible_abi(arch: str) -> bool:
+def _have_compatible_abi(executable: str, arch: str) -> bool:
if arch == "armv7l":
- return _is_linux_armhf()
+ return _is_linux_armhf(executable)
if arch == "i686":
- return _is_linux_i686()
+ return _is_linux_i686(executable)
return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"}
@@ -126,7 +61,7 @@ def _have_compatible_abi(arch: str) -> bool:
# For now, guess what the highest minor version might be, assume it will
# be 50 for testing. Once this actually happens, update the dictionary
# with the actual value.
-_LAST_GLIBC_MINOR: dict[int, int] = collections.defaultdict(lambda: 50)
+_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50)
class _GLibCVersion(NamedTuple):
@@ -134,7 +69,7 @@ class _GLibCVersion(NamedTuple):
minor: int
-def _glibc_version_string_confstr() -> str | None:
+def _glibc_version_string_confstr() -> Optional[str]:
"""
Primary implementation of glibc_version_string using os.confstr.
"""
@@ -143,17 +78,17 @@ def _glibc_version_string_confstr() -> str | None:
# platform module.
# https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183
try:
- # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17".
- version_string = os.confstr("CS_GNU_LIBC_VERSION")
+ # Should be a string like "glibc 2.17".
+ version_string: str = getattr(os, "confstr")("CS_GNU_LIBC_VERSION")
assert version_string is not None
- _, version = version_string.split()
+ _, version = version_string.rsplit()
except (AssertionError, AttributeError, OSError, ValueError):
# os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)...
return None
return version
-def _glibc_version_string_ctypes() -> str | None:
+def _glibc_version_string_ctypes() -> Optional[str]:
"""
Fallback implementation of glibc_version_string using ctypes.
"""
@@ -197,12 +132,12 @@ def _glibc_version_string_ctypes() -> str | None:
return version_str
-def _glibc_version_string() -> str | None:
+def _glibc_version_string() -> Optional[str]:
"""Returns glibc version string, or None if not using glibc."""
return _glibc_version_string_confstr() or _glibc_version_string_ctypes()
-def _parse_glibc_version(version_str: str) -> tuple[int, int]:
+def _parse_glibc_version(version_str: str) -> Tuple[int, int]:
"""Parse glibc version.
We use a regexp instead of str.split because we want to discard any
@@ -213,8 +148,8 @@ def _parse_glibc_version(version_str: str) -> tuple[int, int]:
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
if not m:
warnings.warn(
- "Expected glibc version with 2 components major.minor,"
- " got: %s" % version_str,
+ f"Expected glibc version with 2 components major.minor,"
+ f" got: {version_str}",
RuntimeWarning,
)
return -1, -1
@@ -222,7 +157,7 @@ def _parse_glibc_version(version_str: str) -> tuple[int, int]:
@functools.lru_cache()
-def _get_glibc_version() -> tuple[int, int]:
+def _get_glibc_version() -> Tuple[int, int]:
version_str = _glibc_version_string()
if version_str is None:
return (-1, -1)
@@ -267,7 +202,7 @@ _LEGACY_MANYLINUX_MAP = {
def platform_tags(linux: str, arch: str) -> Iterator[str]:
- if not _have_compatible_abi(arch):
+ if not _have_compatible_abi(sys.executable, arch):
return
# Oldest glibc to be supported regardless of architecture is (2, 17).
too_old_glibc2 = _GLibCVersion(2, 16)
diff --git a/src/wheel/vendored/packaging/_musllinux.py b/src/wheel/vendored/packaging/_musllinux.py
index 7946c9b..706ba60 100644
--- a/src/wheel/vendored/packaging/_musllinux.py
+++ b/src/wheel/vendored/packaging/_musllinux.py
@@ -4,70 +4,13 @@ This module implements logic to detect if the currently running Python is
linked against musl, and what musl version is used.
"""
-from __future__ import annotations
-
-import contextlib
import functools
-import operator
-import os
import re
-import struct
import subprocess
import sys
-from typing import IO, Iterator, NamedTuple
-
-
-def _read_unpacked(f: IO[bytes], fmt: str) -> tuple[int, ...]:
- return struct.unpack(fmt, f.read(struct.calcsize(fmt)))
+from typing import Iterator, NamedTuple, Optional
-
-def _parse_ld_musl_from_elf(f: IO[bytes]) -> str | None:
- """Detect musl libc location by parsing the Python executable.
-
- Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca
- ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
- """
- f.seek(0)
- try:
- ident = _read_unpacked(f, "16B")
- except struct.error:
- return None
- if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF.
- return None
- f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version.
-
- try:
- # e_fmt: Format for program header.
- # p_fmt: Format for section header.
- # p_idx: Indexes to find p_type, p_offset, and p_filesz.
- e_fmt, p_fmt, p_idx = {
- 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit.
- 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit.
- }[ident[4]]
- except KeyError:
- return None
- else:
- p_get = operator.itemgetter(*p_idx)
-
- # Find the interpreter section and return its content.
- try:
- _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt)
- except struct.error:
- return None
- for i in range(e_phnum + 1):
- f.seek(e_phoff + e_phentsize * i)
- try:
- p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt))
- except struct.error:
- return None
- if p_type != 3: # Not PT_INTERP.
- continue
- f.seek(p_offset)
- interpreter = os.fsdecode(f.read(p_filesz)).strip("\0")
- if "musl" not in interpreter:
- return None
- return interpreter
- return None
+from ._elffile import ELFFile
class _MuslVersion(NamedTuple):
@@ -75,7 +18,7 @@ class _MuslVersion(NamedTuple):
minor: int
-def _parse_musl_version(output: str) -> _MuslVersion | None:
+def _parse_musl_version(output: str) -> Optional[_MuslVersion]:
lines = [n for n in (n.strip() for n in output.splitlines()) if n]
if len(lines) < 2 or lines[0][:4] != "musl":
return None
@@ -86,7 +29,7 @@ def _parse_musl_version(output: str) -> _MuslVersion | None:
@functools.lru_cache()
-def _get_musl_version(executable: str) -> _MuslVersion | None:
+def _get_musl_version(executable: str) -> Optional[_MuslVersion]:
"""Detect currently-running musl runtime version.
This is done by checking the specified executable's dynamic linking
@@ -97,15 +40,14 @@ def _get_musl_version(executable: str) -> _MuslVersion | None:
Version 1.2.2
Dynamic Program Loader
"""
- with contextlib.ExitStack() as stack:
- try:
- f = stack.enter_context(open(executable, "rb"))
- except OSError:
- return None
- ld = _parse_ld_musl_from_elf(f)
- if not ld:
+ try:
+ with open(executable, "rb") as f:
+ ld = ELFFile(f).interpreter
+ except (OSError, TypeError, ValueError):
+ return None
+ if ld is None or "musl" not in ld:
return None
- proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True)
+ proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True)
return _parse_musl_version(proc.stderr)
diff --git a/src/wheel/vendored/packaging/tags.py b/src/wheel/vendored/packaging/tags.py
index 4e003a9..a0e1ea2 100644
--- a/src/wheel/vendored/packaging/tags.py
+++ b/src/wheel/vendored/packaging/tags.py
@@ -2,14 +2,24 @@
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
-from __future__ import annotations
-
import logging
import platform
+import subprocess
import sys
import sysconfig
from importlib.machinery import EXTENSION_SUFFIXES
-from typing import Iterable, Iterator, Sequence, Tuple, cast
+from typing import (
+ Dict,
+ FrozenSet,
+ Iterable,
+ Iterator,
+ List,
+ Optional,
+ Sequence,
+ Tuple,
+ Union,
+ cast,
+)
from . import _manylinux, _musllinux
@@ -18,7 +28,7 @@ logger = logging.getLogger(__name__)
PythonVersion = Sequence[int]
MacVersion = Tuple[int, int]
-INTERPRETER_SHORT_NAMES: dict[str, str] = {
+INTERPRETER_SHORT_NAMES: Dict[str, str] = {
"python": "py", # Generic.
"cpython": "cp",
"pypy": "pp",
@@ -27,7 +37,7 @@ INTERPRETER_SHORT_NAMES: dict[str, str] = {
}
-_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
+_32_BIT_INTERPRETER = sys.maxsize <= 2**32
class Tag:
@@ -84,7 +94,7 @@ class Tag:
return f"<{self} @ {id(self)}>"
-def parse_tag(tag: str) -> frozenset[Tag]:
+def parse_tag(tag: str) -> FrozenSet[Tag]:
"""
Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances.
@@ -100,7 +110,7 @@ def parse_tag(tag: str) -> frozenset[Tag]:
return frozenset(tags)
-def _get_config_var(name: str, warn: bool = False) -> int | str | None:
+def _get_config_var(name: str, warn: bool = False) -> Union[int, str, None]:
value = sysconfig.get_config_var(name)
if value is None and warn:
logger.debug(
@@ -122,7 +132,7 @@ def _abi3_applies(python_version: PythonVersion) -> bool:
return len(python_version) > 1 and tuple(python_version) >= (3, 2)
-def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]:
+def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]:
py_version = tuple(py_version) # To allow for version comparison.
abis = []
version = _version_nodot(py_version[:2])
@@ -159,9 +169,9 @@ def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]:
def cpython_tags(
- python_version: PythonVersion | None = None,
- abis: Iterable[str] | None = None,
- platforms: Iterable[str] | None = None,
+ python_version: Optional[PythonVersion] = None,
+ abis: Optional[Iterable[str]] = None,
+ platforms: Optional[Iterable[str]] = None,
*,
warn: bool = False,
) -> Iterator[Tag]:
@@ -222,9 +232,9 @@ def _generic_abi() -> Iterator[str]:
def generic_tags(
- interpreter: str | None = None,
- abis: Iterable[str] | None = None,
- platforms: Iterable[str] | None = None,
+ interpreter: Optional[str] = None,
+ abis: Optional[Iterable[str]] = None,
+ platforms: Optional[Iterable[str]] = None,
*,
warn: bool = False,
) -> Iterator[Tag]:
@@ -267,9 +277,9 @@ def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]:
def compatible_tags(
- python_version: PythonVersion | None = None,
- interpreter: str | None = None,
- platforms: Iterable[str] | None = None,
+ python_version: Optional[PythonVersion] = None,
+ interpreter: Optional[str] = None,
+ platforms: Optional[Iterable[str]] = None,
) -> Iterator[Tag]:
"""
Yields the sequence of tags that are compatible with a specific version of Python.
@@ -301,7 +311,7 @@ def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str:
return "i386"
-def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> list[str]:
+def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> List[str]:
formats = [cpu_arch]
if cpu_arch == "x86_64":
if version < (10, 4):
@@ -334,7 +344,7 @@ def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> list[str]:
def mac_platforms(
- version: MacVersion | None = None, arch: str | None = None
+ version: Optional[MacVersion] = None, arch: Optional[str] = None
) -> Iterator[str]:
"""
Yields the platform tags for a macOS system.
@@ -347,6 +357,22 @@ def mac_platforms(
version_str, _, cpu_arch = platform.mac_ver()
if version is None:
version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
+ if version == (10, 16):
+ # When built against an older macOS SDK, Python will report macOS 10.16
+ # instead of the real version.
+ version_str = subprocess.run(
+ [
+ sys.executable,
+ "-sS",
+ "-c",
+ "import platform; print(platform.mac_ver()[0])",
+ ],
+ check=True,
+ env={"SYSTEM_VERSION_COMPAT": "0"},
+ stdout=subprocess.PIPE,
+ universal_newlines=True,
+ ).stdout
+ version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
else:
version = version
if arch is None:
@@ -473,6 +499,9 @@ def sys_tags(*, warn: bool = False) -> Iterator[Tag]:
yield from generic_tags()
if interp_name == "pp":
- yield from compatible_tags(interpreter="pp3")
+ interp = "pp3"
+ elif interp_name == "cp":
+ interp = "cp" + interpreter_version(warn=warn)
else:
- yield from compatible_tags()
+ interp = None
+ yield from compatible_tags(interpreter=interp)
diff --git a/src/wheel/vendored/vendor.txt b/src/wheel/vendored/vendor.txt
index df56c23..a75029c 100644
--- a/src/wheel/vendored/vendor.txt
+++ b/src/wheel/vendored/vendor.txt
@@ -1 +1 @@
-packaging==21.3
+packaging==22.0