From 9f61a0966e3a6eb8d5e72f1ad9cdd68eef469202 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:25:31 +0100 Subject: [PATCH 1/5] feat: Account for python_versions in validate.py --- validate.py | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/validate.py b/validate.py index be49e508..893a7390 100644 --- a/validate.py +++ b/validate.py @@ -16,6 +16,8 @@ from packaging.utils import parse_wheel_filename from packaging.version import Version +from build import Package + PYTHONS = ((3, 11), (3, 12), (3, 13)) DIST_INFO_RE = re.compile(r"^[^/]+.dist-info/[^/]+$") @@ -44,28 +46,42 @@ def _py_exe(major: int, minor: int) -> str: return f"python{major}.{minor}" -def _pythons_to_check(tags: frozenset[Tag]) -> tuple[str, ...]: - ret: set[str] = set() +def _pythons_to_check(tags: frozenset[Tag], package: Package) -> tuple[str, ...]: + tag_compatible_pythons: set[str] = set() for tag in tags: if tag.abi == "abi3" and tag.interpreter.startswith("cp"): min_py = _parse_cp_tag(tag.interpreter) - ret.update(_py_exe(*py) for py in PYTHONS if py >= min_py) + tag_compatible_pythons.update( + _py_exe(*py) for py in PYTHONS if py >= min_py + ) elif tag.interpreter.startswith("cp"): - ret.add(_py_exe(*_parse_cp_tag(tag.interpreter))) + tag_compatible_pythons.add(_py_exe(*_parse_cp_tag(tag.interpreter))) elif tag.interpreter == "py2": continue elif tag.interpreter.startswith("py3"): for py in PYTHONS: if tag not in packaging.tags.compatible_tags(py): raise AssertionError(f"{tag} is not compatible with python {py}") - ret.update(_py_exe(*py) for py in PYTHONS) + tag_compatible_pythons.update(_py_exe(*py) for py in PYTHONS) else: raise AssertionError(f"unexpected tag: {tag}") - if not ret: + if not tag_compatible_pythons: raise AssertionError(f"no interpreters found for {tags}") - else: - return tuple(sorted(ret)) + + package_compatible_pythons: set[str] = set() + for python_exe in tag_compatible_pythons: + py_version_str = python_exe.replace("python", "") + if py_version_str in package.python_versions: + package_compatible_pythons.add(python_exe) + + if not package_compatible_pythons: + raise AssertionError( + f"no interpreters found for {tags} after applying package constraints {package.python_versions}. " + f"Wheel supports: {sorted(tag_compatible_pythons)}" + ) + + return tuple(sorted(package_compatible_pythons)) def _top_imports(whl: str) -> list[str]: @@ -157,14 +173,18 @@ def main() -> int: raise SystemExit(f"{args.packages_ini}: not found") packages = {} + validate_infos = {} for k in cfg.sections(): pkg, _, version_s = k.partition("==") - packages[(pkg, Version(version_s))] = Info.from_dct(cfg[k]) + key = (pkg, Version(version_s)) + packages[key] = Package.make(k, cfg[k]) + validate_infos[key] = Info.from_dct(cfg[k]) for filename in sorted(os.listdir(args.dist)): name, version, _, wheel_tags = parse_wheel_filename(filename) - info = packages[(name, version)] - for python in _pythons_to_check(wheel_tags): + package = packages[(name, version)] + info = validate_infos[(name, version)] + for python in _pythons_to_check(wheel_tags, package): _validate( python=python, filename=os.path.join(args.dist, filename), From 2255d3289fcb3bf9011a69339617d1e35a107a78 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:28:58 +0100 Subject: [PATCH 2/5] fix param --- validate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate.py b/validate.py index 893a7390..1513d593 100644 --- a/validate.py +++ b/validate.py @@ -46,7 +46,9 @@ def _py_exe(major: int, minor: int) -> str: return f"python{major}.{minor}" -def _pythons_to_check(tags: frozenset[Tag], package: Package) -> tuple[str, ...]: +def _pythons_to_check( + tags: frozenset[Tag], package: Package | None = None +) -> tuple[str, ...]: tag_compatible_pythons: set[str] = set() for tag in tags: if tag.abi == "abi3" and tag.interpreter.startswith("cp"): @@ -69,6 +71,9 @@ def _pythons_to_check(tags: frozenset[Tag], package: Package) -> tuple[str, ...] if not tag_compatible_pythons: raise AssertionError(f"no interpreters found for {tags}") + if not package: + return tuple(sorted(tag_compatible_pythons)) + package_compatible_pythons: set[str] = set() for python_exe in tag_compatible_pythons: py_version_str = python_exe.replace("python", "") From c80923946c804b349c38e84c3e5fbdc17f0ae7c0 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:42:44 +0100 Subject: [PATCH 3/5] pass SpecifierSet instead --- validate.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/validate.py b/validate.py index 1513d593..5310ea58 100644 --- a/validate.py +++ b/validate.py @@ -12,6 +12,7 @@ from typing import NamedTuple import packaging.tags +from packaging.specifiers import SpecifierSet from packaging.tags import Tag from packaging.utils import parse_wheel_filename from packaging.version import Version @@ -47,7 +48,7 @@ def _py_exe(major: int, minor: int) -> str: def _pythons_to_check( - tags: frozenset[Tag], package: Package | None = None + tags: frozenset[Tag], python_versions: SpecifierSet | None = None ) -> tuple[str, ...]: tag_compatible_pythons: set[str] = set() for tag in tags: @@ -71,18 +72,18 @@ def _pythons_to_check( if not tag_compatible_pythons: raise AssertionError(f"no interpreters found for {tags}") - if not package: + if not python_versions: return tuple(sorted(tag_compatible_pythons)) package_compatible_pythons: set[str] = set() for python_exe in tag_compatible_pythons: py_version_str = python_exe.replace("python", "") - if py_version_str in package.python_versions: + if py_version_str in python_versions: package_compatible_pythons.add(python_exe) if not package_compatible_pythons: raise AssertionError( - f"no interpreters found for {tags} after applying package constraints {package.python_versions}. " + f"no interpreters found for {tags} after applying package constraints {python_versions}. " f"Wheel supports: {sorted(tag_compatible_pythons)}" ) @@ -189,7 +190,7 @@ def main() -> int: name, version, _, wheel_tags = parse_wheel_filename(filename) package = packages[(name, version)] info = validate_infos[(name, version)] - for python in _pythons_to_check(wheel_tags, package): + for python in _pythons_to_check(wheel_tags, package.python_versions): _validate( python=python, filename=os.path.join(args.dist, filename), From 9abe583a821f0d559ff3d372623617c6fa51caa2 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:50:13 +0100 Subject: [PATCH 4/5] add a test --- tests/validate_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/validate_test.py b/tests/validate_test.py index 36337aff..abd4b189 100644 --- a/tests/validate_test.py +++ b/tests/validate_test.py @@ -3,6 +3,7 @@ import zipfile import pytest +from packaging.specifiers import SpecifierSet from packaging.tags import parse_tag import validate @@ -87,3 +88,10 @@ def test_top_imports_record(tmp_path): expected = ["distlib", "_distlib_backend", "distlib_top"] assert validate._top_imports(str(whl)) == expected + + +def test_pythons_to_check_with_python_versions_constraint(): + tag = parse_tag("py2.py3-none-any") + constraint = SpecifierSet(">=3.12") + ret = validate._pythons_to_check(tag, constraint) + assert ret == ("python3.12", "python3.13") From 4d575948f1664366f7e41591dafab1f095965250 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 11 Nov 2025 14:04:07 -0800 Subject: [PATCH 5/5] fix merge --- validate.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate.py b/validate.py index 14dbf1ec..0cf02f3b 100644 --- a/validate.py +++ b/validate.py @@ -63,8 +63,9 @@ def _pythons_to_check( continue elif tag.interpreter.startswith("py3"): for py in PYTHONS: - if tag in packaging.tags.compatible_tags(py): - tag_compatible_pythons.add(_py_exe(*py)) + if tag not in packaging.tags.compatible_tags(py): + raise AssertionError(f"{tag} is not compatible with python {py}") + tag_compatible_pythons.add(_py_exe(*py)) else: raise AssertionError(f"unexpected tag: {tag}")