Skip to content

Commit bd22419

Browse files
aignasrickeylev
andauthored
fix(bzlmod): use X.Y select for the hub repo (#1696)
This allows better interoperability between toolchains and the wheels built by the `whl_library`, as wheels are usually compatible across all of the python patch versions. --------- Co-authored-by: Richard Levasseur <[email protected]>
1 parent 786ee48 commit bd22419

File tree

6 files changed

+72
-39
lines changed

6 files changed

+72
-39
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ A brief description of the categories of changes:
2929
* **BREAKING** (wheel) The `incompatible_normalize_name` and
3030
`incompatible_normalize_version` flags have been removed. They had been
3131
flipped to `True` in 0.27.0 release.
32+
* (bzlmod) The pip hub repository now uses the newly introduced config settings
33+
using the `X.Y` python version notation. This improves cross module
34+
interoperability and allows to share wheels built by interpreters using
35+
different patch versions.
3236

3337
### Fixed
3438

examples/multi_python_versions/tests/my_lib_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@
2323
if not my_lib.websockets_is_for_python_version(
2424
workspace_version
2525
) and not my_lib.websockets_is_for_python_version(bzlmod_version):
26-
print("expected package for Python version is different than returned")
26+
print("expected package for Python version is different than returned\n"
27+
f"expected either {workspace_version} or {bzlmod_version}\n"
28+
f"but got {my_lib.websockets.__file__}")
2729
sys.exit(1)

python/config_settings/config_settings.bzl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def construct_config_settings(name, python_versions):
2929

3030
# Maps e.g. "3.8" -> ["3.8.1", "3.8.2", etc]
3131
minor_to_micro_versions = {}
32+
3233
allowed_flag_values = []
3334
for micro_version in python_versions:
3435
minor, _, _ = micro_version.rpartition(".")
@@ -37,9 +38,12 @@ def construct_config_settings(name, python_versions):
3738

3839
string_flag(
3940
name = "python_version",
40-
# TODO: The default here should somehow match the MODULE config
41-
build_setting_default = python_versions[0],
42-
values = sorted(allowed_flag_values),
41+
# TODO: The default here should somehow match the MODULE config. Until
42+
# then, use the empty string to indicate an unknown version. This
43+
# also prevents version-unaware targets from inadvertently matching
44+
# a select condition when they shouldn't.
45+
build_setting_default = "",
46+
values = [""] + sorted(allowed_flag_values),
4347
visibility = ["//visibility:public"],
4448
)
4549

@@ -53,7 +57,6 @@ def construct_config_settings(name, python_versions):
5357
name = equals_minor_version_name,
5458
flag_values = {":python_version": minor_version},
5559
)
56-
5760
matches_minor_version_names = [equals_minor_version_name]
5861

5962
for micro_version in micro_versions:

python/private/bzlmod/pip.bzl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,29 @@ load(
2525
"whl_library",
2626
)
2727
load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
28-
load("//python/private:full_version.bzl", "full_version")
2928
load("//python/private:normalize_name.bzl", "normalize_name")
3029
load("//python/private:parse_whl_name.bzl", "parse_whl_name")
3130
load("//python/private:version_label.bzl", "version_label")
3231
load(":pip_repository.bzl", "pip_repository")
3332

33+
def _parse_version(version):
34+
major, _, version = version.partition(".")
35+
minor, _, version = version.partition(".")
36+
patch, _, version = version.partition(".")
37+
build, _, version = version.partition(".")
38+
39+
return struct(
40+
# use semver vocabulary here
41+
major = major,
42+
minor = minor,
43+
patch = patch, # this is called `micro` in the Python interpreter versioning scheme
44+
build = build,
45+
)
46+
47+
def _major_minor_version(version):
48+
version = _parse_version(version)
49+
return "{}.{}".format(version.major, version.minor)
50+
3451
def _whl_mods_impl(mctx):
3552
"""Implementation of the pip.whl_mods tag class.
3653
@@ -190,7 +207,7 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides):
190207
if whl_name not in whl_map[hub_name]:
191208
whl_map[hub_name][whl_name] = {}
192209

193-
whl_map[hub_name][whl_name][full_version(pip_attr.python_version)] = pip_name + "_"
210+
whl_map[hub_name][whl_name][_major_minor_version(pip_attr.python_version)] = pip_name + "_"
194211

195212
def _pip_impl(module_ctx):
196213
"""Implementation of a class tag that creates the pip hub and corresponding pip spoke whl repositories.
@@ -341,7 +358,7 @@ def _pip_impl(module_ctx):
341358
name = hub_name,
342359
repo_name = hub_name,
343360
whl_map = whl_map,
344-
default_version = full_version(DEFAULT_PYTHON_VERSION),
361+
default_version = _major_minor_version(DEFAULT_PYTHON_VERSION),
345362
)
346363

347364
def _pip_parse_ext_attrs():

python/private/bzlmod/pip_repository.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pip_repository_attrs = {
6363
"default_version": attr.string(
6464
mandatory = True,
6565
doc = """\
66-
This is the default python version in the format of X.Y.Z. This should match
66+
This is the default python version in the format of X.Y. This should match
6767
what is setup by the 'python' extension using the 'is_default = True'
6868
setting.""",
6969
),

tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ _tests.append(_test_all_legacy_aliases_are_created)
7373

7474
def _test_bzlmod_aliases(env):
7575
actual = render_pkg_aliases(
76-
default_version = "3.2.3",
76+
default_version = "3.2",
7777
repo_name = "pypi",
7878
rules_python = "rules_python",
7979
whl_map = {
80-
"bar-baz": ["3.2.3"],
80+
"bar-baz": ["3.2"],
8181
},
8282
)
8383

@@ -94,7 +94,7 @@ alias(
9494
name = "pkg",
9595
actual = select(
9696
{
97-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
97+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
9898
"//conditions:default": "@pypi_32_bar_baz//:pkg",
9999
},
100100
),
@@ -104,7 +104,7 @@ alias(
104104
name = "whl",
105105
actual = select(
106106
{
107-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
107+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
108108
"//conditions:default": "@pypi_32_bar_baz//:whl",
109109
},
110110
),
@@ -114,7 +114,7 @@ alias(
114114
name = "data",
115115
actual = select(
116116
{
117-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
117+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
118118
"//conditions:default": "@pypi_32_bar_baz//:data",
119119
},
120120
),
@@ -124,7 +124,7 @@ alias(
124124
name = "dist_info",
125125
actual = select(
126126
{
127-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
127+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
128128
"//conditions:default": "@pypi_32_bar_baz//:dist_info",
129129
},
130130
),
@@ -141,7 +141,7 @@ def _test_bzlmod_aliases_with_no_default_version(env):
141141
repo_name = "pypi",
142142
rules_python = "rules_python",
143143
whl_map = {
144-
"bar-baz": ["3.2.3", "3.1.3"],
144+
"bar-baz": ["3.2", "3.1"],
145145
},
146146
)
147147

@@ -154,7 +154,7 @@ No matching wheel for current configuration's Python version.
154154
155155
The current build configuration's Python version doesn't match any of the Python
156156
versions available for this wheel. This wheel supports the following Python versions:
157-
3.1.3, 3.2.3
157+
3.1, 3.2
158158
159159
As matched by the `@rules_python//python/config_settings:is_python_<version>`
160160
configuration settings.
@@ -177,8 +177,8 @@ alias(
177177
name = "pkg",
178178
actual = select(
179179
{
180-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
181-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
180+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
181+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
182182
},
183183
no_match_error = _NO_MATCH_ERROR,
184184
),
@@ -188,8 +188,8 @@ alias(
188188
name = "whl",
189189
actual = select(
190190
{
191-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
192-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
191+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
192+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
193193
},
194194
no_match_error = _NO_MATCH_ERROR,
195195
),
@@ -199,8 +199,8 @@ alias(
199199
name = "data",
200200
actual = select(
201201
{
202-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
203-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
202+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
203+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
204204
},
205205
no_match_error = _NO_MATCH_ERROR,
206206
),
@@ -210,8 +210,8 @@ alias(
210210
name = "dist_info",
211211
actual = select(
212212
{
213-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
214-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
213+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
214+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
215215
},
216216
no_match_error = _NO_MATCH_ERROR,
217217
),
@@ -224,11 +224,18 @@ _tests.append(_test_bzlmod_aliases_with_no_default_version)
224224

225225
def _test_bzlmod_aliases_for_non_root_modules(env):
226226
actual = render_pkg_aliases(
227-
default_version = "3.2.4",
227+
# NOTE @aignas 2024-01-17: if the default X.Y version coincides with the
228+
# versions that are used in the root module, then this would be the same as
229+
# as _test_bzlmod_aliases.
230+
#
231+
# However, if the root module uses a different default version than the
232+
# non-root module, then we will have a no-match-error because the default_version
233+
# is not in the list of the versions in the whl_map.
234+
default_version = "3.3",
228235
repo_name = "pypi",
229236
rules_python = "rules_python",
230237
whl_map = {
231-
"bar-baz": ["3.2.3", "3.1.3"],
238+
"bar-baz": ["3.2", "3.1"],
232239
},
233240
)
234241

@@ -241,7 +248,7 @@ No matching wheel for current configuration's Python version.
241248
242249
The current build configuration's Python version doesn't match any of the Python
243250
versions available for this wheel. This wheel supports the following Python versions:
244-
3.1.3, 3.2.3
251+
3.1, 3.2
245252
246253
As matched by the `@rules_python//python/config_settings:is_python_<version>`
247254
configuration settings.
@@ -264,8 +271,8 @@ alias(
264271
name = "pkg",
265272
actual = select(
266273
{
267-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:pkg",
268-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:pkg",
274+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
275+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
269276
},
270277
no_match_error = _NO_MATCH_ERROR,
271278
),
@@ -275,8 +282,8 @@ alias(
275282
name = "whl",
276283
actual = select(
277284
{
278-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:whl",
279-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:whl",
285+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
286+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
280287
},
281288
no_match_error = _NO_MATCH_ERROR,
282289
),
@@ -286,8 +293,8 @@ alias(
286293
name = "data",
287294
actual = select(
288295
{
289-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:data",
290-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:data",
296+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
297+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
291298
},
292299
no_match_error = _NO_MATCH_ERROR,
293300
),
@@ -297,8 +304,8 @@ alias(
297304
name = "dist_info",
298305
actual = select(
299306
{
300-
"@@rules_python//python/config_settings:is_python_3.1.3": "@pypi_31_bar_baz//:dist_info",
301-
"@@rules_python//python/config_settings:is_python_3.2.3": "@pypi_32_bar_baz//:dist_info",
307+
"@@rules_python//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
308+
"@@rules_python//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
302309
},
303310
no_match_error = _NO_MATCH_ERROR,
304311
),
@@ -311,12 +318,12 @@ _tests.append(_test_bzlmod_aliases_for_non_root_modules)
311318

312319
def _test_bzlmod_aliases_are_created_for_all_wheels(env):
313320
actual = render_pkg_aliases(
314-
default_version = "3.2.3",
321+
default_version = "3.2",
315322
repo_name = "pypi",
316323
rules_python = "rules_python",
317324
whl_map = {
318-
"bar": ["3.1.2", "3.2.3"],
319-
"foo": ["3.1.2", "3.2.3"],
325+
"bar": ["3.1", "3.2"],
326+
"foo": ["3.1", "3.2"],
320327
},
321328
)
322329

0 commit comments

Comments
 (0)