From b4ca613545d1222608a50381491d3a53595e8240 Mon Sep 17 00:00:00 2001 From: Julien Stephan Date: Mon, 19 Oct 2026 15:03:18 +0200 Subject: [PATCH] check_versions.py: deprecate as soon as upstream ships any riscv64 wheel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we only deprecated once upstream published riscv64 wheels for every target Python (3.12, 3.13, 3.14, 3.14t). If even one was missing we kept building the package ourselves for all target versions, including the ones upstream already covers. xmhuffman is an example: upstream ships riscv64 wheels for 3.12, 3.13 and 3.14, but not 3.14t. We don't want to keep building those covered versions ourselves, but we also shouldn't start building 3.14t (or any other upstream-unsupported version) on upstream's behalf just to fill the gap — a free-threaded build succeeding doesn't mean the resulting wheel is actually free-threading-safe, and the same applies to any other Python version upstream chose not to support. That's a correctness guarantee only upstream can make, so we defer to whatever matrix upstream decides to publish instead of completing it for them. has_riscv64_wheel (require every target version) becomes has_any_riscv64_wheel (require at least one), used both to stop declaring new versions for us to build once upstream has any riscv64 coverage, and to trigger deprecation on partial upstream coverage. Signed-off-by: Julien Stephan --- ci_scripts/check_versions.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ci_scripts/check_versions.py b/ci_scripts/check_versions.py index 1893b739b8c3..b24123b8c7fb 100755 --- a/ci_scripts/check_versions.py +++ b/ci_scripts/check_versions.py @@ -153,11 +153,11 @@ def matching_riscv64_wheels( } -def has_riscv64_wheel( +def has_any_riscv64_wheel( package_info: Dict, target_version: str, python_versions: List[str] = TARGET_PYTHON_VERSIONS ) -> bool: - """Check whether a version has upstream riscv64 wheels covering every python_versions entry.""" - return all(matching_riscv64_wheels(package_info, target_version, python_versions).values()) + """Check whether a version has an upstream riscv64 wheel for any python_versions entry.""" + return any(matching_riscv64_wheels(package_info, target_version, python_versions).values()) def is_pure_python_wheel(package_info: Dict, target_version: str) -> bool: @@ -450,13 +450,13 @@ def check_upgrade( candidates = [v for v in get_new_versions(pypi_info, registry_version) or [pypi_version] if v not in declared] # We provide wheels up to the point where upstream does: a version that - # already has riscv64 wheels for every target Python, or that went pure + # already has a riscv64 wheel for any target Python, or that went pure # Python, is never built here, but every gap before it is. - upstream = [v for v in candidates if has_riscv64_wheel(pypi_info, v) or is_pure_python_wheel(pypi_info, v)] + upstream = [v for v in candidates if has_any_riscv64_wheel(pypi_info, v) or is_pure_python_wheel(pypi_info, v)] new_versions = [v for v in candidates if v not in upstream] if upstream: print(f" [=] {package}: skipping {', '.join(f'v{v}' for v in upstream)}, " - f"riscv64 or pure Python wheels on PyPI for Python {', '.join(TARGET_PYTHON_VERSIONS)}") + "already riscv64 (full or partial) or pure Python upstream") if new_versions: print(f"[^] {package} can be upgraded: v{registry_version} -> {', '.join(f'v{v}' for v in new_versions)}") @@ -478,15 +478,14 @@ def check_upgrade( print(f"[+] {package}: {', '.join(f'v{v}' for v in pending)} already declared, waiting for the build") return up_to_date - if behind and has_riscv64_wheel(pypi_info, pypi_version): - py_list = ", ".join(TARGET_PYTHON_VERSIONS) + if behind and has_any_riscv64_wheel(pypi_info, pypi_version): wheels_by_version = matching_riscv64_wheels(pypi_info, pypi_version) - print(f"[-] {package} v{pypi_version} has riscv64 wheels on PyPI for Python {py_list}. Can be deprecated.") + print(f"[-] {package} v{pypi_version} has riscv64 wheels on PyPI. Can be deprecated.") wheel_lines = [f"- {pv}: {fn}" for pv, files in wheels_by_version.items() for fn in files] for line in wheel_lines: print(f" {line}") reason = ( - f"{package} v{pypi_version} has riscv64 wheels on PyPI for Python {py_list}: " + f"{package} v{pypi_version} has riscv64 wheels on PyPI: " f"{pypi_package_url}\n\n" + "\n".join(wheel_lines) ) return deprecation_result(package, registry_version, pypi_version, reason, declare) @@ -681,7 +680,7 @@ def write_reports(results: List[Dict[str, any]], directory: Path) -> List[Dict[s def _self_test(): - """Sanity-check has_riscv64_wheel's per-interpreter matching. Run with --self-test.""" + """Sanity-check has_any_riscv64_wheel's per-interpreter matching. Run with --self-test.""" releases = { "1.0": [ {"filename": "pkg-1.0-cp312-cp312-manylinux_2_34_riscv64.whl"}, @@ -691,19 +690,20 @@ def _self_test(): ] } info = {"releases": releases} - # Missing 3.14t -> not all target versions covered. - assert has_riscv64_wheel(info, "1.0") is False - assert has_riscv64_wheel(info, "1.0", ["3.12", "3.13"]) is True + # Missing 3.14t, but 3.12/3.13/3.14 are covered -> deprecatable even though + # the matrix isn't complete. + assert has_any_riscv64_wheel(info, "1.0") is True + assert has_any_riscv64_wheel(info, "1.0", ["3.14t"]) is False releases["1.0"].append({"filename": "pkg-1.0-cp314-cp314t-manylinux_2_34_riscv64.whl"}) - assert has_riscv64_wheel(info, "1.0") is True + assert has_any_riscv64_wheel(info, "1.0") is True # abi3 wheel covers any cp3X >= its floor, but never a free-threaded target. abi3_info = {"releases": {"1.0": [ {"filename": "pkg-1.0-cp39-abi3-manylinux_2_34_riscv64.whl"}, ]}} - assert has_riscv64_wheel(abi3_info, "1.0", ["3.12", "3.13", "3.14"]) is True - assert has_riscv64_wheel(abi3_info, "1.0", ["3.14t"]) is False + assert has_any_riscv64_wheel(abi3_info, "1.0", ["3.12", "3.13", "3.14"]) is True + assert has_any_riscv64_wheel(abi3_info, "1.0", ["3.14t"]) is False # Per-package PR titles, one PR per package. upgrade = {"status": "need_upgrade", "package": "PyYAML", "registry_version": "6.0",