Skip to content

Commit 2c28e61

Browse files
authored
feat(bzlmod): Register a default toolchain (#1259)
This makes rules_python always provide a default toolchain when using bzlmod. Note that, unlike workspace builds, the default is not the local system Python (`@bazel_tools//tools/python:autodetecting_toolchain`). Instead, the default is a hermetic runtime, but no guarantees are made about the particular version used. In practice, it will be the latest available Python version. Work towards #1233
1 parent 1f58f4c commit 2c28e61

File tree

5 files changed

+75
-28
lines changed

5 files changed

+75
-28
lines changed

.github/workflows/create_archive_and_notes.sh

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,6 @@ pip.parse(
4040
)
4141
4242
use_repo(pip, "pip")
43-
44-
# (Optional) Register a specific python toolchain instead of using the host version
45-
python = use_extension("@rules_python//python:extensions.bzl", "python")
46-
47-
python.toolchain(
48-
name = "python3_9",
49-
python_version = "3.9",
50-
)
51-
52-
use_repo(python, "python3_9_toolchains")
53-
54-
register_toolchains(
55-
"@python3_9_toolchains//:all",
56-
)
5743
\`\`\`
5844
5945
## Using WORKSPACE

BZLMOD_SUPPORT.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,27 @@ This rule set does not have full feature partity with the older `WORKSPACE` type
3535
2. Gazelle does not support finding deps in sub-modules. For instance we can have a dep like ` "@our_other_module//other_module/pkg:lib",` in a `py_test` definition.
3636

3737
Check ["issues"](/bazelbuild/rules_python/issues) for an up to date list.
38+
39+
## Differences in behavior from WORKSPACE
40+
41+
### Default toolchain is not the local system Python
42+
43+
Under bzlmod, the default toolchain is no longer based on the locally installed
44+
system Python. Instead, a recent Python version using the pre-built,
45+
standalone runtimes are used.
46+
47+
If you need the local system Python to be your toolchain, then it's suggested
48+
that you setup and configure your own toolchain and register it. Note that using
49+
the local system's Python is not advised because will vary between users and
50+
platforms.
51+
52+
If you want to use the same toolchain as what WORKSPACE used, then manually
53+
register the builtin Bazel Python toolchain by doing
54+
`register_toolchains("@bazel_tools//tools/python:autodetecting_toolchain")`.
55+
**IMPORTANT: this should only be done in a root module, and may intefere with
56+
the toolchains rules_python registers**.
57+
58+
NOTE: Regardless of your toolchain, due to
59+
[#691](https://github.com/bazelbuild/rules_python/issues/691), `rules_python`
60+
still relies on a local Python being available to bootstrap the program before
61+
handing over execution to the toolchain Python.

MODULE.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ use_repo(
5151
# We need to do another use_extension call to expose the "pythons_hub"
5252
# repo.
5353
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
54+
55+
# The default toolchain to use if nobody configures a toolchain.
56+
# NOTE: This is not a stable version. It is provided for convenience, but will
57+
# change frequently to track the most recent Python version.
58+
# NOTE: The root module can override this.
59+
python.toolchain(
60+
is_default = True,
61+
python_version = "3.11",
62+
)
5463
use_repo(python, "pythons_hub")
5564

5665
# This call registers the Python toolchains.

README.md

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,31 +45,52 @@ the older way of configuring bazel with a `WORKSPACE` file.
4545

4646
### Using bzlmod
4747

48+
NOTE: bzlmod support is still experimental; APIs subject to change.
49+
4850
To import rules_python in your project, you first need to add it to your
4951
`MODULE.bazel` file, using the snippet provided in the
5052
[release you choose](https://github.com/bazelbuild/rules_python/releases).
5153

54+
Once the dependency is added, a Python toolchain will be automatically
55+
registered and you'll be able to create runnable programs and tests.
56+
57+
5258
#### Toolchain registration with bzlmod
5359

54-
To register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `MODULE.bazel` file:
60+
NOTE: bzlmod support is still experimental; APIs subject to change.
61+
62+
A default toolchain is automatically configured for by depending on
63+
`rules_python`. Note, however, the version used tracks the most recent Python
64+
release and will change often.
65+
66+
If you want to register specific Python versions, then use
67+
`python.toolchain()` for each version you need:
5568

5669
```starlark
57-
# Find the latest version number here: https://github.com/bazelbuild/rules_python/releases
58-
# and change the version number if needed in the line below.
59-
bazel_dep(name = "rules_python", version = "0.21.0")
70+
python = use_extension("@rules_python//python:extensions.bzl", "python")
71+
72+
python.toolchain(
73+
python_version = "3.9",
74+
)
75+
```
76+
77+
### Using pip with bzlmod
6078

79+
NOTE: bzlmod support is still experimental; APIs subject to change.
80+
81+
To use dependencies from PyPI, the `pip.parse()` extension is used to
82+
convert a requirements file into Bazel dependencies.
83+
84+
```starlark
6185
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
6286
python.toolchain(
63-
name = "python",
64-
configure_coverage_tool = True,
65-
is_default = True,
6687
python_version = "3.9",
6788
)
6889

6990
interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter")
7091
interpreter.install(
7192
name = "interpreter",
72-
python_name = "python",
93+
python_name = "python_3_9",
7394
)
7495
use_repo(interpreter, "interpreter")
7596

python/extensions/python.bzl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,20 @@ def _python_impl(module_ctx):
9898
module_name = mod.name,
9999
)
100100

101-
# Only the root module is allowed to set the default toolchain
102-
# to prevent submodules from clobbering each other.
103-
# A single toolchain in the root module is treated as the default
104-
# because it's unambigiuous.
101+
# Only the root module and rules_python are allowed to specify the default
102+
# toolchain for a couple reasons:
103+
# * It prevents submodules from specifying different defaults and only
104+
# one of them winning.
105+
# * rules_python needs to set a soft default in case the root module doesn't,
106+
# e.g. if the root module doesn't use Python itself.
107+
# * The root module is allowed to override the rules_python default.
105108
if mod.is_root:
109+
# A single toolchain is treated as the default because it's unambiguous.
106110
is_default = toolchain_attr.is_default or len(mod.tags.toolchain) == 1
111+
elif mod.name == "rules_python" and not default_toolchain:
112+
# We don't do the len() check because we want the default that rules_python
113+
# sets to be clearly visible.
114+
is_default = toolchain_attr.is_default
107115
else:
108116
is_default = False
109117

@@ -129,8 +137,7 @@ def _python_impl(module_ctx):
129137
# A default toolchain is required so that the non-version-specific rules
130138
# are able to match a toolchain.
131139
if default_toolchain == None:
132-
fail("No default toolchain found: exactly one toolchain must have " +
133-
"is_default=True set")
140+
fail("No default Python toolchain configured. Is rules_python missing `is_default=True`?")
134141

135142
# The last toolchain in the BUILD file is set as the default
136143
# toolchain. We need the default last.

0 commit comments

Comments
 (0)