8000 test(bzlmod): add python.toolchain unit tests (#2204) · keith/rules_python@c9972d3 · GitHub
[go: up one dir, main page]

Skip to content

Commit c9972d3

Browse files
aignasrickeylev
andauthored
test(bzlmod): add python.toolchain unit tests (bazel-contrib#2204)
With this PR we get rudimentary unit tests for the `python` bzlmod extension which allows us to unit test the override behaviour that will become more complex soon. Summary: - refactor: inline the python_register_toolchains - refactor: use toolchain_info to call python_register_toolchains - refactor: move the registration out of the main loop - refactor: split the parsing of the modules to a separate function - test(bzlmod): add python.toolchain module parsing tests Work towards bazel-contrib#2081 --------- Co-authored-by: Richard Levasseur <richardlev@gmail.com>
1 parent 7d42a93 commit c9972d3

File tree

3 files changed

+328
-31
lines changed

3 files changed

+328
-31
lines changed

python/private/python.bzl

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,21 @@ load(":util.bzl", "IS_BAZEL_6_4_OR_HIGHER")
2828
_MAX_NUM_TOOLCHAINS = 9999
2929
_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
3030

31-
def _python_register_toolchains(name, toolchain_attr, module, ignore_root_user_error):
32-
"""Calls python_register_toolchains and returns a struct used to collect the toolchains.
31+
def parse_modules(module_ctx):
32+
"""Parse the modules and return a struct for registrations.
33+
34+
Args:
35+
module_ctx: {type}`module_ctx` module context.
36+
37+
Returns:
38+
A struct with the following attributes:
39+
* `toolchains`: The list of toolchains to register. The last
40+
element is special and is treated as the default toolchain.
41+
* `defaults`: The default `kwargs` passed to
42+
{bzl:obj}`python_register_toolchains`.
43+
* `debug_info`: {type}`None | dict` extra information to be passed
44+
to the debug repo.
3345
"""
34-
python_register_toolchains(
35-
name = name,
36-
python_version = toolchain_attr.python_version,
37-
register_coverage_tool = toolchain_attr.configure_coverage_tool,
38-
ignore_root_user_error = ignore_root_user_error,
39-
)
40-
return struct(
41-
python_version = toolchain_attr.python_version,
42-
name = name,
43-
module = struct(name = module.name, is_root = module.is_root),
44-
)
45-
46-
def _python_impl(module_ctx):
4746
if module_ctx.os.environ.get("RULES_PYTHON_BZLMOD_DEBUG", "0") == "1":
4847
debug_info = {
4948
"toolchains_registered": [],
@@ -61,7 +60,7 @@ def _python_impl(module_ctx):
6160
# This is a toolchain_info struct.
6261
default_toolchain = None
6362

64-
# Map of string Major.Minor to the toolchain_info struct
63+
# Map of version string to the toolchain_info struct
6564
global_toolchain_versions = {}
6665

6766
ignore_root_user_error = None
@@ -139,11 +138,11 @@ def _python_impl(module_ctx):
139138
)
140139
toolchain_info = None
141140
else:
142-
toolchain_info = _python_register_toolchains(
143-
toolchain_name,
144-
toolchain_attr,
145-
module = mod,
146-
ignore_root_user_error = ignore_root_user_error,
141+
toolchain_info = struct(
142+
python_version = toolchain_attr.python_version,
143+
name = toolchain_name,
144+
register_coverage_tool = toolchain_attr.configure_coverage_tool,
145+
module = struct(name = mod.name, is_root = mod.is_root),
147146
)
148147
global_toolchain_versions[toolchain_version] = toolchain_info
149148
if debug_info:
@@ -184,39 +183,67 @@ def _python_impl(module_ctx):
184183
if len(toolchains) > _MAX_NUM_TOOLCHAINS:
185184
fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
186185

186+
return struct(
187+
toolchains = [
188+
struct(
189+
python_version = t.python_version,
190+
name = t.name,
191+
register_coverage_tool = t.register_coverage_tool,
192+
)
193+
for t in toolchains
194+
],
195+
debug_info = debug_info,
196+
default_python_version = toolchains[-1].python_version,
197+
defaults = {
198+
"ignore_root_user_error": ignore_root_user_error,
199+
},
200+
)
201+
202+
def _python_impl(module_ctx):
203+
py = parse_modules(module_ctx)
204+
205+
for toolchain_info in py.toolchains:
206+
python_register_toolchains(
207+
name = toolchain_info.name,
208+
python_version = toolchain_info.python_version,
209+
register_coverage_tool = toolchain_info.register_coverage_tool,
210+
**py.defaults
211+
)
212+
187213
# Create the pythons_hub repo for the interpreter meta data and the
188214
# the various toolchains.
189215
hub_repo(
190216
name = "pythons_hub",
191-
default_python_version = default_toolchain.python_version,
217+
# Last toolchain is default
218+
default_python_version = py.default_python_version,
192219
toolchain_prefixes = [
193220
render.toolchain_prefix(index, toolchain.name, _TOOLCHAIN_INDEX_PAD_LENGTH)
194-
for index, toolchain in enumerate(toolchains)
221+
for index, toolchain in enumerate(py.toolchains)
195222
],
196-
toolchain_python_versions = [t.python_version for t in toolchains],
223+
toolchain_python_versions = [t.python_version for t in py.toolchains],
197224
# The last toolchain is the default; it can't have version constraints
198225
# Despite the implication of the arg name, the values are strs, not bools
199226
toolchain_set_python_version_constraints = [
200-
"True" if i != len(toolchains) - 1 else "False"
201-
for i in range(len(toolchains))
227+
"True" if i != len(py.toolchains) - 1 else "False"
228+
for i in range(len(py.toolchains))
202229
],
203-
toolchain_user_repository_names = [t.name for t in toolchains],
230+
toolchain_user_repository_names = [t.name for t in py.toolchains],
204231
)
205232

206233
# This is require in order to support multiple version py_test
207234
# and py_binary
208235
multi_toolchain_aliases(
209236
name = "python_versions",
210237
python_versions = {
211-
version: toolchain.name
212-
for version, toolchain in global_toolchain_versions.items()
238+
toolchain.python_version: toolchain.name
239+
for toolchain in py.toolchains
213240
},
214241
)
215242

216-
if debug_info != None:
243+
if py.debug_info != None:
217244
_debug_repo(
218245
name = "rules_python_bzlmod_debug",
219-
debug_info = json.encode_indent(debug_info),
246+
debug_info = json.encode_indent(py.debug_info),
220247
)
221248

222249
if bazel_features.external_deps.extension_metadata_has_reproducible:

tests/python/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load(":python_tests.bzl", "python_test_suite")
16+
17+
python_test_suite(name = "python_tests")

0 commit comments

Comments
 (0)
0