Skip to content

Commit 6a48f85

Browse files
committed
correctly select by py_tag
1 parent d36610f commit 6a48f85

File tree

2 files changed

+125
-30
lines changed

2 files changed

+125
-30
lines changed

python/private/pypi/select_whl.bzl

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,55 @@ load("//python/private:version.bzl", "version")
44
load(":parse_whl_name.bzl", "parse_whl_name")
55
load(":python_tag.bzl", "PY_TAG_GENERIC", "python_tag")
66

7-
def _get_priority(*, tag, values, allow_wildcard = True):
7+
def _get_priority(*, tags, values, allow_wildcard = True):
8+
keys = []
89
for priority, wp in enumerate(values):
9-
head, sep, tail = wp.partition("*")
10-
if "*" in tail:
11-
fail("only a single '*' can be present in the matcher")
12-
if not allow_wildcard and sep:
13-
fail("'*' is not allowed in the matcher")
10+
for tag in tags.split("."):
11+
head, sep, tail = wp.partition("*")
12+
if "*" in tail:
13+
fail("only a single '*' can be present in the matcher")
14+
if not allow_wildcard and sep:
15+
fail("'*' is not allowed in the matcher")
16+
17+
if not sep and tag == head:
18+
keys.append(priority)
19+
elif sep and tag.startswith(head) and tag.endswith(tail):
20+
keys.append(priority)
21+
22+
if not keys:
23+
return None
24+
25+
return max(keys)
26+
27+
def _get_py_priority(*, tags, implementation, py_version):
28+
keys = []
29+
for tag in tags.split("."):
30+
if tag.startswith(PY_TAG_GENERIC):
31+
ver_str = tag[len(PY_TAG_GENERIC):]
32+
elif tag.startswith(implementation):
33+
ver_str = tag[len(implementation):]
34+
else:
35+
continue
36+
37+
# Add a 0 at the end in case it is a single digit
38+
ver_str = "{}.{}".format(ver_str[0], ver_str[1:] or "0")
39+
40+
ver = version.parse(ver_str)
41+
if not version.is_compatible(py_version, ver):
42+
continue
43+
44+
keys.append((
45+
tag.startswith(implementation),
46+
version.key(ver),
47+
# Prefer shorter py_tags, which will yield more specialized matches,
48+
# like preferring py3 over py2.py3
49+
-len(tags),
50+
))
1451

15-
for p in tag.split("."):
16-
if not sep and p == head:
17-
return priority
18-
elif sep and p.startswith(head) and p.endswith(tail):
19-
return priority
52+
if not keys:
53+
return None
2054

21-
return None
55+
return max(keys)
2256

2357
def select_whl(*, whls, python_version, platforms, whl_abi_tags, implementation_name = "cpython", limit = 1, logger = None):
2458
"""Select a whl that is the most suitable for the given platform.
@@ -56,26 +90,22 @@ def select_whl(*, whls, python_version, platforms, whl_abi_tags, implementation_
5690
))
5791
continue
5892

59-
if parsed.python_tag == "py2.py3":
60-
min_version = "2"
61-
else:
62-
min_version = parsed.python_tag[len(implementation):]
63-
64-
if len(min_version) > 1:
65-
min_version = "{}.{}".format(min_version[0], min_version[1:])
66-
67-
min_whl_py_version = version.parse(min_version, strict = True)
68-
if not version.is_ge(py_version, min_whl_py_version):
93+
py_priority = _get_py_priority(
94+
tags = parsed.python_tag,
95+
implementation = implementation,
96+
py_version = py_version,
97+
)
98+
if py_priority == None:
6999
if logger:
70-
logger.debug(lambda: "Discarding the wheel because the min version supported based on the wheel ABI tag '{}' ({}) is not compatible with the provided target Python version '{}'".format(
71-
parsed.abi_tag,
72-
min_whl_py_version.string,
100+
logger.debug(lambda: "The py_tag '{}' does not match implementation version: {} {}".format(
101+
parsed.py_tag,
102+
implementation,
73103
py_version.string,
74104
))
75105
continue
76106

77107
abi_priority = _get_priority(
78-
tag = parsed.abi_tag,
108+
tags = parsed.abi_tag,
79109
values = whl_abi_tags,
80110
allow_wildcard = False,
81111
)
@@ -86,8 +116,9 @@ def select_whl(*, whls, python_version, platforms, whl_abi_tags, implementation_
86116
whl_abi_tags,
87117
))
88118
continue
119+
89120
platform_priority = _get_priority(
90-
tag = parsed.platform_tag,
121+
tags = parsed.platform_tag,
91122
values = platforms,
92123
)
93124
if platform_priority == None:
@@ -100,10 +131,8 @@ def select_whl(*, whls, python_version, platforms, whl_abi_tags, implementation_
100131

101132
key = (
102133
# Ensure that we chose the highest compatible version
103-
parsed.python_tag.startswith(implementation),
134+
py_priority,
104135
platform_priority,
105-
# prefer abi_tags in this order
106-
version.key(min_whl_py_version),
107136
abi_priority,
108137
)
109138
candidates.setdefault(key, whl)

tests/pypi/select_whl/select_whl_tests.bzl

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,55 @@ def _select_whl(whls, debug = False, **kwargs):
9696

9797
_tests = []
9898

99+
def _test_not_select_py2(env):
100+
# Check we prefer platform specific wheels
101+
got = _select_whl(
102+
whls = [
103+
"pkg-0.0.1-py2-none-any.whl",
104+
"pkg-0.0.1-py3-none-any.whl",
105+
"pkg-0.0.1-py312-none-any.whl",
106+
],
107+
platforms = ["any"],
108+
whl_abi_tags = ["none"],
109+
python_version = "3.13",
110+
limit = 2,
111+
)
112+
_match(
113+
env,
114+
got,
115+
"pkg-0.0.1-py3-none-any.whl",
116+
"pkg-0.0.1-py312-none-any.whl",
117+
)
118+
119+
_tests.append(_test_not_select_py2)
120+
121+
def _test_select_cp312(env):
122+
# Check we prefer platform specific wheels
123+
got = _select_whl(
124+
whls = [
125+
"pkg-0.0.1-py2-none-any.whl",
126+
"pkg-0.0.1-py3-none-any.whl",
127+
"pkg-0.0.1-py312-none-any.whl",
128+
"pkg-0.0.1-cp39-none-any.whl",
129+
"pkg-0.0.1-cp312-none-any.whl",
130+
"pkg-0.0.1-cp314-none-any.whl",
131+
],
132+
platforms = ["any"],
133+
whl_abi_tags = ["none"],
134+
python_version = "3.13",
135+
limit = 5,
136+
)
137+
_match(
138+
env,
139+
got,
140+
"pkg-0.0.1-py3-none-any.whl",
141+
"pkg-0.0.1-py312-none-any.whl",
142+
"pkg-0.0.1-cp39-none-any.whl",
143+
"pkg-0.0.1-cp312-none-any.whl",
144+
)
145+
146+
_tests.append(_test_select_cp312)
147+
99148
def _test_simplest(env):
100149
whls = [
101150
"pkg-0.0.1-py2.py3-abi3-any.whl",
@@ -281,6 +330,23 @@ def _test_freethreaded_wheels(env):
281330

282331
_tests.append(_test_freethreaded_wheels)
283332

333+
def _test_pytags_all_possible(env):
334+
got = _select_whl(
335+
whls = [
336+
"pkg-0.0.1-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313-none-win_amd64.whl",
337+
],
338+
platforms = ["win_amd64"],
339+
whl_abi_tags = ["none"],
340+
python_version = "3.12",
341+
)
342+
_match(
343+
env,
344+
[got],
345+
"pkg-0.0.1-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313-none-win_amd64.whl",
346+
)
347+
348+
_tests.append(_test_pytags_all_possible)
349+
284350
def select_whl_test_suite(name):
285351
"""Create the test suite.
286352

0 commit comments

Comments
 (0)