Skip to content

Commit

Permalink
Updated vendored packaging to 24.0
Browse files Browse the repository at this point in the history
agronholm committed Mar 10, 2024
1 parent a9119c8 commit 92921a0
Showing 14 changed files with 95 additions and 68 deletions.
1 change: 1 addition & 0 deletions docs/news.rst
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ Release Notes
**UNRELEASED**

- Dropped support for Python 3.7
- Updated vendored ``packaging`` to 24.0

**0.42.0 (2023-11-26)**

6 changes: 3 additions & 3 deletions src/wheel/bdist_wheel.py
Original file line number Diff line number Diff line change
@@ -412,9 +412,9 @@ def run(self):
)

self.set_undefined_options("install_egg_info", ("target", "egginfo_dir"))
distinfo_dirname = "{}-{}.dist-info".format(
safer_name(self.distribution.get_name()),
safer_version(self.distribution.get_version()),
distinfo_dirname = (
f"{safer_name(self.distribution.get_name())}-"
f"{safer_version(self.distribution.get_version())}.dist-info"
)
distinfo_dir = os.path.join(self.bdist_dir, distinfo_dirname)
self.egg2dist(self.egginfo_dir, distinfo_dir)
4 changes: 2 additions & 2 deletions src/wheel/cli/pack.py
Original file line number Diff line number Diff line change
@@ -45,8 +45,8 @@ def pack(directory: str, dest_dir: str, build_number: str | None) -> None:

if not tags:
raise WheelError(
"No tags present in {}/WHEEL; cannot determine target wheel "
"filename".format(dist_info_dir)
f"No tags present in {dist_info_dir}/WHEEL; cannot determine target "
f"wheel filename"
)

# Set the wheel file name and add/replace/remove the Build tag in .dist-info/WHEEL
1 change: 1 addition & 0 deletions src/wheel/metadata.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Tools for converting old- to new-style metadata.
"""

from __future__ import annotations

import functools
16 changes: 12 additions & 4 deletions src/wheel/vendored/packaging/_manylinux.py
Original file line number Diff line number Diff line change
@@ -55,7 +55,15 @@ def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool:
return _is_linux_armhf(executable)
if "i686" in archs:
return _is_linux_i686(executable)
allowed_archs = {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x", "loongarch64"}
allowed_archs = {
"x86_64",
"aarch64",
"ppc64",
"ppc64le",
"s390x",
"loongarch64",
"riscv64",
}
return any(arch in allowed_archs for arch in archs)


@@ -82,7 +90,7 @@ def _glibc_version_string_confstr() -> Optional[str]:
# https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183
try:
# Should be a string like "glibc 2.17".
version_string: str = getattr(os, "confstr")("CS_GNU_LIBC_VERSION")
version_string: Optional[str] = os.confstr("CS_GNU_LIBC_VERSION")
assert version_string is not None
_, version = version_string.rsplit()
except (AssertionError, AttributeError, OSError, ValueError):
@@ -159,7 +167,7 @@ def _parse_glibc_version(version_str: str) -> Tuple[int, int]:
return int(m.group("major")), int(m.group("minor"))


@functools.lru_cache()
@functools.lru_cache
def _get_glibc_version() -> Tuple[int, int]:
version_str = _glibc_version_string()
if version_str is None:
@@ -174,7 +182,7 @@ def _is_compatible(arch: str, version: _GLibCVersion) -> bool:
return False
# Check for presence of _manylinux module.
try:
import _manylinux # noqa
import _manylinux
except ImportError:
return True
if hasattr(_manylinux, "manylinux_compatible"):
2 changes: 1 addition & 1 deletion src/wheel/vendored/packaging/_musllinux.py
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ def _parse_musl_version(output: str) -> Optional[_MuslVersion]:
return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2)))


@functools.lru_cache()
@functools.lru_cache
def _get_musl_version(executable: str) -> Optional[_MuslVersion]:
"""Detect currently-running musl runtime version.
7 changes: 2 additions & 5 deletions src/wheel/vendored/packaging/_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Handwritten parser of dependency specifiers.
The docstring for each __parse_* function contains ENBF-inspired grammar representing
The docstring for each __parse_* function contains EBNF-inspired grammar representing
the implementation.
"""

@@ -324,10 +324,7 @@ def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar:


def process_env_var(env_var: str) -> Variable:
if (
env_var == "platform_python_implementation"
or env_var == "python_implementation"
):
if env_var in ("platform_python_implementation", "python_implementation"):
return Variable("platform_python_implementation")
else:
return Variable(env_var)
3 changes: 2 additions & 1 deletion src/wheel/vendored/packaging/markers.py
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
Op,
Value,
Variable,
)
from ._parser import (
parse_marker as _parse_marker,
)
from ._tokenizer import ParserSyntaxError
@@ -69,7 +71,6 @@ def _normalize_extra_values(results: Any) -> Any:
def _format_marker(
marker: Union[List[str], MarkerAtom, str], first: Optional[bool] = True
) -> str:

assert isinstance(marker, (list, tuple, str))

# Sometimes we have a structure like [[...]] which is a single item list
2 changes: 1 addition & 1 deletion src/wheel/vendored/packaging/requirements.py
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ def __init__(self, requirement_string: str) -> None:

self.name: str = parsed.name
self.url: Optional[str] = parsed.url or None
self.extras: Set[str] = set(parsed.extras if parsed.extras else [])
self.extras: Set[str] = set(parsed.extras or [])
self.specifier: SpecifierSet = SpecifierSet(parsed.specifier)
self.marker: Optional[Marker] = None
if parsed.marker is not None:
69 changes: 36 additions & 33 deletions src/wheel/vendored/packaging/specifiers.py
Original file line number Diff line number Diff line change
@@ -11,17 +11,7 @@
import abc
import itertools
import re
from typing import (
Callable,
Iterable,
Iterator,
List,
Optional,
Set,
Tuple,
TypeVar,
Union,
)
from typing import Callable, Iterable, Iterator, List, Optional, Tuple, TypeVar, Union

from .utils import canonicalize_version
from .version import Version
@@ -374,7 +364,6 @@ def _get_operator(self, op: str) -> CallableOperator:
return operator_callable

def _compare_compatible(self, prospective: Version, spec: str) -> bool:

# Compatible releases have an equivalent combination of >= and ==. That
# is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
# implement this in terms of the other specifiers instead of
@@ -383,7 +372,7 @@ def _compare_compatible(self, prospective: Version, spec: str) -> bool:

# We want everything but the last item in the version, but we want to
# ignore suffix segments.
prefix = ".".join(
prefix = _version_join(
list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1]
)

@@ -395,7 +384,6 @@ def _compare_compatible(self, prospective: Version, spec: str) -> bool:
)

def _compare_equal(self, prospective: Version, spec: str) -> bool:

# We need special logic to handle prefix matching
if spec.endswith(".*"):
# In the case of prefix matching we want to ignore local segment.
@@ -404,13 +392,13 @@ def _compare_equal(self, prospective: Version, spec: str) -> bool:
)
# Get the normalized version string ignoring the trailing .*
normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False)
# Split the spec out by dots, and pretend that there is an implicit
# dot in between a release segment and a pre-release segment.
# Split the spec out by bangs and dots, and pretend that there is
# an implicit dot in between a release segment and a pre-release segment.
split_spec = _version_split(normalized_spec)

# Split the prospective version out by dots, and pretend that there
# is an implicit dot in between a release segment and a pre-release
# segment.
# Split the prospective version out by bangs and dots, and pretend
# that there is an implicit dot in between a release segment and
# a pre-release segment.
split_prospective = _version_split(normalized_prospective)

# 0-pad the prospective version before shortening it to get the correct
@@ -439,21 +427,18 @@ def _compare_not_equal(self, prospective: Version, spec: str) -> bool:
return not self._compare_equal(prospective, spec)

def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool:

# NB: Local version identifiers are NOT permitted in the version
# specifier, so local version labels can be universally removed from
# the prospective version.
return Version(prospective.public) <= Version(spec)

def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool:

# NB: Local version identifiers are NOT permitted in the version
# specifier, so local version labels can be universally removed from
# the prospective version.
return Version(prospective.public) >= Version(spec)

def _compare_less_than(self, prospective: Version, spec_str: str) -> bool:

# Convert our spec to a Version instance, since we'll want to work with
# it as a version.
spec = Version(spec_str)
@@ -478,7 +463,6 @@ def _compare_less_than(self, prospective: Version, spec_str: str) -> bool:
return True

def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool:

# Convert our spec to a Version instance, since we'll want to work with
# it as a version.
spec = Version(spec_str)
@@ -644,8 +628,19 @@ def filter(


def _version_split(version: str) -> List[str]:
"""Split version into components.
The split components are intended for version comparison. The logic does
not attempt to retain the original version string, so joining the
components back with :func:`_version_join` may not produce the original
version string.
"""
result: List[str] = []
for item in version.split("."):

epoch, _, rest = version.rpartition("!")
result.append(epoch or "0")

for item in rest.split("."):
match = _prefix_regex.search(item)
if match:
result.extend(match.groups())
@@ -654,6 +649,17 @@ def _version_split(version: str) -> List[str]:
return result


def _version_join(components: List[str]) -> str:
"""Join split version components into a version string.
This function assumes the input came from :func:`_version_split`, where the
first component must be the epoch (either empty or numeric), and all other
components numeric.
"""
epoch, *rest = components
return f"{epoch}!{'.'.join(rest)}"


def _is_not_suffix(segment: str) -> bool:
return not any(
segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post")
@@ -675,7 +681,10 @@ def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str
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)))
return (
list(itertools.chain.from_iterable(left_split)),
list(itertools.chain.from_iterable(right_split)),
)


class SpecifierSet(BaseSpecifier):
@@ -707,14 +716,8 @@ def __init__(
# strip each item to remove leading/trailing whitespace.
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]

# Parsed each individual specifier, attempting first to make it a
# Specifier.
parsed: Set[Specifier] = set()
for specifier in split_specifiers:
parsed.add(Specifier(specifier))

# Turn our parsed specifiers into a frozen set and save them for later.
self._specs = frozenset(parsed)
# Make each individual specifier a Specifier and save in a frozen set for later.
self._specs = frozenset(map(Specifier, split_specifiers))

# Store our prereleases value so we can use it later to determine if
# we accept prereleases or not.
44 changes: 31 additions & 13 deletions src/wheel/vendored/packaging/tags.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

import logging
import platform
import re
import struct
import subprocess
import sys
@@ -124,20 +125,37 @@ def _normalize_string(string: str) -> str:
return string.replace(".", "_").replace("-", "_").replace(" ", "_")


def _abi3_applies(python_version: PythonVersion) -> bool:
def _is_threaded_cpython(abis: List[str]) -> bool:
"""
Determine if the ABI corresponds to a threaded (`--disable-gil`) build.
The threaded builds are indicated by a "t" in the abiflags.
"""
if len(abis) == 0:
return False
# expect e.g., cp313
m = re.match(r"cp\d+(.*)", abis[0])
if not m:
return False
abiflags = m.group(1)
return "t" in abiflags


def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool:
"""
Determine if the Python version supports abi3.
PEP 384 was first implemented in Python 3.2.
PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`)
builds do not support abi3.
"""
return len(python_version) > 1 and tuple(python_version) >= (3, 2)
return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading


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])
debug = pymalloc = ucs4 = ""
threading = debug = pymalloc = ucs4 = ""
with_debug = _get_config_var("Py_DEBUG", warn)
has_refcount = hasattr(sys, "gettotalrefcount")
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
@@ -146,6 +164,8 @@ def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]:
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
if with_debug or (with_debug is None and (has_refcount or has_ext)):
debug = "d"
if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn):
threading = "t"
if py_version < (3, 8):
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
if with_pymalloc or with_pymalloc is None:
@@ -159,13 +179,8 @@ def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]:
elif debug:
# Debug builds can also load "normal" extension modules.
# We can also assume no UCS-4 or pymalloc requirement.
abis.append(f"cp{version}")
abis.insert(
0,
"cp{version}{debug}{pymalloc}{ucs4}".format(
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
),
)
abis.append(f"cp{version}{threading}")
abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}")
return abis


@@ -213,11 +228,14 @@ def cpython_tags(
for abi in abis:
for platform_ in platforms:
yield Tag(interpreter, abi, platform_)
if _abi3_applies(python_version):

threading = _is_threaded_cpython(abis)
use_abi3 = _abi3_applies(python_version, threading)
if use_abi3:
yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms)
yield from (Tag(interpreter, "none", platform_) for platform_ in platforms)

if _abi3_applies(python_version):
if use_abi3:
for minor_version in range(python_version[1] - 1, 1, -1):
for platform_ in platforms:
interpreter = "cp{version}".format(
2 changes: 0 additions & 2 deletions src/wheel/vendored/packaging/version.py
Original file line number Diff line number Diff line change
@@ -452,7 +452,6 @@ def micro(self) -> int:
def _parse_letter_version(
letter: Optional[str], number: Union[str, bytes, SupportsInt, None]
) -> Optional[Tuple[str, int]]:

if letter:
# We consider there to be an implicit 0 in a pre-release if there is
# not a numeral associated with it.
@@ -508,7 +507,6 @@ def _cmpkey(
dev: Optional[Tuple[str, int]],
local: Optional[LocalType],
) -> CmpKey:

# When we compare a release version, we want to compare it with all of the
# trailing zeros removed. So we'll use a reverse the list, drop all the now
# leading zeros until we come to something non zero, then take the rest
2 changes: 1 addition & 1 deletion src/wheel/vendored/vendor.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
packaging==23.2
packaging==24.0
4 changes: 2 additions & 2 deletions src/wheel/wheelfile.py
Original file line number Diff line number Diff line change
@@ -81,8 +81,8 @@ def __init__(self, file, mode="r", compression=ZIP_DEFLATED):

if algorithm.lower() in {"md5", "sha1"}:
raise WheelError(
"Weak hash algorithm ({}) is not permitted by PEP "
"427".format(algorithm)
f"Weak hash algorithm ({algorithm}) is not permitted by "
f"PEP 427"
)

self._file_hashes[path] = (

0 comments on commit 92921a0

Please sign in to comment.