refactor: have bzlmod pass platforms to python_register_toolchains (#2884)
This is to facilitate eventually allowing overrides to add additional
platforms.
Instead of the PLATFORMS global being used, the python bzlmod extension
passing the
mapping directly to python_register_toolchains, then receives back the
subset of
platforms that had repos defined. That subset is then later used when
(re)constructing
the list of repo names for the toolchains.
diff --git a/python/private/python.bzl b/python/private/python.bzl
index c187904..c87beef 100644
--- a/python/private/python.bzl
+++ b/python/private/python.bzl
@@ -34,12 +34,13 @@
Returns:
A struct with the following attributes:
- * `toolchains`: The list of toolchains to register. The last
- element is special and is treated as the default toolchain.
- * `defaults`: The default `kwargs` passed to
- {bzl:obj}`python_register_toolchains`.
- * `debug_info`: {type}`None | dict` extra information to be passed
- to the debug repo.
+ * `toolchains`: The list of toolchains to register. The last
+ element is special and is treated as the default toolchain.
+ * `config`: Various toolchain config, see `_get_toolchain_config`.
+ * `debug_info`: {type}`None | dict` extra information to be passed
+ to the debug repo.
+ * `platforms`: {type}`dict[str, platform_info]` of the base set of
+ platforms toolchains should be created for, if possible.
"""
if module_ctx.os.environ.get("RULES_PYTHON_BZLMOD_DEBUG", "0") == "1":
debug_info = {
@@ -285,11 +286,12 @@
kwargs.update(py.config.kwargs.get(toolchain_info.python_version, {}))
kwargs.update(py.config.kwargs.get(full_python_version, {}))
kwargs.update(py.config.default)
- loaded_platforms[full_python_version] = python_register_toolchains(
+ toolchain_registered_platforms = python_register_toolchains(
name = toolchain_info.name,
_internal_bzlmod_toolchain_call = True,
**kwargs
)
+ loaded_platforms[full_python_version] = toolchain_registered_platforms
# List of the base names ("python_3_10") for the toolchain repos
base_toolchain_repo_names = []
@@ -332,20 +334,19 @@
base_name = t.name
base_toolchain_repo_names.append(base_name)
fv = full_version(version = t.python_version, minor_mapping = py.config.minor_mapping)
- for platform in loaded_platforms[fv]:
- if platform not in PLATFORMS:
- continue
+ platforms = loaded_platforms[fv]
+ for platform_name, platform_info in platforms.items():
key = str(len(toolchain_names))
- full_name = "{}_{}".format(base_name, platform)
+ full_name = "{}_{}".format(base_name, platform_name)
toolchain_names.append(full_name)
toolchain_repo_names[key] = full_name
- toolchain_tcw_map[key] = PLATFORMS[platform].compatible_with
+ toolchain_tcw_map[key] = platform_info.compatible_with
# The target_settings attribute may not be present for users
# patching python/versions.bzl.
- toolchain_ts_map[key] = getattr(PLATFORMS[platform], "target_settings", [])
- toolchain_platform_keys[key] = platform
+ toolchain_ts_map[key] = getattr(platform_info, "target_settings", [])
+ toolchain_platform_keys[key] = platform_name
toolchain_python_versions[key] = fv
# The last toolchain is the default; it can't have version constraints
@@ -483,9 +484,9 @@
return
for platform in (tag.sha256 or []):
- if platform not in PLATFORMS:
+ if platform not in default["platforms"]:
_fail("The platform must be one of {allowed} but got '{got}'".format(
- allowed = sorted(PLATFORMS),
+ allowed = sorted(default["platforms"]),
got = platform,
))
return
@@ -602,6 +603,26 @@
override.fn(tag = tag, _fail = _fail, default = default)
def _get_toolchain_config(*, modules, _fail = fail):
+ """Computes the configs for toolchains.
+
+ Args:
+ modules: The modules from module_ctx
+ _fail: Function to call for failing; only used for testing.
+
+ Returns:
+ A struct with the following:
+ * `kwargs`: {type}`dict[str, dict[str, object]` custom kwargs to pass to
+ `python_register_toolchains`, keyed by python version.
+ The first key is either a Major.Minor or Major.Minor.Patch
+ string.
+ * `minor_mapping`: {type}`dict[str, str]` the mapping of Major.Minor
+ to Major.Minor.Patch.
+ * `default`: {type}`dict[str, object]` of kwargs passed along to
+ `python_register_toolchains`. These keys take final precedence.
+ * `register_all_versions`: {type}`bool` whether all known versions
+ should be registered.
+ """
+
# Items that can be overridden
available_versions = {
version: {
@@ -621,6 +642,7 @@
}
default = {
"base_url": DEFAULT_RELEASE_BASE_URL,
+ "platforms": dict(PLATFORMS), # Copy so it's mutable.
"tool_versions": available_versions,
}
diff --git a/python/private/python_register_toolchains.bzl b/python/private/python_register_toolchains.bzl
index cd3e9cb..6a4c0c3 100644
--- a/python/private/python_register_toolchains.bzl
+++ b/python/private/python_register_toolchains.bzl
@@ -41,6 +41,7 @@
register_coverage_tool = False,
set_python_version_constraint = False,
tool_versions = None,
+ platforms = PLATFORMS,
minor_mapping = None,
**kwargs):
"""Convenience macro for users which does typical setup.
@@ -70,12 +71,18 @@
tool_versions: {type}`dict` contains a mapping of version with SHASUM
and platform info. If not supplied, the defaults in
python/versions.bzl will be used.
+ platforms: {type}`dict[str, platform_info]` platforms to create toolchain
+ repositories for. Note that only a subset is created, depending
+ on what's available in `tool_versions`.
minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z`
version.
**kwargs: passed to each {obj}`python_repository` call.
Returns:
- On bzlmod this returns the loaded platform labels. Otherwise None.
+ On workspace, returns None.
+
+ On bzlmod, returns a `dict[str, platform_info]`, which is the
+ subset of `platforms` that it created repositories for.
"""
bzlmod_toolchain_call = kwargs.pop("_internal_bzlmod_toolchain_call", False)
if bzlmod_toolchain_call:
@@ -104,13 +111,13 @@
))
register_coverage_tool = False
- loaded_platforms = []
- for platform in PLATFORMS.keys():
+ loaded_platforms = {}
+ for platform in platforms.keys():
sha256 = tool_versions[python_version]["sha256"].get(platform, None)
if not sha256:
continue
- loaded_platforms.append(platform)
+ loaded_platforms[platform] = platforms[platform]
(release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions)
# allow passing in a tool version
@@ -162,7 +169,7 @@
host_toolchain(
name = name + "_host",
- platforms = loaded_platforms,
+ platforms = loaded_platforms.keys(),
python_version = python_version,
)
@@ -170,7 +177,7 @@
name = name,
python_version = python_version,
user_repository_name = name,
- platforms = loaded_platforms,
+ platforms = loaded_platforms.keys(),
)
# in bzlmod we write out our own toolchain repos
@@ -182,6 +189,6 @@
python_version = python_version,
set_python_version_constraint = set_python_version_constraint,
user_repository_name = name,
- platforms = loaded_platforms,
+ platforms = loaded_platforms.keys(),
)
return None
diff --git a/tests/python/python_tests.bzl b/tests/python/python_tests.bzl
index 443174c..19be1c4 100644
--- a/tests/python/python_tests.bzl
+++ b/tests/python/python_tests.bzl
@@ -149,6 +149,7 @@
"base_url",
"ignore_root_user_error",
"tool_versions",
+ "platforms",
])
env.expect.that_bool(py.config.default["ignore_root_user_error"]).equals(True)
env.expect.that_str(py.default_python_version).equals("3.11")