Skip to content

Commit 0a88a6e

Browse files
committed
improve docs - add repositories.bzl docs and improve docs for bzlmod
1 parent 46af7f9 commit 0a88a6e

File tree

8 files changed

+80
-52
lines changed

8 files changed

+80
-52
lines changed

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ A brief description of the categories of changes:
2525
[x.x.x]: https://github.com/bazelbuild/rules_python/releases/tag/x.x.x
2626

2727
### Changed
28-
* (gazelle): Update error messages when unable to resolve a dependency to be more human-friendly.
28+
* (gazelle): Update error messages when unable to resolve a dependency to be
29+
more human-friendly.
30+
* (toolchain): The toolchain patches now expose the `patch_strip` attribute
31+
that one should use when patching toolchains. Please set it if you are
32+
patching python interpreter. In the next release the default will be set to
33+
`0` which better reflects the defaults used in public `bazel` APIs.
2934

3035
### Fixed
3136
* (whl_library): Remove `--no-index` and add `--no-build-isolation` to the

docs/BUILD.bazel

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ sphinx_stardocs(
9494
"//python/private/common:py_library_rule_bazel_bzl",
9595
"//python/private/common:py_runtime_rule_bzl",
9696
"//python/private/common:py_test_rule_bazel_bzl",
97+
# FIXME @aignas 2024-08-26: should we have this here?
98+
"//python:repositories_bzl",
9799
] + ([
98100
# Bazel 6 + Stardoc isn't able to parse something about the python bzlmod extension
99101
"//python/extensions:python_bzl",

python/private/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ bzl_library(
298298
srcs = ["toolchains_repo.bzl"],
299299
deps = [
300300
":repo_utils_bzl",
301+
":text_util_bzl",
301302
"//python:versions_bzl",
302303
],
303304
)

python/private/common/py_runtime_rule.bzl

+4-4
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ See @bazel_tools//tools/python:python_bootstrap_template.txt for more variables.
204204
"coverage_tool": attr.label(
205205
allow_files = False,
206206
doc = """
207-
This is a target to use for collecting code coverage information from `py_binary`
208-
and `py_test` targets.
207+
This is a target to use for collecting code coverage information from
208+
{rule}`py_binary` and {rule}`py_test` targets.
209209
210210
If set, the target must either produce a single file or be an executable target.
211211
The path to the single file, or the executable if the target is executable,
@@ -214,7 +214,7 @@ runfiles will be added to the runfiles when coverage is enabled.
214214
215215
The entry point for the tool must be loadable by a Python interpreter (e.g. a
216216
`.py` or `.pyc` file). It must accept the command line arguments
217-
of coverage.py (https://coverage.readthedocs.io), at least including
217+
of [`coverage.py`](https://coverage.readthedocs.io), at least including
218218
the `run` and `lcov` subcommands.
219219
""",
220220
),
@@ -306,7 +306,7 @@ The template to use when two stage bootstrapping is enabled
306306
default = DEFAULT_STUB_SHEBANG,
307307
doc = """
308308
"Shebang" expression prepended to the bootstrapping Python stub script
309-
used when executing `py_binary` targets.
309+
used when executing {rule}`py_binary` targets.
310310
311311
See https://github.com/bazelbuild/bazel/issues/8685 for
312312
motivation.

python/private/python.bzl

+28-12
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def _python_impl(module_ctx):
147147
base_url = python_tools.base_url,
148148
ignore_root_user_error = ignore_root_user_error,
149149
tool_versions = python_tools.available_versions,
150-
# TODO @aignas 2024-08-08: allow to modify these values via the bzlmod extension
150+
# TODO @aignas 2024-08-08: allow modifying these values via the bzlmod extension
151151
# distutils_content = None,
152152
)
153153
global_toolchain_versions[toolchain_version] = toolchain_info
@@ -280,11 +280,16 @@ def _process_tag_classes(mod, fail = fail):
280280

281281
sha256[p] = sha
282282

283-
available_versions[tag.version] = {
283+
version = {
284+
"patch_strip": tag.patch_strip,
285+
# Use a list if there is only a single item the key is `*`,
286+
# otherwise pass the dict down to the toolchain rule.
287+
"patches": tag.patches.get("*", tag.patches) if len(tag.patches) == 1 else tag.patches,
284288
"sha256": sha256,
285289
"strip_prefix": tag.strip_prefix,
286290
"url": tag.url,
287291
}
292+
available_versions[tag.version] = version
288293

289294
register_all = False
290295
for tag in mod.tags.override:
@@ -343,12 +348,6 @@ def _get_bazel_version_specific_kwargs():
343348

344349
return kwargs
345350

346-
_rules_python_private_testing = tag_class(
347-
attrs = {
348-
"register_all_versions": attr.bool(default = False),
349-
},
350-
)
351-
352351
_toolchain = tag_class(
353352
doc = """Tag class used to register Python toolchains.
354353
Use this tag class to register one or more Python toolchains. This class
@@ -413,7 +412,11 @@ can result in spurious build failures.
413412
)
414413

415414
_override = tag_class(
416-
doc = """Tag class used to override defaults and behaviour of the module extension.""",
415+
doc = """Tag class used to override defaults and behaviour of the module extension.
416+
417+
:::{versionadded} 0.36.0
418+
:::
419+
""",
417420
attrs = {
418421
"available_python_versions": attr.string_list(
419422
mandatory = False,
@@ -426,13 +429,27 @@ _override = tag_class(
426429
),
427430

428431
# Internal attributes that are only usable from `rules_python`
429-
"register_all_versions": attr.bool(default = False, doc = "rules_python internal use only"),
432+
"register_all_versions": attr.bool(default = False, doc = "`rules_python` **internal** use only!"),
430433
},
431434
)
432435

433436
_single_version_override = tag_class(
434-
doc = """Override single python version settings.""",
437+
doc = """Override single python version settings.
438+
439+
:::{versionadded} 0.36.0
440+
:::
441+
""",
435442
attrs = {
443+
"patch_strip": attr.int(
444+
mandatory = False,
445+
doc = "Same as the --strip argument of Unix patch.",
446+
# TODO @aignas 2024-08-26: switch to 0 when 0.36.0 is released
447+
default = 1,
448+
),
449+
"patches": attr.string_list_dict(
450+
mandatory = False,
451+
doc = "A list of labels pointing to patch files to apply for this module as values with keys as values from the PLATFORMS dict. The patch files must exist in the source tree of the top level project. They are applied in the list order. If patches have a single key '*', then the patches will be applied to all available interpreters for that version.",
452+
),
436453
"sha256s": attr.string_dict(
437454
mandatory = False,
438455
doc = "The python platform to sha256 dict. The platform key must be present in the PLATFORMS dict.",
@@ -459,7 +476,6 @@ python = module_extension(
459476
implementation = _python_impl,
460477
tag_classes = {
461478
"override": _override,
462-
"rules_python_private_testing": _rules_python_private_testing,
463479
"single_version_override": _single_version_override,
464480
"toolchain": _toolchain,
465481
},

python/private/python_repositories.bzl

+35-30
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ def http_archive(**kwargs):
4747
def py_repositories():
4848
"""Runtime dependencies that users must install.
4949
50-
This function should be loaded and called in the user's WORKSPACE.
51-
With bzlmod enabled, this function is not needed since MODULE.bazel handles transitive deps.
50+
This function should be loaded and called in the user's `WORKSPACE`.
51+
52+
With `bzlmod` enabled, this function is not needed since `MODULE.bazel`
53+
handles transitive deps.
5254
"""
5355
maybe(
5456
internal_config_repo,
@@ -178,8 +180,7 @@ def _python_repository_impl(rctx):
178180
patches = rctx.attr.patches
179181
if patches:
180182
for patch in patches:
181-
# Should take the strip as an attr, but this is fine for the moment
182-
rctx.patch(patch, strip = 1)
183+
rctx.patch(patch, strip = rctx.attr.patch_strip)
183184

184185
# Write distutils.cfg to the Python installation.
185186
if "windows" in platform:
@@ -450,6 +451,7 @@ py_exec_tools_toolchain(
450451
"ignore_root_user_error": rctx.attr.ignore_root_user_error,
451452
"name": rctx.attr.name,
452453
"netrc": rctx.attr.netrc,
454+
"patch_strip": rctx.attr.patch_strip,
453455
"patches": rctx.attr.patches,
454456
"platform": platform,
455457
"python_version": python_version,
@@ -473,27 +475,11 @@ python_repository = repository_rule(
473475
doc = "Override mapping of hostnames to authorization patterns; mirrors the eponymous attribute from http_archive",
474476
),
475477
"coverage_tool": attr.string(
476-
# Mirrors the definition at
477-
# https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/python/py_runtime_rule.bzl
478478
doc = """
479-
This is a target to use for collecting code coverage information from `py_binary`
480-
and `py_test` targets.
481-
482-
If set, the target must either produce a single file or be an executable target.
483-
The path to the single file, or the executable if the target is executable,
484-
determines the entry point for the python coverage tool. The target and its
485-
runfiles will be added to the runfiles when coverage is enabled.
486-
487-
The entry point for the tool must be loadable by a Python interpreter (e.g. a
488-
`.py` or `.pyc` file). It must accept the command line arguments
489-
of coverage.py (https://coverage.readthedocs.io), at least including
490-
the `run` and `lcov` subcommands.
479+
This is a target to use for collecting code coverage information from {rule}`py_binary`
480+
and {rule}`py_test` targets.
491481
492-
The target is accepted as a string by the python_repository and evaluated within
493-
the context of the toolchain repository.
494-
495-
For more information see the official bazel docs
496-
(https://bazel.build/reference/be/python#py_runtime.coverage_tool).
482+
For more information see {attr}`py_runtime.coverage_tool`.
497483
""",
498484
),
499485
"distutils": attr.label(
@@ -515,6 +501,12 @@ For more information see the official bazel docs
515501
"netrc": attr.string(
516502
doc = ".netrc file to use for authentication; mirrors the eponymous attribute from http_archive",
517503
),
504+
"patch_strip": attr.int(
505+
doc = "Same as the --strip argument of Unix patch.",
506+
# TODO @aignas 2024-08-26: switch to 0 when 0.36.0 is released
507+
default = 1,
508+
mandatory = False,
509+
),
518510
"patches": attr.label_list(
519511
doc = "A list of patch files to apply to the unpacked interpreter",
520512
mandatory = False,
@@ -568,32 +560,40 @@ def python_register_toolchains(
568560
register_toolchains = True,
569561
register_coverage_tool = False,
570562
set_python_version_constraint = False,
571-
tool_versions = TOOL_VERSIONS,
563+
tool_versions = None,
572564
**kwargs):
573-
"""Convenience macro for users which does typical setup.
565+
"""Convenience macro for users which does typical setup in `WORKSPACE`.
574566
575567
- Create a repository for each built-in platform like "python_linux_amd64" -
576568
this repository is lazily fetched when Python is needed for that platform.
577569
- Create a repository exposing toolchains for each platform like
578570
"python_platforms".
579571
- Register a toolchain pointing at each platform.
572+
580573
Users can avoid this macro and do these steps themselves, if they want more
581574
control.
575+
576+
With `bzlmod` enabled, this function is not needed since `rules_python` is
577+
handling everything. In order to override the default behaviour from the
578+
root module one can see the docs for the {rule}`python` extension.
579+
582580
Args:
583581
name: base name for all created repos, like "python38".
584582
python_version: the Python version.
585-
distutils: see the distutils attribute in the python_repository repository rule.
586-
distutils_content: see the distutils_content attribute in the python_repository repository rule.
583+
distutils: see the {attr}`python_repository.distutils`.
584+
distutils_content: see the {attr}`python_repository.distutils_content`.
587585
register_toolchains: Whether or not to register the downloaded toolchains.
588586
register_coverage_tool: Whether or not to register the downloaded coverage tool to the toolchains.
589587
NOTE: Coverage support using the toolchain is only supported in Bazel 6 and higher.
590588
591589
set_python_version_constraint: When set to true, target_compatible_with for the toolchains will include a version constraint.
592590
tool_versions: a dict containing a mapping of version with SHASUM and platform info. If not supplied, the defaults
593591
in python/versions.bzl will be used.
594-
**kwargs: passed to each python_repositories call.
592+
**kwargs: passed to each {rule}`python_repositories` call.
595593
"""
596594

595+
tool_versions = tool_versions or TOOL_VERSIONS
596+
597597
if BZLMOD_ENABLED:
598598
# you cannot used native.register_toolchains when using bzlmod.
599599
register_toolchains = False
@@ -626,7 +626,7 @@ def python_register_toolchains(
626626
continue
627627

628628
loaded_platforms.append(platform)
629-
(release_filename, urls, strip_prefix, patches) = get_release_info(platform, python_version, base_url, tool_versions)
629+
(release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions)
630630

631631
# allow passing in a tool version
632632
coverage_tool = None
@@ -651,6 +651,7 @@ def python_register_toolchains(
651651
platform = platform,
652652
),
653653
sha256 = sha256,
654+
patches = patch_strip,
654655
patches = patches,
655656
platform = platform,
656657
python_version = python_version,
@@ -660,6 +661,10 @@ def python_register_toolchains(
660661
distutils_content = distutils_content,
661662
strip_prefix = strip_prefix,
662663
coverage_tool = coverage_tool,
664+
# Will be one of
665+
# * auth_patterns
666+
# * ignore_root_user_error
667+
# * netrc
663668
**kwargs
664669
)
665670
if register_toolchains:
@@ -713,7 +718,7 @@ def python_register_multi_toolchains(
713718
python_versions: the Python version.
714719
default_version: the default Python version. If not set, the first version in
715720
python_versions is used.
716-
**kwargs: passed to each python_register_toolchains call.
721+
**kwargs: passed to each {rule}`python_register_toolchains` call.
717722
"""
718723
if len(python_versions) == 0:
719724
fail("python_versions must not be empty")

python/repositories.bzl

-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
load(
1919
"//python/private:python_repositories.bzl",
2020
_STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER_FILENAME",
21-
_http_archive = "http_archive",
2221
_is_standalone_interpreter = "is_standalone_interpreter",
2322
_py_repositories = "py_repositories",
2423
_python_register_multi_toolchains = "python_register_multi_toolchains",
@@ -33,6 +32,5 @@ python_register_toolchains = _python_register_toolchains
3332
# These symbols are of questionable public visibility. They were probably
3433
# not intended to be actually public.
3534
STANDALONE_INTERPRETER_FILENAME = _STANDALONE_INTERPRETER_FILENAME
36-
http_archive = _http_archive
3735
is_standalone_interpreter = _is_standalone_interpreter
3836
python_repository = _python_repository

python/versions.bzl

+4-3
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ def get_release_info(platform, python_version, base_url = DEFAULT_RELEASE_BASE_U
636636
tool_versions: A dict listing the interpreter versions, their SHAs and URL
637637
638638
Returns:
639-
A tuple of (filename, url, and archive strip prefix)
639+
A tuple of (filename, url, archive strip prefix, patches, patch_strip)
640640
"""
641641

642642
url = tool_versions[python_version]["url"]
@@ -669,12 +669,13 @@ def get_release_info(platform, python_version, base_url = DEFAULT_RELEASE_BASE_U
669669

670670
patches = tool_versions[python_version].get("patches", [])
671671
if type(patches) == type({}):
672-
if platform in patches.keys():
672+
if platform in patches:
673673
patches = patches[platform]
674674
else:
675675
patches = []
676+
patch_strip = tool_versions[python_version].get("patch_strip", None)
676677

677-
return (release_filename, rendered_urls, strip_prefix, patches)
678+
return (release_filename, rendered_urls, strip_prefix, patches, patch_strip)
678679

679680
def print_toolchains_checksums(name):
680681
native.genrule(

0 commit comments

Comments
 (0)