|
16 | 16 | from packaging.utils import parse_wheel_filename |
17 | 17 | from packaging.version import Version |
18 | 18 |
|
| 19 | +from build import Package |
| 20 | + |
19 | 21 | PYTHONS = ((3, 11), (3, 12), (3, 13)) |
20 | 22 | DIST_INFO_RE = re.compile(r"^[^/]+.dist-info/[^/]+$") |
21 | 23 |
|
@@ -44,28 +46,42 @@ def _py_exe(major: int, minor: int) -> str: |
44 | 46 | return f"python{major}.{minor}" |
45 | 47 |
|
46 | 48 |
|
47 | | -def _pythons_to_check(tags: frozenset[Tag]) -> tuple[str, ...]: |
48 | | - ret: set[str] = set() |
| 49 | +def _pythons_to_check(tags: frozenset[Tag], package: Package) -> tuple[str, ...]: |
| 50 | + tag_compatible_pythons: set[str] = set() |
49 | 51 | for tag in tags: |
50 | 52 | if tag.abi == "abi3" and tag.interpreter.startswith("cp"): |
51 | 53 | min_py = _parse_cp_tag(tag.interpreter) |
52 | | - ret.update(_py_exe(*py) for py in PYTHONS if py >= min_py) |
| 54 | + tag_compatible_pythons.update( |
| 55 | + _py_exe(*py) for py in PYTHONS if py >= min_py |
| 56 | + ) |
53 | 57 | elif tag.interpreter.startswith("cp"): |
54 | | - ret.add(_py_exe(*_parse_cp_tag(tag.interpreter))) |
| 58 | + tag_compatible_pythons.add(_py_exe(*_parse_cp_tag(tag.interpreter))) |
55 | 59 | elif tag.interpreter == "py2": |
56 | 60 | continue |
57 | 61 | elif tag.interpreter.startswith("py3"): |
58 | 62 | for py in PYTHONS: |
59 | 63 | if tag not in packaging.tags.compatible_tags(py): |
60 | 64 | raise AssertionError(f"{tag} is not compatible with python {py}") |
61 | | - ret.update(_py_exe(*py) for py in PYTHONS) |
| 65 | + tag_compatible_pythons.update(_py_exe(*py) for py in PYTHONS) |
62 | 66 | else: |
63 | 67 | raise AssertionError(f"unexpected tag: {tag}") |
64 | 68 |
|
65 | | - if not ret: |
| 69 | + if not tag_compatible_pythons: |
66 | 70 | raise AssertionError(f"no interpreters found for {tags}") |
67 | | - else: |
68 | | - return tuple(sorted(ret)) |
| 71 | + |
| 72 | + package_compatible_pythons: set[str] = set() |
| 73 | + for python_exe in tag_compatible_pythons: |
| 74 | + py_version_str = python_exe.replace("python", "") |
| 75 | + if py_version_str in package.python_versions: |
| 76 | + package_compatible_pythons.add(python_exe) |
| 77 | + |
| 78 | + if not package_compatible_pythons: |
| 79 | + raise AssertionError( |
| 80 | + f"no interpreters found for {tags} after applying package constraints {package.python_versions}. " |
| 81 | + f"Wheel supports: {sorted(tag_compatible_pythons)}" |
| 82 | + ) |
| 83 | + |
| 84 | + return tuple(sorted(package_compatible_pythons)) |
69 | 85 |
|
70 | 86 |
|
71 | 87 | def _top_imports(whl: str) -> list[str]: |
@@ -157,14 +173,18 @@ def main() -> int: |
157 | 173 | raise SystemExit(f"{args.packages_ini}: not found") |
158 | 174 |
|
159 | 175 | packages = {} |
| 176 | + validate_infos = {} |
160 | 177 | for k in cfg.sections(): |
161 | 178 | pkg, _, version_s = k.partition("==") |
162 | | - packages[(pkg, Version(version_s))] = Info.from_dct(cfg[k]) |
| 179 | + key = (pkg, Version(version_s)) |
| 180 | + packages[key] = Package.make(k, cfg[k]) |
| 181 | + validate_infos[key] = Info.from_dct(cfg[k]) |
163 | 182 |
|
164 | 183 | for filename in sorted(os.listdir(args.dist)): |
165 | 184 | name, version, _, wheel_tags = parse_wheel_filename(filename) |
166 | | - info = packages[(name, version)] |
167 | | - for python in _pythons_to_check(wheel_tags): |
| 185 | + package = packages[(name, version)] |
| 186 | + info = validate_infos[(name, version)] |
| 187 | + for python in _pythons_to_check(wheel_tags, package): |
168 | 188 | _validate( |
169 | 189 | python=python, |
170 | 190 | filename=os.path.join(args.dist, filename), |
|
0 commit comments