Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/validate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import zipfile

import pytest
from packaging.specifiers import SpecifierSet
from packaging.tags import parse_tag

import validate
Expand Down Expand Up @@ -97,3 +98,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")
51 changes: 39 additions & 12 deletions validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
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

from build import Package

PYTHONS = ((3, 11), (3, 12), (3, 13))
DIST_INFO_RE = re.compile(r"^[^/]+.dist-info/[^/]+$")

Expand Down Expand Up @@ -44,27 +47,47 @@ 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], python_versions: SpecifierSet | None = None
) -> 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 in packaging.tags.compatible_tags(py):
ret.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}")

if not ret:
if not tag_compatible_pythons:
raise AssertionError(f"no interpreters found for {tags}")
else:
return tuple(sorted(ret))

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 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 {python_versions}. "
f"Wheel supports: {sorted(tag_compatible_pythons)}"
)

return tuple(sorted(package_compatible_pythons))


def _top_imports(whl: str) -> list[str]:
Expand Down Expand Up @@ -156,14 +179,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.python_versions):
_validate(
python=python,
filename=os.path.join(args.dist, filename),
Expand Down
Loading