Skip to content

Commit 451e62c

Browse files
authored
refactor(internal): make the usage of MINOR_MAPPING variable explicit in full_version (#2219)
This PR just makes the `MINOR_MAPPING` overridable and explicit in many macros/rules that we own. Even though technically new API is exposed, I am not sure if it is possible to use it and I am not sure if we should advertise it. Explicit minor_mapping results in easier wiring of `python.override` `bzlmod` extension tag class planned for #2081.
1 parent 9b16bfb commit 451e62c

File tree

11 files changed

+68
-36
lines changed

11 files changed

+68
-36
lines changed

examples/bzlmod/MODULE.bazel.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/private/BUILD.bazel

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ bzl_library(
114114
bzl_library(
115115
name = "full_version_bzl",
116116
srcs = ["full_version.bzl"],
117-
deps = ["//python:versions_bzl"],
118117
)
119118

120119
bzl_library(
@@ -132,6 +131,7 @@ bzl_library(
132131
name = "python_bzl",
133132
srcs = ["python.bzl"],
134133
deps = [
134+
":full_version_bzl",
135135
":pythons_hub_bzl",
136136
":repo_utils_bzl",
137137
":toolchains_repo_bzl",
@@ -164,7 +164,6 @@ bzl_library(
164164
deps = [
165165
":full_version_bzl",
166166
":py_toolchain_suite_bzl",
167-
"//python:versions_bzl",
168167
],
169168
)
170169

python/private/config_settings.bzl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ def _ver_key(s):
2727
micro, _, s = s.partition(".")
2828
return (int(major), int(minor), int(micro))
2929

30-
def _flag_values(python_versions):
30+
def _flag_values(*, python_versions, minor_mapping):
3131
"""Construct a map of python_version to a list of toolchain values.
3232
3333
This mapping maps the concept of a config setting to a list of compatible toolchain versions.
3434
For using this in the code, the VERSION_FLAG_VALUES should be used instead.
3535
3636
Args:
37-
python_versions: list of strings; all X.Y.Z python versions
37+
python_versions: {type}`list[str]` X.Y.Z` python versions.
38+
minor_mapping: {type}`dict[str, str]` `X.Y` to `X.Y.Z` mapping.
3839
3940
Returns:
4041
A `map[str, list[str]]`. Each key is a python_version flag value. Each value
@@ -61,13 +62,13 @@ def _flag_values(python_versions):
6162
ret.setdefault(minor_version, [minor_version]).append(micro_version)
6263

6364
# Ensure that is_python_3.9.8 is matched if python_version is set
64-
# to 3.9 if MINOR_MAPPING points to 3.9.8
65-
default_micro_version = MINOR_MAPPING[minor_version]
65+
# to 3.9 if minor_mapping points to 3.9.8
66+
default_micro_version = minor_mapping[minor_version]
6667
ret[micro_version] = [micro_version, minor_version] if default_micro_version == micro_version else [micro_version]
6768

6869
return ret
6970

70-
VERSION_FLAG_VALUES = _flag_values(TOOL_VERSIONS.keys())
71+
VERSION_FLAG_VALUES = _flag_values(python_versions = TOOL_VERSIONS.keys(), minor_mapping = MINOR_MAPPING)
7172

7273
def is_python_config_setting(name, *, python_version, reuse_conditions = None, **kwargs):
7374
"""Create a config setting for matching 'python_version' configuration flag.

python/private/full_version.bzl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,19 @@
1414

1515
"""A small helper to ensure that we are working with full versions."""
1616

17-
load("//python:versions.bzl", "MINOR_MAPPING")
18-
19-
def full_version(version):
17+
def full_version(*, version, minor_mapping):
2018
"""Return a full version.
2119
2220
Args:
23-
version: the version in `X.Y` or `X.Y.Z` format.
21+
version: {type}`str` the version in `X.Y` or `X.Y.Z` format.
22+
minor_mapping: {type}`dict[str, str]` mapping between `X.Y` to `X.Y.Z` format.
2423
2524
Returns:
2625
a full version given the version string. If the string is already a
2726
major version then we return it as is.
2827
"""
29-
if version in MINOR_MAPPING:
30-
return MINOR_MAPPING[version]
28+
if version in minor_mapping:
29+
return minor_mapping[version]
3130

3231
parts = version.split(".")
3332
if len(parts) == 3:
@@ -36,7 +35,7 @@ def full_version(version):
3635
fail(
3736
"Unknown Python version '{}', available values are: {}".format(
3837
version,
39-
",".join(MINOR_MAPPING.keys()),
38+
",".join(minor_mapping.keys()),
4039
),
4140
)
4241
else:

python/private/pypi/BUILD.bazel

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ bzl_library(
156156
bzl_library(
157157
name = "multi_pip_parse_bzl",
158158
srcs = ["multi_pip_parse.bzl"],
159-
deps = ["pip_repository_bzl"],
159+
deps = [
160+
"pip_repository_bzl",
161+
"//python/private:text_util_bzl",
162+
],
160163
)
161164

162165
bzl_library(

python/private/pypi/multi_pip_parse.bzl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""A pip_parse implementation for version aware toolchains in WORKSPACE."""
1616

17+
load("//python/private:text_util.bzl", "render")
1718
load(":pip_repository.bzl", pip_parse = "pip_repository")
1819

1920
def _multi_pip_parse_impl(rctx):
@@ -97,6 +98,7 @@ def install_deps(**whl_library_kwargs):
9798
name = "{name}_" + wheel_name,
9899
wheel_name = wheel_name,
99100
default_version = "{default_version}",
101+
minor_mapping = {minor_mapping},
100102
version_map = _version_map[wheel_name],
101103
)
102104
""".format(
@@ -107,6 +109,7 @@ def install_deps(**whl_library_kwargs):
107109
process_requirements_calls = "\n".join(process_requirements_calls),
108110
rules_python = rules_python,
109111
default_version = rctx.attr.default_version,
112+
minor_mapping = render.indent(render.dict(rctx.attr.minor_mapping)).lstrip(),
110113
)
111114
rctx.file("requirements.bzl", requirements_bzl)
112115
rctx.file("BUILD.bazel", "exports_files(['requirements.bzl'])")
@@ -115,23 +118,25 @@ _multi_pip_parse = repository_rule(
115118
_multi_pip_parse_impl,
116119
attrs = {
117120
"default_version": attr.string(),
121+
"minor_mapping": attr.string_dict(),
118122
"pip_parses": attr.string_dict(),
119123
"_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
120124
},
121125
)
122126

123-
def multi_pip_parse(name, default_version, python_versions, python_interpreter_target, requirements_lock, **kwargs):
127+
def multi_pip_parse(name, default_version, python_versions, python_interpreter_target, requirements_lock, minor_mapping, **kwargs):
124128
"""NOT INTENDED FOR DIRECT USE!
125129
126130
This is intended to be used by the multi_pip_parse implementation in the template of the
127131
multi_toolchain_aliases repository rule.
128132
129133
Args:
130134
name: the name of the multi_pip_parse repository.
131-
default_version: the default Python version.
132-
python_versions: all Python toolchain versions currently registered.
133-
python_interpreter_target: a dictionary which keys are Python versions and values are resolved host interpreters.
134-
requirements_lock: a dictionary which keys are Python versions and values are locked requirements files.
135+
default_version: {type}`str` the default Python version.
136+
python_versions: {type}`list[str]` all Python toolchain versions currently registered.
137+
python_interpreter_target: {type}`dict[str, Label]` a dictionary which keys are Python versions and values are resolved host interpreters.
138+
requirements_lock: {type}`dict[str, Label]` a dictionary which keys are Python versions and values are locked requirements files.
139+
minor_mapping: {type}`dict[str, str]` mapping between `X.Y` to `X.Y.Z` format.
135140
**kwargs: extra arguments passed to all wrapped pip_parse.
136141
137142
Returns:
@@ -157,4 +162,5 @@ def multi_pip_parse(name, default_version, python_versions, python_interpreter_t
157162
name = name,
158163
default_version = default_version,
159164
pip_parses = pip_parses,
165+
minor_mapping = minor_mapping,
160166
)

python/private/pypi/whl_library_alias.bzl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ def _whl_library_alias_impl(rctx):
2929
build_content.append(_whl_library_render_alias_target(
3030
alias_name = alias_name,
3131
default_repo_prefix = default_repo_prefix,
32+
minor_mapping = rctx.attr.minor_mapping,
3233
rules_python = rules_python,
3334
version_map = version_map,
3435
wheel_name = rctx.attr.wheel_name,
3536
))
3637
rctx.file("BUILD.bazel", "\n".join(build_content))
3738

3839
def _whl_library_render_alias_target(
40+
*,
3941
alias_name,
4042
default_repo_prefix,
43+
minor_mapping,
4144
rules_python,
4245
version_map,
4346
wheel_name):
@@ -48,7 +51,7 @@ alias(
4851
for [python_version, repo_prefix] in version_map:
4952
alias.append("""\
5053
"@{rules_python}//python/config_settings:is_python_{full_python_version}": "{actual}",""".format(
51-
full_python_version = full_version(python_version),
54+
full_python_version = full_version(version = python_version, minor_mapping = minor_mapping),
5255
actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
5356
repo_prefix = repo_prefix,
5457
wheel_name = wheel_name,
@@ -92,6 +95,7 @@ whl_library_alias = repository_rule(
9295
"not specified, then the default rules won't be able to " +
9396
"resolve a wheel and an error will occur.",
9497
),
98+
"minor_mapping": attr.string_dict(mandatory = True),
9599
"version_map": attr.string_dict(mandatory = True),
96100
"wheel_name": attr.string(mandatory = True),
97101
"_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),

python/private/python.bzl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
load("@bazel_features//:features.bzl", "bazel_features")
1818
load("//python:repositories.bzl", "python_register_toolchains")
19-
load("//python:versions.bzl", "TOOL_VERSIONS")
20-
load("//python/private:repo_utils.bzl", "repo_utils")
19+
load("//python:versions.bzl", "MINOR_MAPPING", "TOOL_VERSIONS")
20+
load(":full_version.bzl", "full_version")
2121
load(":pythons_hub.bzl", "hub_repo")
22+
load(":repo_utils.bzl", "repo_utils")
2223
load(":text_util.bzl", "render")
2324
load(":toolchains_repo.bzl", "multi_toolchain_aliases")
2425
load(":util.bzl", "IS_BAZEL_6_4_OR_HIGHER")
@@ -184,6 +185,11 @@ def parse_modules(module_ctx):
184185
fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
185186

186187
return struct(
188+
debug_info = debug_info,
189+
default_python_version = toolchains[-1].python_version,
190+
defaults = {
191+
"ignore_root_user_error": ignore_root_user_error,
192+
},
187193
toolchains = [
188194
struct(
189195
python_version = t.python_version,
@@ -192,11 +198,6 @@ def parse_modules(module_ctx):
192198
)
193199
for t in toolchains
194200
],
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-
},
200201
)
201202

202203
def _python_impl(module_ctx):
@@ -207,6 +208,7 @@ def _python_impl(module_ctx):
207208
name = toolchain_info.name,
208209
python_version = toolchain_info.python_version,
209210
register_coverage_tool = toolchain_info.register_coverage_tool,
211+
minor_mapping = MINOR_MAPPING,
210212
**py.defaults
211213
)
212214

@@ -220,7 +222,10 @@ def _python_impl(module_ctx):
220222
render.toolchain_prefix(index, toolchain.name, _TOOLCHAIN_INDEX_PAD_LENGTH)
221223
for index, toolchain in enumerate(py.toolchains)
222224
],
223-
toolchain_python_versions = [t.python_version for t in py.toolchains],
225+
toolchain_python_versions = [
226+
full_version(version = t.python_version, minor_mapping = MINOR_MAPPING)
227+
for t in py.toolchains
228+
],
224229
# The last toolchain is the default; it can't have version constraints
225230
# Despite the implication of the arg name, the values are strs, not bools
226231
toolchain_set_python_version_constraints = [

python/private/python_repositories.bzl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
2222
load(
2323
"//python:versions.bzl",
2424
"DEFAULT_RELEASE_BASE_URL",
25+
"MINOR_MAPPING",
2526
"PLATFORMS",
2627
"TOOL_VERSIONS",
2728
"get_release_info",
@@ -583,6 +584,7 @@ def python_register_toolchains(
583584
register_coverage_tool = False,
584585
set_python_version_constraint = False,
585586
tool_versions = None,
587+
minor_mapping = None,
586588
**kwargs):
587589
"""Convenience macro for users which does typical setup.
588590
@@ -607,6 +609,8 @@ def python_register_toolchains(
607609
tool_versions: {type}`dict` contains a mapping of version with SHASUM
608610
and platform info. If not supplied, the defaults in
609611
python/versions.bzl will be used.
612+
minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z`
613+
version.
610614
**kwargs: passed to each {obj}`python_repository` call.
611615
"""
612616

@@ -616,8 +620,9 @@ def python_register_toolchains(
616620

617621
base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL)
618622
tool_versions = tool_versions or TOOL_VERSIONS
623+
minor_mapping = minor_mapping or MINOR_MAPPING
619624

620-
python_version = full_version(python_version)
625+
python_version = full_version(version = python_version, minor_mapping = minor_mapping)
621626

622627
toolchain_repo_name = "{name}_toolchains".format(name = name)
623628

@@ -716,6 +721,7 @@ def python_register_multi_toolchains(
716721
name,
717722
python_versions,
718723
default_version = None,
724+
minor_mapping = None,
719725
**kwargs):
720726
"""Convenience macro for registering multiple Python toolchains.
721727
@@ -724,11 +730,15 @@ def python_register_multi_toolchains(
724730
python_versions: {type}`list[str]` the Python versions.
725731
default_version: {type}`str` the default Python version. If not set,
726732
the first version in python_versions is used.
733+
minor_mapping: {type}`dict[str, str]` mapping between `X.Y` to `X.Y.Z`
734+
format. Defaults to the value in `//python:versions.bzl`.
727735
**kwargs: passed to each {obj}`python_register_toolchains` call.
728736
"""
729737
if len(python_versions) == 0:
730738
fail("python_versions must not be empty")
731739

740+
minor_mapping = minor_mapping or MINOR_MAPPING
741+
732742
if not default_version:
733743
default_version = python_versions.pop(0)
734744
for python_version in python_versions:
@@ -742,12 +752,14 @@ def python_register_multi_toolchains(
742752
name = name + "_" + python_version.replace(".", "_"),
743753
python_version = python_version,
744754
set_python_version_constraint = True,
755+
minor_mapping = minor_mapping,
745756
**kwargs
746757
)
747758
python_register_toolchains(
748759
name = name + "_" + default_version.replace(".", "_"),
749760
python_version = default_version,
750761
set_python_version_constraint = False,
762+
minor_mapping = minor_mapping,
751763
**kwargs
752764
)
753765

@@ -757,4 +769,5 @@ def python_register_multi_toolchains(
757769
python_version: name + "_" + python_version.replace(".", "_")
758770
for python_version in (python_versions + [default_version])
759771
},
772+
minor_mapping = minor_mapping,
760773
)

python/private/pythons_hub.bzl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
"Repo rule used by bzlmod extension to create a repo that has a map of Python interpreters and their labels"
1616

17-
load("//python/private:full_version.bzl", "full_version")
1817
load(
1918
"//python/private:toolchains_repo.bzl",
2019
"python_toolchain_build_file_content",
@@ -59,7 +58,7 @@ def _hub_build_file_content(
5958
[
6059
python_toolchain_build_file_content(
6160
prefix = prefixes[i],
62-
python_version = full_version(python_versions[i]),
61+
python_version = python_versions[i],
6362
set_python_version_constraint = set_python_version_constraints[i],
6463
user_repository_name = user_repository_names[i],
6564
)
@@ -123,15 +122,15 @@ This rule also writes out the various toolchains for the different Python versio
123122
implementation = _hub_repo_impl,
124123
attrs = {
125124
"default_python_version": attr.string(
126-
doc = "Default Python version for the build.",
125+
doc = "Default Python version for the build in `X.Y` or `X.Y.Z` format.",
127126
mandatory = True,
128127
),
129128
"toolchain_prefixes": attr.string_list(
130129
doc = "List prefixed for the toolchains",
131130
mandatory = True,
132131
),
133132
"toolchain_python_versions": attr.string_list(
134-
doc = "List of Python versions for the toolchains",
133+
doc = "List of Python versions for the toolchains. In `X.Y.Z` format.",
135134
mandatory = True,
136135
),
137136
"toolchain_set_python_version_constraints": attr.string_list(

0 commit comments

Comments
 (0)