Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-wheel for openSUSE:Factory checked in at 2023-12-28 22:54:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-wheel (Old) and /work/SRC/openSUSE:Factory/.python-wheel.new.28375 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-wheel" Thu Dec 28 22:54:41 2023 rev:35 rq:1135267 version:0.42.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-wheel/python-wheel.changes 2023-09-07 21:14:02.108081024 +0200 +++ /work/SRC/openSUSE:Factory/.python-wheel.new.28375/python-wheel.changes 2023-12-28 22:54:46.347771721 +0100 @@ -1,0 +2,17 @@ +Fri Dec 22 15:31:14 UTC 2023 - Ben Greiner <c...@bnavigator.de> + +- Update to 0.42.0 + * Allowed removing build tag with wheel tags --build "" + * Fixed wheel pack and wheel tags writing updated WHEEL fields + after a blank line, causing other tools to ignore them + * Fixed wheel pack and wheel tags writing WHEEL with CRLF line + endings or a mix of CRLF and LF + * Fixed wheel pack --build-number "" not removing build tag from + WHEEL (above changes by Benjamin Gilbert) +- Release 0.41.3 + * Updated vendored packaging to 23.2 + * Fixed ABI tag generation for CPython 3.13a1 on Windows (PR by + Sam Gross) +- Remove pip dependency for easier bootstrap + +------------------------------------------------------------------- Old: ---- wheel-0.41.2.tar.gz New: ---- wheel-0.42.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-wheel.spec ++++++ --- /var/tmp/diff_new_pack.M6B3Lu/_old 2023-12-28 22:54:47.147800927 +0100 +++ /var/tmp/diff_new_pack.M6B3Lu/_new 2023-12-28 22:54:47.151801073 +0100 @@ -32,16 +32,16 @@ %endif %{?sle15_python_module_pythons} Name: python-wheel%{psuffix} -Version: 0.41.2 +Version: 0.42.0 Release: 0 Summary: A built-package format for Python License: MIT Group: Development/Languages/Python URL: https://github.com/pypa/wheel Source: https://github.com/pypa/wheel/archive/%{version}.tar.gz#/wheel-%{version}.tar.gz +# Bootstrap: Don't BuildRequire setuptools or pip here! BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module flit-core} -BuildRequires: %{python_module pip} BuildRequires: fdupes BuildRequires: python-rpm-macros >= 20210929 %if %{with libalternatives} @@ -74,11 +74,21 @@ %autosetup -p1 -n wheel-%{version} %build -%pyproject_wheel +%if !%{with test} +%{python_expand # bootstrap with built-in pip +$python -m venv build/env +build/env/bin/python -m ensurepip +export PYTHONPATH=build/env/lib/python%{$python_bin_suffix}/site-packages +%{$python_pyproject_wheel} +} +%endif %install %if !%{with test} -%pyproject_install +%{python_expand # use pip bootstrapped above +export PYTHONPATH=build/env/lib/python%{$python_bin_suffix}/site-packages +%{$python_pyproject_install} +} %python_clone -a %{buildroot}%{_bindir}/wheel %python_expand %fdupes %{buildroot}%{$python_sitelib} %endif ++++++ wheel-0.41.2.tar.gz -> wheel-0.42.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/.github/workflows/publish.yml new/wheel-0.42.0/.github/workflows/publish.yml --- old/wheel-0.41.2/.github/workflows/publish.yml 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/.github/workflows/publish.yml 2023-11-26 15:35:45.000000000 +0100 @@ -13,7 +13,7 @@ runs-on: ubuntu-latest environment: release steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -39,3 +39,20 @@ uses: actions/download-artifact@v3 - name: Upload packages uses: pypa/gh-action-pypi-publish@release/v1 + + release: + name: Create a GitHub release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - id: changelog + uses: agronholm/release-notes@v1 + with: + path: docs/news.rst + version_pattern: "^\\*\\*([0-9a-z.]+) " + - uses: ncipollo/release-action@v1 + with: + body: ${{ steps.changelog.outputs.changelog }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/.github/workflows/test.yml new/wheel-0.42.0/.github/workflows/test.yml --- old/wheel-0.41.2/.github/workflows/test.yml 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/.github/workflows/test.yml 2023-11-26 15:35:45.000000000 +0100 @@ -14,7 +14,7 @@ fail-fast: false matrix: os: [ubuntu-latest] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8", "pypy-3.9"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.8", "pypy-3.9"] include: - os: macos-latest python-version: "3.7" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/.pre-commit-config.yaml new/wheel-0.42.0/.pre-commit-config.yaml --- old/wheel-0.41.2/.pre-commit-config.yaml 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/.pre-commit-config.yaml 2023-11-26 15:35:45.000000000 +0100 @@ -2,7 +2,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -18,18 +18,14 @@ - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.285 + rev: v0.1.6 hooks: - id: ruff args: [--fix, --show-fixes] - -- repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.7.0 - hooks: - - id: black + - id: ruff-format - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/docs/news.rst new/wheel-0.42.0/docs/news.rst --- old/wheel-0.41.2/docs/news.rst 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/docs/news.rst 2023-11-26 15:35:45.000000000 +0100 @@ -1,6 +1,21 @@ Release Notes ============= +**0.42.0 (2023-11-26)** + +- Allowed removing build tag with ``wheel tags --build ""`` +- Fixed ``wheel pack`` and ``wheel tags`` writing updated ``WHEEL`` fields after a + blank line, causing other tools to ignore them +- Fixed ``wheel pack`` and ``wheel tags`` writing ``WHEEL`` with CRLF line endings or + a mix of CRLF and LF +- Fixed ``wheel pack --build-number ""`` not removing build tag from ``WHEEL`` + (above changes by Benjamin Gilbert) + +**0.41.3 (2023-10-30)** + +- Updated vendored ``packaging`` to 23.2 +- Fixed ABI tag generation for CPython 3.13a1 on Windows (PR by Sam Gross) + **0.41.2 (2023-08-22)** - Fixed platform tag detection for GraalPy and 32-bit python running on an aarch64 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/pyproject.toml new/wheel-0.42.0/pyproject.toml --- old/wheel-0.41.2/pyproject.toml 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/pyproject.toml 2023-11-26 15:35:45.000000000 +0100 @@ -30,6 +30,7 @@ Documentation = "https://wheel.readthedocs.io/" Changelog = "https://wheel.readthedocs.io/en/stable/news.html" "Issue Tracker" = "https://github.com/pypa/wheel/issues" +Source = "https://github.com/pypa/wheel" [project.scripts] wheel = "wheel.cli:main" @@ -110,7 +111,7 @@ [tool.tox] legacy_tox_ini = ''' [tox] -envlist = py37, py38, py39, py310, py311, py312, pypy3, lint, pkg +envlist = py37, py38, py39, py310, py311, py312, py313, pypy3, lint, pkg minversion = 4.0.0 skip_missing_interpreters = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/__init__.py new/wheel-0.42.0/src/wheel/__init__.py --- old/wheel-0.41.2/src/wheel/__init__.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/__init__.py 2023-11-26 15:35:45.000000000 +0100 @@ -1,3 +1,3 @@ from __future__ import annotations -__version__ = "0.41.2" +__version__ = "0.42.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/bdist_wheel.py new/wheel-0.42.0/src/wheel/bdist_wheel.py --- old/wheel-0.41.2/src/wheel/bdist_wheel.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/bdist_wheel.py 2023-11-26 15:35:45.000000000 +0100 @@ -17,7 +17,6 @@ from email.generator import BytesGenerator, Generator from email.policy import EmailPolicy from glob import iglob -from io import BytesIO from shutil import rmtree from zipfile import ZIP_DEFLATED, ZIP_STORED @@ -117,8 +116,12 @@ m = "m" abi = f"{impl}{tags.interpreter_version()}{d}{m}{u}" - elif soabi and impl == "cp": + elif soabi and impl == "cp" and soabi.startswith("cpython"): + # non-Windows abi = "cp" + soabi.split("-")[1] + elif soabi and impl == "cp" and soabi.startswith("cp"): + # Windows + abi = soabi.split("-")[0] elif soabi and impl == "pp": # we want something like pypy36-pp73 abi = "-".join(soabi.split("-")[:2]) @@ -194,8 +197,9 @@ ( "compression=", None, - "zipfile compression (one of: {})" - " (default: 'deflated')".format(", ".join(supported_compressions)), + "zipfile compression (one of: {})" " (default: 'deflated')".format( + ", ".join(supported_compressions) + ), ), ( "python-tag=", @@ -463,10 +467,8 @@ wheelfile_path = os.path.join(wheelfile_base, "WHEEL") log.info(f"creating {wheelfile_path}") - buffer = BytesIO() - BytesGenerator(buffer, maxheaderlen=0).flatten(msg) with open(wheelfile_path, "wb") as f: - f.write(buffer.getvalue().replace(b"\r\n", b"\r")) + BytesGenerator(f, maxheaderlen=0).flatten(msg) def _ensure_relative(self, path): # copied from dir_util, deleted diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/cli/__init__.py new/wheel-0.42.0/src/wheel/cli/__init__.py --- old/wheel-0.41.2/src/wheel/cli/__init__.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/cli/__init__.py 2023-11-26 15:35:45.000000000 +0100 @@ -58,7 +58,7 @@ def parse_build_tag(build_tag: str) -> str: - if not build_tag[0].isdigit(): + if build_tag and not build_tag[0].isdigit(): raise ArgumentTypeError("build tag must begin with a digit") elif "-" in build_tag: raise ArgumentTypeError("invalid character ('-') in build tag") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/cli/convert.py new/wheel-0.42.0/src/wheel/cli/convert.py --- old/wheel-0.41.2/src/wheel/cli/convert.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/cli/convert.py 2023-11-26 15:35:45.000000000 +0100 @@ -42,7 +42,7 @@ return bdist_wheel.get_tag(self) -def egg2wheel(egg_path: str, dest_dir: str): +def egg2wheel(egg_path: str, dest_dir: str) -> None: filename = os.path.basename(egg_path) match = egg_info_re.match(filename) if not match: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/cli/pack.py new/wheel-0.42.0/src/wheel/cli/pack.py --- old/wheel-0.41.2/src/wheel/cli/pack.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/cli/pack.py 2023-11-26 15:35:45.000000000 +0100 @@ -1,16 +1,18 @@ from __future__ import annotations +import email.policy import os.path import re +from email.generator import BytesGenerator +from email.parser import BytesParser from wheel.cli import WheelError from wheel.wheelfile import WheelFile DIST_INFO_RE = re.compile(r"^(?P<namever>(?P<name>.+?)-(?P<ver>\d.*?))\.dist-info$") -BUILD_NUM_RE = re.compile(rb"Build: (\d\w*)$") -def pack(directory: str, dest_dir: str, build_number: str | None): +def pack(directory: str, dest_dir: str, build_number: str | None) -> None: """Repack a previously unpacked wheel directory into a new wheel file. The .dist-info/WHEEL file must contain one or more tags so that the target @@ -35,10 +37,11 @@ name_version = DIST_INFO_RE.match(dist_info_dir).group("namever") # Read the tags and the existing build number from .dist-info/WHEEL - existing_build_number = None wheel_file_path = os.path.join(directory, dist_info_dir, "WHEEL") with open(wheel_file_path, "rb") as f: - tags, existing_build_number = read_tags(f.read()) + info = BytesParser(policy=email.policy.compat32).parse(f) + tags: list[str] = info.get_all("Tag", []) + existing_build_number = info.get("Build") if not tags: raise WheelError( @@ -49,17 +52,14 @@ # Set the wheel file name and add/replace/remove the Build tag in .dist-info/WHEEL build_number = build_number if build_number is not None else existing_build_number if build_number is not None: + del info["Build"] if build_number: + info["Build"] = build_number name_version += "-" + build_number if build_number != existing_build_number: - with open(wheel_file_path, "rb+") as f: - wheel_file_content = f.read() - wheel_file_content = set_build_number(wheel_file_content, build_number) - - f.seek(0) - f.truncate() - f.write(wheel_file_content) + with open(wheel_file_path, "wb") as f: + BytesGenerator(f, maxheaderlen=0).flatten(info) # Reassemble the tags for the wheel file tagline = compute_tagline(tags) @@ -73,45 +73,6 @@ print("OK") -def read_tags(input_str: bytes) -> tuple[list[str], str | None]: - """Read tags from a string. - - :param input_str: A string containing one or more tags, separated by spaces - :return: A list of tags and a list of build tags - """ - - tags = [] - existing_build_number = None - for line in input_str.splitlines(): - if line.startswith(b"Tag: "): - tags.append(line.split(b" ")[1].rstrip().decode("ascii")) - elif line.startswith(b"Build: "): - existing_build_number = line.split(b" ")[1].rstrip().decode("ascii") - - return tags, existing_build_number - - -def set_build_number(wheel_file_content: bytes, build_number: str | None) -> bytes: - """Compute a build tag and add/replace/remove as necessary. - - :param wheel_file_content: The contents of .dist-info/WHEEL - :param build_number: The build tags present in .dist-info/WHEEL - :return: The (modified) contents of .dist-info/WHEEL - """ - replacement = ( - ("Build: %s\r\n" % build_number).encode("ascii") if build_number else b"" - ) - - wheel_file_content, num_replaced = BUILD_NUM_RE.subn( - replacement, wheel_file_content - ) - - if not num_replaced: - wheel_file_content += replacement - - return wheel_file_content - - def compute_tagline(tags: list[str]) -> str: """Compute a tagline from a list of tags. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/cli/tags.py new/wheel-0.42.0/src/wheel/cli/tags.py --- old/wheel-0.41.2/src/wheel/cli/tags.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/cli/tags.py 2023-11-26 15:35:45.000000000 +0100 @@ -1,11 +1,12 @@ from __future__ import annotations +import email.policy import itertools import os from collections.abc import Iterable +from email.parser import BytesParser from ..wheelfile import WheelFile -from .pack import read_tags, set_build_number def _compute_tags(original_tags: Iterable[str], new_tags: str | None) -> set[str]: @@ -48,6 +49,7 @@ assert f.filename, f"{f.filename} must be available" wheel_info = f.read(f.dist_info_path + "/WHEEL") + info = BytesParser(policy=email.policy.compat32).parsebytes(wheel_info) original_wheel_name = os.path.basename(f.filename) namever = f.parsed_filename.group("namever") @@ -56,7 +58,8 @@ original_abi_tags = f.parsed_filename.group("abi").split(".") original_plat_tags = f.parsed_filename.group("plat").split(".") - tags, existing_build_tag = read_tags(wheel_info) + tags: list[str] = info.get_all("Tag", []) + existing_build_tag = info.get("Build") impls = {tag.split("-")[0] for tag in tags} abivers = {tag.split("-")[1] for tag in tags} @@ -103,12 +106,13 @@ final_wheel_name = "-".join(final_tags) + ".whl" if original_wheel_name != final_wheel_name: - tags = [ - f"{a}-{b}-{c}" - for a, b, c in itertools.product( - final_python_tags, final_abi_tags, final_plat_tags - ) - ] + del info["Tag"], info["Build"] + for a, b, c in itertools.product( + final_python_tags, final_abi_tags, final_plat_tags + ): + info["Tag"] = f"{a}-{b}-{c}" + if build: + info["Build"] = build original_wheel_path = os.path.join( os.path.dirname(f.filename), original_wheel_name @@ -125,10 +129,7 @@ if item.filename == f.dist_info_path + "/RECORD": continue if item.filename == f.dist_info_path + "/WHEEL": - content = fin.read(item) - content = set_tags(content, tags) - content = set_build_number(content, build) - fout.writestr(item, content) + fout.writestr(item, info.as_bytes()) else: fout.writestr(item, fin.read(item)) @@ -136,18 +137,3 @@ os.remove(original_wheel_path) return final_wheel_name - - -def set_tags(in_string: bytes, tags: Iterable[str]) -> bytes: - """Set the tags in the .dist-info/WHEEL file contents. - - :param in_string: The string to modify. - :param tags: The tags to set. - """ - - lines = [line for line in in_string.splitlines() if not line.startswith(b"Tag:")] - for tag in tags: - lines.append(b"Tag: " + tag.encode("ascii")) - in_string = b"\r\n".join(lines) + b"\r\n" - - return in_string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/_manylinux.py new/wheel-0.42.0/src/wheel/vendored/packaging/_manylinux.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/_manylinux.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/_manylinux.py 2023-11-26 15:35:45.000000000 +0100 @@ -5,7 +5,7 @@ import re import sys import warnings -from typing import Dict, Generator, Iterator, NamedTuple, Optional, Tuple +from typing import Dict, Generator, Iterator, NamedTuple, Optional, Sequence, Tuple from ._elffile import EIClass, EIData, ELFFile, EMachine @@ -14,6 +14,8 @@ EF_ARM_ABI_FLOAT_HARD = 0x00000400 +# `os.PathLike` not a generic type until Python 3.9, so sticking with `str` +# as the type for `path` until then. @contextlib.contextmanager def _parse_elf(path: str) -> Generator[Optional[ELFFile], None, None]: try: @@ -48,12 +50,13 @@ ) -def _have_compatible_abi(executable: str, arch: str) -> bool: - if arch == "armv7l": +def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool: + if "armv7l" in archs: return _is_linux_armhf(executable) - if arch == "i686": + if "i686" in archs: return _is_linux_i686(executable) - return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} + allowed_archs = {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x", "loongarch64"} + return any(arch in allowed_archs for arch in archs) # If glibc ever changes its major version, we need to know what the last @@ -165,7 +168,7 @@ # From PEP 513, PEP 600 -def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: +def _is_compatible(arch: str, version: _GLibCVersion) -> bool: sys_glibc = _get_glibc_version() if sys_glibc < version: return False @@ -201,12 +204,22 @@ } -def platform_tags(linux: str, arch: str) -> Iterator[str]: - if not _have_compatible_abi(sys.executable, arch): +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate manylinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be manylinux-compatible. + + :returns: An iterator of compatible manylinux tags. + """ + if not _have_compatible_abi(sys.executable, archs): return # Oldest glibc to be supported regardless of architecture is (2, 17). too_old_glibc2 = _GLibCVersion(2, 16) - if arch in {"x86_64", "i686"}: + if set(archs) & {"x86_64", "i686"}: # On x86/i686 also oldest glibc to be supported is (2, 5). too_old_glibc2 = _GLibCVersion(2, 4) current_glibc = _GLibCVersion(*_get_glibc_version()) @@ -220,19 +233,20 @@ for glibc_major in range(current_glibc.major - 1, 1, -1): glibc_minor = _LAST_GLIBC_MINOR[glibc_major] glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) - for glibc_max in glibc_max_list: - if glibc_max.major == too_old_glibc2.major: - min_minor = too_old_glibc2.minor - else: - # For other glibc major versions oldest supported is (x, 0). - min_minor = -1 - for glibc_minor in range(glibc_max.minor, min_minor, -1): - glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) - tag = "manylinux_{}_{}".format(*glibc_version) - if _is_compatible(tag, arch, glibc_version): - yield linux.replace("linux", tag) - # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. - if glibc_version in _LEGACY_MANYLINUX_MAP: - legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] - if _is_compatible(legacy_tag, arch, glibc_version): - yield linux.replace("linux", legacy_tag) + for arch in archs: + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(arch, glibc_version): + yield f"{tag}_{arch}" + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(arch, glibc_version): + yield f"{legacy_tag}_{arch}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/_musllinux.py new/wheel-0.42.0/src/wheel/vendored/packaging/_musllinux.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/_musllinux.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/_musllinux.py 2023-11-26 15:35:45.000000000 +0100 @@ -8,7 +8,7 @@ import re import subprocess import sys -from typing import Iterator, NamedTuple, Optional +from typing import Iterator, NamedTuple, Optional, Sequence from ._elffile import ELFFile @@ -47,24 +47,27 @@ return None if ld is None or "musl" not in ld: return None - proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) + proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True) return _parse_musl_version(proc.stderr) -def platform_tags(arch: str) -> Iterator[str]: +def platform_tags(archs: Sequence[str]) -> Iterator[str]: """Generate musllinux tags compatible to the current platform. - :param arch: Should be the part of platform tag after the ``linux_`` - prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a - prerequisite for the current platform to be musllinux-compatible. + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be musllinux-compatible. :returns: An iterator of compatible musllinux tags. """ sys_musl = _get_musl_version(sys.executable) if sys_musl is None: # Python not dynamically linked against musl. return - for minor in range(sys_musl.minor, -1, -1): - yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + for arch in archs: + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" if __name__ == "__main__": # pragma: no cover diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/_parser.py new/wheel-0.42.0/src/wheel/vendored/packaging/_parser.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/_parser.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/_parser.py 2023-11-26 15:35:45.000000000 +0100 @@ -163,7 +163,11 @@ if not tokenizer.check("LEFT_BRACKET", peek=True): return [] - with tokenizer.enclosing_tokens("LEFT_BRACKET", "RIGHT_BRACKET"): + with tokenizer.enclosing_tokens( + "LEFT_BRACKET", + "RIGHT_BRACKET", + around="extras", + ): tokenizer.consume("WS") extras = _parse_extras_list(tokenizer) tokenizer.consume("WS") @@ -203,7 +207,11 @@ specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS | WS? version_many WS? """ - with tokenizer.enclosing_tokens("LEFT_PARENTHESIS", "RIGHT_PARENTHESIS"): + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="version specifier", + ): tokenizer.consume("WS") parsed_specifiers = _parse_version_many(tokenizer) tokenizer.consume("WS") @@ -217,7 +225,20 @@ """ parsed_specifiers = "" while tokenizer.check("SPECIFIER"): + span_start = tokenizer.position parsed_specifiers += tokenizer.read().text + if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True): + tokenizer.raise_syntax_error( + ".* suffix can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position + 1, + ) + if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True): + tokenizer.raise_syntax_error( + "Local version label can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position, + ) tokenizer.consume("WS") if not tokenizer.check("COMMA"): break @@ -231,7 +252,13 @@ # Recursive descent parser for marker expression # -------------------------------------------------------------------------------------- def parse_marker(source: str) -> MarkerList: - return _parse_marker(Tokenizer(source, rules=DEFAULT_RULES)) + return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList: + retval = _parse_marker(tokenizer) + tokenizer.expect("END", expected="end of marker expression") + return retval def _parse_marker(tokenizer: Tokenizer) -> MarkerList: @@ -254,7 +281,11 @@ tokenizer.consume("WS") if tokenizer.check("LEFT_PARENTHESIS", peek=True): - with tokenizer.enclosing_tokens("LEFT_PARENTHESIS", "RIGHT_PARENTHESIS"): + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="marker expression", + ): tokenizer.consume("WS") marker: MarkerAtom = _parse_marker(tokenizer) tokenizer.consume("WS") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/_tokenizer.py new/wheel-0.42.0/src/wheel/vendored/packaging/_tokenizer.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/_tokenizer.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/_tokenizer.py 2023-11-26 15:35:45.000000000 +0100 @@ -78,6 +78,8 @@ "AT": r"\@", "URL": r"[^ \t]+", "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", + "VERSION_PREFIX_TRAIL": r"\.\*", + "VERSION_LOCAL_LABEL_TRAIL": r"\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*", "WS": r"[ \t]+", "END": r"$", } @@ -167,21 +169,23 @@ ) @contextlib.contextmanager - def enclosing_tokens(self, open_token: str, close_token: str) -> Iterator[bool]: + def enclosing_tokens( + self, open_token: str, close_token: str, *, around: str + ) -> Iterator[None]: if self.check(open_token): open_position = self.position self.read() else: open_position = None - yield open_position is not None + yield if open_position is None: return if not self.check(close_token): self.raise_syntax_error( - f"Expected closing {close_token}", + f"Expected matching {close_token} for {open_token}, after {around}", span_start=open_position, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/markers.py new/wheel-0.42.0/src/wheel/vendored/packaging/markers.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/markers.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/markers.py 2023-11-26 15:35:45.000000000 +0100 @@ -8,7 +8,14 @@ import sys from typing import Any, Callable, Dict, List, Optional, Tuple, Union -from ._parser import MarkerAtom, MarkerList, Op, Value, Variable, parse_marker +from ._parser import ( + MarkerAtom, + MarkerList, + Op, + Value, + Variable, + parse_marker as _parse_marker, +) from ._tokenizer import ParserSyntaxError from .specifiers import InvalidSpecifier, Specifier from .utils import canonicalize_name @@ -189,7 +196,7 @@ # packaging.requirements.Requirement. If any additional logic is # added here, make sure to mirror/adapt Requirement. try: - self._markers = _normalize_extra_values(parse_marker(marker)) + self._markers = _normalize_extra_values(_parse_marker(marker)) # The attribute `_markers` can be described in terms of a recursive type: # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]] # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/requirements.py new/wheel-0.42.0/src/wheel/vendored/packaging/requirements.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/requirements.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/requirements.py 2023-11-26 15:35:45.000000000 +0100 @@ -2,13 +2,13 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -import urllib.parse -from typing import Any, List, Optional, Set +from typing import Any, Iterator, Optional, Set -from ._parser import parse_requirement +from ._parser import parse_requirement as _parse_requirement from ._tokenizer import ParserSyntaxError from .markers import Marker, _normalize_extra_values from .specifiers import SpecifierSet +from .utils import canonicalize_name class InvalidRequirement(ValueError): @@ -32,23 +32,12 @@ def __init__(self, requirement_string: str) -> None: try: - parsed = parse_requirement(requirement_string) + parsed = _parse_requirement(requirement_string) except ParserSyntaxError as e: raise InvalidRequirement(str(e)) from e self.name: str = parsed.name - if parsed.url: - parsed_url = urllib.parse.urlparse(parsed.url) - if parsed_url.scheme == "file": - if urllib.parse.urlunparse(parsed_url) != parsed.url: - raise InvalidRequirement("Invalid URL given") - elif not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc - ): - raise InvalidRequirement(f"Invalid URL: {parsed.url}") - self.url: Optional[str] = parsed.url - else: - self.url = None + self.url: Optional[str] = parsed.url or None self.extras: Set[str] = set(parsed.extras if parsed.extras else []) self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) self.marker: Optional[Marker] = None @@ -56,38 +45,44 @@ self.marker = Marker.__new__(Marker) self.marker._markers = _normalize_extra_values(parsed.marker) - def __str__(self) -> str: - parts: List[str] = [self.name] + def _iter_parts(self, name: str) -> Iterator[str]: + yield name if self.extras: formatted_extras = ",".join(sorted(self.extras)) - parts.append(f"[{formatted_extras}]") + yield f"[{formatted_extras}]" if self.specifier: - parts.append(str(self.specifier)) + yield str(self.specifier) if self.url: - parts.append(f"@ {self.url}") + yield f"@ {self.url}" if self.marker: - parts.append(" ") + yield " " if self.marker: - parts.append(f"; {self.marker}") + yield f"; {self.marker}" - return "".join(parts) + def __str__(self) -> str: + return "".join(self._iter_parts(self.name)) def __repr__(self) -> str: return f"<Requirement('{self}')>" def __hash__(self) -> int: - return hash((self.__class__.__name__, str(self))) + return hash( + ( + self.__class__.__name__, + *self._iter_parts(canonicalize_name(self.name)), + ) + ) def __eq__(self, other: Any) -> bool: if not isinstance(other, Requirement): return NotImplemented return ( - self.name == other.name + canonicalize_name(self.name) == canonicalize_name(other.name) and self.extras == other.extras and self.specifier == other.specifier and self.url == other.url diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/specifiers.py new/wheel-0.42.0/src/wheel/vendored/packaging/specifiers.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/specifiers.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/specifiers.py 2023-11-26 15:35:45.000000000 +0100 @@ -1,5 +1,4 @@ # 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. """ @@ -253,7 +252,8 @@ # Store whether or not this Specifier should accept prereleases self._prereleases = prereleases - @property + # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515 + @property # type: ignore[override] def prereleases(self) -> bool: # If there is an explicit prereleases set for this, then we'll just # blindly use that. @@ -399,7 +399,9 @@ # We need special logic to handle prefix matching if spec.endswith(".*"): # In the case of prefix matching we want to ignore local segment. - normalized_prospective = canonicalize_version(prospective.public) + normalized_prospective = canonicalize_version( + prospective.public, strip_trailing_zero=False + ) # 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/tags.py new/wheel-0.42.0/src/wheel/vendored/packaging/tags.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/tags.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/tags.py 2023-11-26 15:35:45.000000000 +0100 @@ -4,6 +4,7 @@ import logging import platform +import struct import subprocess import sys import sysconfig @@ -37,7 +38,7 @@ } -_32_BIT_INTERPRETER = sys.maxsize <= 2**32 +_32_BIT_INTERPRETER = struct.calcsize("P") == 4 class Tag: @@ -111,7 +112,7 @@ def _get_config_var(name: str, warn: bool = False) -> Union[int, str, None]: - value = sysconfig.get_config_var(name) + value: Union[int, str, None] = sysconfig.get_config_var(name) if value is None and warn: logger.debug( "Config variable '%s' is unset, Python ABI tag may be incorrect", name @@ -120,7 +121,7 @@ def _normalize_string(string: str) -> str: - return string.replace(".", "_").replace("-", "_") + return string.replace(".", "_").replace("-", "_").replace(" ", "_") def _abi3_applies(python_version: PythonVersion) -> bool: @@ -406,7 +407,7 @@ check=True, env={"SYSTEM_VERSION_COMPAT": "0"}, stdout=subprocess.PIPE, - universal_newlines=True, + text=True, ).stdout version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) else: @@ -469,15 +470,21 @@ def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: linux = _normalize_string(sysconfig.get_platform()) + if not linux.startswith("linux_"): + # we should never be here, just yield the sysconfig one and return + yield linux + return if is_32bit: if linux == "linux_x86_64": linux = "linux_i686" elif linux == "linux_aarch64": - linux = "linux_armv7l" + linux = "linux_armv8l" _, arch = linux.split("_", 1) - yield from _manylinux.platform_tags(linux, arch) - yield from _musllinux.platform_tags(arch) - yield linux + archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch]) + yield from _manylinux.platform_tags(archs) + yield from _musllinux.platform_tags(archs) + for arch in archs: + yield f"linux_{arch}" def _generic_platforms() -> Iterator[str]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/utils.py new/wheel-0.42.0/src/wheel/vendored/packaging/utils.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/utils.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/utils.py 2023-11-26 15:35:45.000000000 +0100 @@ -12,6 +12,12 @@ NormalizedName = NewType("NormalizedName", str) +class InvalidName(ValueError): + """ + An invalid distribution name; users should refer to the packaging user guide. + """ + + class InvalidWheelFilename(ValueError): """ An invalid wheel filename was found, users should refer to PEP 427. @@ -24,17 +30,28 @@ """ +# Core metadata spec for `Name` +_validate_regex = re.compile( + r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE +) _canonicalize_regex = re.compile(r"[-_.]+") +_normalized_regex = re.compile(r"^([a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9])$") # PEP 427: The build number must start with a digit. _build_tag_regex = re.compile(r"(\d+)(.*)") -def canonicalize_name(name: str) -> NormalizedName: +def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName: + if validate and not _validate_regex.match(name): + raise InvalidName(f"name is invalid: {name!r}") # This is taken from PEP 503. value = _canonicalize_regex.sub("-", name).lower() return cast(NormalizedName, value) +def is_normalized_name(name: str) -> bool: + return _normalized_regex.match(name) is not None + + def canonicalize_version( version: Union[Version, str], *, strip_trailing_zero: bool = True ) -> str: @@ -100,11 +117,18 @@ parts = filename.split("-", dashes - 2) name_part = parts[0] - # See PEP 427 for the rules on escaping the project name + # See PEP 427 for the rules on escaping the project name. if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: raise InvalidWheelFilename(f"Invalid project name: {filename}") name = canonicalize_name(name_part) - version = Version(parts[1]) + + try: + version = Version(parts[1]) + except InvalidVersion as e: + raise InvalidWheelFilename( + f"Invalid wheel filename (invalid version): {filename}" + ) from e + if dashes == 5: build_part = parts[2] build_match = _build_tag_regex.match(build_part) @@ -137,5 +161,12 @@ raise InvalidSdistFilename(f"Invalid sdist filename: {filename}") name = canonicalize_name(name_part) - version = Version(version_part) + + try: + version = Version(version_part) + except InvalidVersion as e: + raise InvalidSdistFilename( + f"Invalid sdist filename (invalid version): {filename}" + ) from e + return (name, version) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/packaging/version.py new/wheel-0.42.0/src/wheel/vendored/packaging/version.py --- old/wheel-0.41.2/src/wheel/vendored/packaging/version.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/packaging/version.py 2023-11-26 15:35:45.000000000 +0100 @@ -7,37 +7,39 @@ from packaging.version import parse, Version """ -import collections import itertools import re -from typing import Callable, Optional, SupportsInt, Tuple, Union +from typing import Any, Callable, NamedTuple, Optional, SupportsInt, Tuple, Union from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType __all__ = ["VERSION_PATTERN", "parse", "Version", "InvalidVersion"] -InfiniteTypes = Union[InfinityType, NegativeInfinityType] -PrePostDevType = Union[InfiniteTypes, Tuple[str, int]] -SubLocalType = Union[InfiniteTypes, int, str] -LocalType = Union[ +LocalType = Tuple[Union[int, str], ...] + +CmpPrePostDevType = Union[InfinityType, NegativeInfinityType, Tuple[str, int]] +CmpLocalType = Union[ NegativeInfinityType, - Tuple[ - Union[ - SubLocalType, - Tuple[SubLocalType, str], - Tuple[NegativeInfinityType, SubLocalType], - ], - ..., - ], + Tuple[Union[Tuple[int, str], Tuple[NegativeInfinityType, Union[int, str]]], ...], ] CmpKey = Tuple[ - int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType + int, + Tuple[int, ...], + CmpPrePostDevType, + CmpPrePostDevType, + CmpPrePostDevType, + CmpLocalType, ] VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool] -_Version = collections.namedtuple( - "_Version", ["epoch", "release", "dev", "pre", "post", "local"] -) + +class _Version(NamedTuple): + epoch: int + release: Tuple[int, ...] + dev: Optional[Tuple[str, int]] + pre: Optional[Tuple[str, int]] + post: Optional[Tuple[str, int]] + local: Optional[LocalType] def parse(version: str) -> "Version": @@ -63,7 +65,7 @@ class _BaseVersion: - _key: CmpKey + _key: Tuple[Any, ...] def __hash__(self) -> int: return hash(self._key) @@ -117,7 +119,7 @@ (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment (?P<pre> # pre-release [-_\.]? - (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) + (?P<pre_l>alpha|a|beta|b|preview|pre|c|rc) [-_\.]? (?P<pre_n>[0-9]+)? )? @@ -179,6 +181,7 @@ """ _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE) + _key: CmpKey def __init__(self, version: str) -> None: """Initialize a Version object. @@ -268,8 +271,7 @@ >>> Version("1!2.0.0").epoch 1 """ - _epoch: int = self._version.epoch - return _epoch + return self._version.epoch @property def release(self) -> Tuple[int, ...]: @@ -285,8 +287,7 @@ Includes trailing zeroes but not the epoch or any pre-release / development / post-release suffixes. """ - _release: Tuple[int, ...] = self._version.release - return _release + return self._version.release @property def pre(self) -> Optional[Tuple[str, int]]: @@ -301,8 +302,7 @@ >>> Version("1.2.3rc1").pre ('rc', 1) """ - _pre: Optional[Tuple[str, int]] = self._version.pre - return _pre + return self._version.pre @property def post(self) -> Optional[int]: @@ -450,7 +450,7 @@ def _parse_letter_version( - letter: str, number: Union[str, bytes, SupportsInt] + letter: Optional[str], number: Union[str, bytes, SupportsInt, None] ) -> Optional[Tuple[str, int]]: if letter: @@ -488,7 +488,7 @@ _local_version_separators = re.compile(r"[\._-]") -def _parse_local_version(local: str) -> Optional[LocalType]: +def _parse_local_version(local: Optional[str]) -> Optional[LocalType]: """ Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). """ @@ -506,7 +506,7 @@ pre: Optional[Tuple[str, int]], post: Optional[Tuple[str, int]], dev: Optional[Tuple[str, int]], - local: Optional[Tuple[SubLocalType]], + local: Optional[LocalType], ) -> CmpKey: # When we compare a release version, we want to compare it with all of the @@ -523,7 +523,7 @@ # if there is not a pre or a post segment. If we have one of those then # the normal sorting rules will handle this case correctly. if pre is None and post is None and dev is not None: - _pre: PrePostDevType = NegativeInfinity + _pre: CmpPrePostDevType = NegativeInfinity # Versions without a pre-release (except as noted above) should sort after # those with one. elif pre is None: @@ -533,21 +533,21 @@ # Versions without a post segment should sort before those with one. if post is None: - _post: PrePostDevType = NegativeInfinity + _post: CmpPrePostDevType = NegativeInfinity else: _post = post # Versions without a development segment should sort after those with one. if dev is None: - _dev: PrePostDevType = Infinity + _dev: CmpPrePostDevType = Infinity else: _dev = dev if local is None: # Versions without a local segment should sort before those with one. - _local: LocalType = NegativeInfinity + _local: CmpLocalType = NegativeInfinity else: # Versions with a local segment need that segment parsed to implement # the sorting rules in PEP440. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/src/wheel/vendored/vendor.txt new/wheel-0.42.0/src/wheel/vendored/vendor.txt --- old/wheel-0.41.2/src/wheel/vendored/vendor.txt 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/src/wheel/vendored/vendor.txt 2023-11-26 15:35:45.000000000 +0100 @@ -1 +1 @@ -packaging==23.0 +packaging==23.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/tests/cli/test_pack.py new/wheel-0.42.0/tests/cli/test_pack.py --- old/wheel-0.41.2/tests/cli/test_pack.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/tests/cli/test_pack.py 2023-11-26 15:35:45.000000000 +0100 @@ -1,7 +1,9 @@ from __future__ import annotations +import email.policy import os -from textwrap import dedent +from email.message import Message +from email.parser import BytesParser from zipfile import ZipFile import pytest @@ -55,24 +57,25 @@ if line and not line.startswith(b"test-1.0.dist-info/WHEEL,") ) - new_wheel_file_content = zf.read("test-1.0.dist-info/WHEEL") + parser = BytesParser(policy=email.policy.compat32) + new_wheel_file_content = parser.parsebytes(zf.read("test-1.0.dist-info/WHEEL")) assert new_record_lines == old_record_lines - expected_build_num = build_tag_arg or existing_build_tag - expected_wheel_content = dedent( - """\ - Wheel-Version: 1.0 - Generator: bdist_wheel (0.30.0) - Root-Is-Purelib: false - Tag: py2-none-any - Tag: py3-none-any - """.replace( - "\n", "\r\n" - ) + # Line endings and trailing blank line will depend on whether WHEEL + # was modified. Circumvent this by comparing parsed key/value pairs. + expected_wheel_content = Message() + expected_wheel_content["Wheel-Version"] = "1.0" + expected_wheel_content["Generator"] = "bdist_wheel (0.30.0)" + expected_wheel_content["Root-Is-Purelib"] = "false" + expected_wheel_content["Tag"] = "py2-none-any" + expected_wheel_content["Tag"] = "py3-none-any" + expected_build_num = ( + build_tag_arg if build_tag_arg is not None else existing_build_tag ) if expected_build_num: - expected_wheel_content += "Build: %s\r\n" % expected_build_num + expected_wheel_content["Build"] = expected_build_num - expected_wheel_content = expected_wheel_content.encode("ascii") - assert new_wheel_file_content == expected_wheel_content + assert sorted(new_wheel_file_content.items()) == sorted( + expected_wheel_content.items() + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/tests/cli/test_tags.py new/wheel-0.42.0/tests/cli/test_tags.py --- old/wheel-0.41.2/tests/cli/test_tags.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/tests/cli/test_tags.py 2023-11-26 15:35:45.000000000 +0100 @@ -39,8 +39,8 @@ with WheelFile(str(output_file)) as f: output = f.read(f.dist_info_path + "/WHEEL") assert ( - output == b"Wheel-Version: 1.0\r\nGenerator: bdist_wheel (0.30.0)" - b"\r\nRoot-Is-Purelib: false\r\nTag: py3-none-any\r\n" + output == b"Wheel-Version: 1.0\nGenerator: bdist_wheel (0.30.0)" + b"\nRoot-Is-Purelib: false\nTag: py3-none-any\n\n" ) output_file.unlink() @@ -116,6 +116,8 @@ assert TESTWHEEL_NAME.replace("-py2", "-1bah-py2") == newname output_file = wheelpath.parent / newname assert output_file.exists() + newname = tags(str(wheelpath), build_tag="") + assert TESTWHEEL_NAME == newname output_file.unlink() @@ -151,9 +153,9 @@ output = f.read(f.dist_info_path + "/WHEEL") assert ( output - == b"Wheel-Version: 1.0\r\nGenerator: bdist_wheel (0.30.0)\r\nRoot-Is-Purelib:" - b" false\r\nTag: py2-none-linux_x86_64\r\nTag: py3-none-linux_x86_64\r\nTag:" - b" py4-none-linux_x86_64\r\nBuild: 1\r\n" + == b"Wheel-Version: 1.0\nGenerator: bdist_wheel (0.30.0)\nRoot-Is-Purelib:" + b" false\nTag: py2-none-linux_x86_64\nTag: py3-none-linux_x86_64\nTag:" + b" py4-none-linux_x86_64\nBuild: 1\n\n" ) output_file.unlink() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wheel-0.41.2/tests/test_bdist_wheel.py new/wheel-0.42.0/tests/test_bdist_wheel.py --- old/wheel-0.41.2/tests/test_bdist_wheel.py 2023-08-22 11:29:26.000000000 +0200 +++ new/wheel-0.42.0/tests/test_bdist_wheel.py 2023-11-26 15:35:45.000000000 +0100 @@ -287,6 +287,12 @@ ) +def test_get_abi_tag_windows(monkeypatch): + monkeypatch.setattr(tags, "interpreter_name", lambda: "cp") + monkeypatch.setattr(sysconfig, "get_config_var", lambda x: "cp313-win_amd64") + assert get_abi_tag() == "cp313" + + def test_get_abi_tag_pypy_old(monkeypatch): monkeypatch.setattr(tags, "interpreter_name", lambda: "pp") monkeypatch.setattr(sysconfig, "get_config_var", lambda x: "pypy36-pp73")