Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 38b5ac0

Browse filesBrowse files
authored
refactor(bzlmod): move bzlmod code to private/bzlmod (bazel-contrib#1477)
This PR just moves all of the private `bzlmod` code to `python/private/bzlmod` and adds minimal `bzl_library` bindings to make the docs the same. Once bazel-contrib#1476 is merged, we can start exposing documentation for `module_extension`. This includes extras in `pip_install/pip_repository.bzl` just to make it possible to review and merge bazel-contrib#1476 and this in parallel.
1 parent 8dbe88f commit 38b5ac0
Copy full SHA for 38b5ac0

14 files changed

+845
-753
lines changed

‎MODULE.bazel

Copy file name to clipboardExpand all lines: MODULE.bazel
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf"
1414

1515
bazel_dep(name = "stardoc", version = "0.6.2", dev_dependency = True, repo_name = "io_bazel_stardoc")
1616

17-
internal_deps = use_extension("@rules_python//python/extensions/private:internal_deps.bzl", "internal_deps")
17+
internal_deps = use_extension("@rules_python//python/private/bzlmod:internal_deps.bzl", "internal_deps")
1818
internal_deps.install()
1919
use_repo(
2020
internal_deps,

‎python/extensions/pip.bzl

Copy file name to clipboardExpand all lines: python/extensions/pip.bzl
+2-439Lines changed: 2 additions & 439 deletions
Large diffs are not rendered by default.

‎python/extensions/python.bzl

Copy file name to clipboardExpand all lines: python/extensions/python.bzl
+2-249Lines changed: 2 additions & 249 deletions
Original file line numberDiff line numberDiff line change
@@ -14,253 +14,6 @@
1414

1515
"Python toolchain module extensions for use with bzlmod"
1616

17-
load("//python:repositories.bzl", "python_register_toolchains")
18-
load("//python/extensions/private:pythons_hub.bzl", "hub_repo")
19-
load("//python/private:toolchains_repo.bzl", "multi_toolchain_aliases")
17+
load("//python/private/bzlmod:python.bzl", _python = "python")
2018

21-
# This limit can be increased essentially arbitrarily, but doing so will cause a rebuild of all
22-
# targets using any of these toolchains due to the changed repository name.
23-
_MAX_NUM_TOOLCHAINS = 9999
24-
_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
25-
26-
def _toolchain_prefix(index, name):
27-
"""Prefixes the given name with the index, padded with zeros to ensure lexicographic sorting.
28-
29-
Examples:
30-
_toolchain_prefix( 2, "foo") == "_0002_foo_"
31-
_toolchain_prefix(2000, "foo") == "_2000_foo_"
32-
"""
33-
return "_{}_{}_".format(_left_pad_zero(index, _TOOLCHAIN_INDEX_PAD_LENGTH), name)
34-
35-
def _left_pad_zero(index, length):
36-
if index < 0:
37-
fail("index must be non-negative")
38-
return ("0" * length + str(index))[-length:]
39-
40-
# Printing a warning msg not debugging, so we have to disable
41-
# the buildifier check.
42-
# buildifier: disable=print
43-
def _print_warn(msg):
44-
print("WARNING:", msg)
45-
46-
def _python_register_toolchains(name, toolchain_attr, version_constraint):
47-
"""Calls python_register_toolchains and returns a struct used to collect the toolchains.
48-
"""
49-
python_register_toolchains(
50-
name = name,
51-
python_version = toolchain_attr.python_version,
52-
register_coverage_tool = toolchain_attr.configure_coverage_tool,
53-
ignore_root_user_error = toolchain_attr.ignore_root_user_error,
54-
set_python_version_constraint = version_constraint,
55-
)
56-
return struct(
57-
python_version = toolchain_attr.python_version,
58-
set_python_version_constraint = str(version_constraint),
59-
name = name,
60-
)
61-
62-
def _python_impl(module_ctx):
63-
# The toolchain info structs to register, in the order to register them in.
64-
toolchains = []
65-
66-
# We store the default toolchain separately to ensure it is the last
67-
# toolchain added to toolchains.
68-
default_toolchain = None
69-
70-
# Map of string Major.Minor to the toolchain name and module name
71-
global_toolchain_versions = {}
72-
73-
for mod in module_ctx.modules:
74-
module_toolchain_versions = []
75-
76-
for toolchain_attr in mod.tags.toolchain:
77-
toolchain_version = toolchain_attr.python_version
78-
toolchain_name = "python_" + toolchain_version.replace(".", "_")
79-
80-
# Duplicate versions within a module indicate a misconfigured module.
81-
if toolchain_version in module_toolchain_versions:
82-
_fail_duplicate_module_toolchain_version(toolchain_version, mod.name)
83-
module_toolchain_versions.append(toolchain_version)
84-
85-
# Ignore version collisions in the global scope because there isn't
86-
# much else that can be done. Modules don't know and can't control
87-
# what other modules do, so the first in the dependency graph wins.
88-
if toolchain_version in global_toolchain_versions:
89-
# If the python version is explicitly provided by the root
90-
# module, they should not be warned for choosing the same
91-
# version that rules_python provides as default.
92-
first = global_toolchain_versions[toolchain_version]
93-
if mod.name != "rules_python" or not first.is_root:
94-
_warn_duplicate_global_toolchain_version(
95-
toolchain_version,
96-
first = first,
97-
second_toolchain_name = toolchain_name,
98-
second_module_name = mod.name,
99-
)
100-
continue
101-
global_toolchain_versions[toolchain_version] = struct(
102-
toolchain_name = toolchain_name,
103-
module_name = mod.name,
104-
is_root = mod.is_root,
105-
)
106-
107-
# Only the root module and rules_python are allowed to specify the default
108-
# toolchain for a couple reasons:
109-
# * It prevents submodules from specifying different defaults and only
110-
# one of them winning.
111-
# * rules_python needs to set a soft default in case the root module doesn't,
112-
# e.g. if the root module doesn't use Python itself.
113-
# * The root module is allowed to override the rules_python default.
114-
if mod.is_root:
115-
# A single toolchain is treated as the default because it's unambiguous.
116-
is_default = toolchain_attr.is_default or len(mod.tags.toolchain) == 1
117-
elif mod.name == "rules_python" and not default_toolchain:
118-
# We don't do the len() check because we want the default that rules_python
119-
# sets to be clearly visible.
120-
is_default = toolchain_attr.is_default
121-
else:
122-
is_default = False
123-
124-
# We have already found one default toolchain, and we can only have
125-
# one.
126-
if is_default and default_toolchain != None:
127-
_fail_multiple_default_toolchains(
128-
first = default_toolchain.name,
129-
second = toolchain_name,
130-
)
131-
132-
toolchain_info = _python_register_toolchains(
133-
toolchain_name,
134-
toolchain_attr,
135-
version_constraint = not is_default,
136-
)
137-
138-
if is_default:
139-
default_toolchain = toolchain_info
140-
else:
141-
toolchains.append(toolchain_info)
142-
143-
# A default toolchain is required so that the non-version-specific rules
144-
# are able to match a toolchain.
145-
if default_toolchain == None:
146-
fail("No default Python toolchain configured. Is rules_python missing `is_default=True`?")
147-
148-
# The last toolchain in the BUILD file is set as the default
149-
# toolchain. We need the default last.
150-
toolchains.append(default_toolchain)
151-
152-
if len(toolchains) > _MAX_NUM_TOOLCHAINS:
153-
fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
154-
155-
# Create the pythons_hub repo for the interpreter meta data and the
156-
# the various toolchains.
157-
hub_repo(
158-
name = "pythons_hub",
159-
default_python_version = default_toolchain.python_version,
160-
toolchain_prefixes = [
161-
_toolchain_prefix(index, toolchain.name)
162-
for index, toolchain in enumerate(toolchains)
163-
],
164-
toolchain_python_versions = [t.python_version for t in toolchains],
165-
toolchain_set_python_version_constraints = [t.set_python_version_constraint for t in toolchains],
166-
toolchain_user_repository_names = [t.name for t in toolchains],
167-
)
168-
169-
# This is require in order to support multiple version py_test
170-
# and py_binary
171-
multi_toolchain_aliases(
172-
name = "python_versions",
173-
python_versions = {
174-
version: entry.toolchain_name
175-
for version, entry in global_toolchain_versions.items()
176-
},
177-
)
178-
179-
def _fail_duplicate_module_toolchain_version(version, module):
180-
fail(("Duplicate module toolchain version: module '{module}' attempted " +
181-
"to use version '{version}' multiple times in itself").format(
182-
version = version,
183-
module = module,
184-
))
185-
186-
def _warn_duplicate_global_toolchain_version(version, first, second_toolchain_name, second_module_name):
187-
_print_warn((
188-
"Ignoring toolchain '{second_toolchain}' from module '{second_module}': " +
189-
"Toolchain '{first_toolchain}' from module '{first_module}' " +
190-
"already registered Python version {version} and has precedence"
191-
).format(
192-
first_toolchain = first.toolchain_name,
193-
first_module = first.module_name,
194-
second_module = second_module_name,
195-
second_toolchain = second_toolchain_name,
196-
version = version,
197-
))
198-
199-
def _fail_multiple_default_toolchains(first, second):
200-
fail(("Multiple default toolchains: only one toolchain " +
201-
"can have is_default=True. First default " +
202-
"was toolchain '{first}'. Second was '{second}'").format(
203-
first = first,
204-
second = second,
205-
))
206-
207-
python = module_extension(
208-
doc = """Bzlmod extension that is used to register Python toolchains.
209-
""",
210-
implementation = _python_impl,
211-
tag_classes = {
212-
"toolchain": tag_class(
213-
doc = """Tag class used to register Python toolchains.
214-
Use this tag class to register one or more Python toolchains. This class
215-
is also potentially called by sub modules. The following covers different
216-
business rules and use cases.
217-
218-
Toolchains in the Root Module
219-
220-
This class registers all toolchains in the root module.
221-
222-
Toolchains in Sub Modules
223-
224-
It will create a toolchain that is in a sub module, if the toolchain
225-
of the same name does not exist in the root module. The extension stops name
226-
clashing between toolchains in the root module and toolchains in sub modules.
227-
You cannot configure more than one toolchain as the default toolchain.
228-
229-
Toolchain set as the default version
230-
231-
This extension will not create a toolchain that exists in a sub module,
232-
if the sub module toolchain is marked as the default version. If you have
233-
more than one toolchain in your root module, you need to set one of the
234-
toolchains as the default version. If there is only one toolchain it
235-
is set as the default toolchain.
236-
237-
Toolchain repository name
238-
239-
A toolchain's repository name uses the format `python_{major}_{minor}`, e.g.
240-
`python_3_10`. The `major` and `minor` components are
241-
`major` and `minor` are the Python version from the `python_version` attribute.
242-
""",
243-
attrs = {
244-
"configure_coverage_tool": attr.bool(
245-
mandatory = False,
246-
doc = "Whether or not to configure the default coverage tool for the toolchains.",
247-
),
248-
"ignore_root_user_error": attr.bool(
249-
default = False,
250-
doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",
251-
mandatory = False,
252-
),
253-
"is_default": attr.bool(
254-
mandatory = False,
255-
doc = "Whether the toolchain is the default version",
256-
),
257-
"python_version": attr.string(
258-
mandatory = True,
259-
doc = "The Python version, in `major.minor` format, e.g " +
260-
"'3.12', to create a toolchain for. Patch level " +
261-
"granularity (e.g. '3.12.1') is not supported.",
262-
),
263-
},
264-
),
265-
},
266-
)
19+
python = _python

‎python/pip_install/BUILD.bazel

Copy file name to clipboardExpand all lines: python/pip_install/BUILD.bazel
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ bzl_library(
3838
"//python/private:render_pkg_aliases_bzl",
3939
"//python/private:toolchains_repo_bzl",
4040
"//python/private:which_bzl",
41+
"//python/private/bzlmod:pip_repository_bzl",
4142
],
4243
)
4344

‎python/pip_install/pip_repository.bzl

Copy file name to clipboardExpand all lines: python/pip_install/pip_repository.bzl
+4-62Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ load("//python/private:normalize_name.bzl", "normalize_name")
2525
load("//python/private:render_pkg_aliases.bzl", "render_pkg_aliases")
2626
load("//python/private:toolchains_repo.bzl", "get_host_os_arch")
2727
load("//python/private:which.bzl", "which_with_fail")
28+
load("//python/private/bzlmod:pip_repository.bzl", _pip_hub_repository_bzlmod = "pip_repository")
2829

2930
CPPFLAGS = "CPPFLAGS"
3031

3132
COMMAND_LINE_TOOLS_PATH_SLUG = "commandlinetools"
3233

3334
_WHEEL_ENTRY_POINT_PREFIX = "rules_python_wheel_entry_point"
3435

36+
# Kept for not creating merge conflicts with PR#1476, can be removed later.
37+
pip_hub_repository_bzlmod = _pip_hub_repository_bzlmod
38+
3539
def _construct_pypath(rctx):
3640
"""Helper function to construct a PYTHONPATH.
3741
@@ -267,68 +271,6 @@ A requirements_lock attribute must be specified, or a platform-specific lockfile
267271
""")
268272
return requirements_txt
269273

270-
def _pip_hub_repository_bzlmod_impl(rctx):
271-
bzl_packages = rctx.attr.whl_map.keys()
272-
aliases = render_pkg_aliases(
273-
repo_name = rctx.attr.repo_name,
274-
rules_python = rctx.attr._template.workspace_name,
275-
default_version = rctx.attr.default_version,
276-
whl_map = rctx.attr.whl_map,
277-
)
278-
for path, contents in aliases.items():
279-
rctx.file(path, contents)
280-
281-
# NOTE: we are using the canonical name with the double '@' in order to
282-
# always uniquely identify a repository, as the labels are being passed as
283-
# a string and the resolution of the label happens at the call-site of the
284-
# `requirement`, et al. macros.
285-
macro_tmpl = "@@{name}//{{}}:{{}}".format(name = rctx.attr.name)
286-
287-
rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS)
288-
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
289-
"%%ALL_DATA_REQUIREMENTS%%": _format_repr_list([
290-
macro_tmpl.format(p, "data")
291-
for p in bzl_packages
292-
]),
293-
"%%ALL_REQUIREMENTS%%": _format_repr_list([
294-
macro_tmpl.format(p, p)
295-
for p in bzl_packages
296-
]),
297-
"%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
298-
macro_tmpl.format(p, "whl")
299-
for p in bzl_packages
300-
]),
301-
"%%MACRO_TMPL%%": macro_tmpl,
302-
"%%NAME%%": rctx.attr.name,
303-
})
304-
305-
pip_hub_repository_bzlmod_attrs = {
306-
"default_version": attr.string(
307-
mandatory = True,
308-
doc = """\
309-
This is the default python version in the format of X.Y.Z. This should match
310-
what is setup by the 'python' extension using the 'is_default = True'
311-
setting.""",
312-
),
313-
"repo_name": attr.string(
314-
mandatory = True,
315-
doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name.",
316-
),
317-
"whl_map": attr.string_list_dict(
318-
mandatory = True,
319-
doc = "The wheel map where values are python versions",
320-
),
321-
"_template": attr.label(
322-
default = ":pip_repository_requirements_bzlmod.bzl.tmpl",
323-
),
324-
}
325-
326-
pip_hub_repository_bzlmod = repository_rule(
327-
attrs = pip_hub_repository_bzlmod_attrs,
328-
doc = """A rule for bzlmod mulitple pip repository creation. PRIVATE USE ONLY.""",
329-
implementation = _pip_hub_repository_bzlmod_impl,
330-
)
331-
332274
def _pip_repository_impl(rctx):
333275
requirements_txt = locked_requirements_label(rctx, rctx.attr)
334276
content = rctx.read(requirements_txt)

‎python/private/BUILD.bazel

Copy file name to clipboardExpand all lines: python/private/BUILD.bazel
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ licenses(["notice"])
2727
filegroup(
2828
name = "distribution",
2929
srcs = glob(["**"]) + [
30+
"//python/private/bzlmod:distribution",
3031
"//python/private/common:distribution",
3132
"//python/private/proto:distribution",
3233
"//tools/build_defs/python/private:distribution",

‎python/extensions/private/BUILD.bazel renamed to ‎python/private/bzlmod/BUILD.bazel

Copy file name to clipboardExpand all lines: python/private/bzlmod/BUILD.bazel
+13-1Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,24 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
16+
1517
package(default_visibility = ["//visibility:private"])
1618

1719
licenses(["notice"])
1820

1921
filegroup(
2022
name = "distribution",
2123
srcs = glob(["**"]),
22-
visibility = ["//python/extensions/private:__pkg__"],
24+
visibility = ["//python/private:__pkg__"],
25+
)
26+
27+
bzl_library(
28+
name = "pip_repository_bzl",
29+
srcs = ["pip_repository.bzl"],
30+
visibility = ["//:__subpackages__"],
31+
deps = [
32+
"//python/private:render_pkg_aliases_bzl",
33+
"//python/private:text_util_bzl",
34+
],
2335
)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.