Skip to content

Commit

Permalink
feat(bzlmod): Register a default toolchain
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rickeylev committed Jun 8, 2023
1 parent b228f60 commit 0a62a01
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 28 deletions.
14 changes: 0 additions & 14 deletions .github/workflows/create_archive_and_notes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,6 @@ pip.parse(
)
use_repo(pip, "pip")
# (Optional) Register a specific python toolchain instead of using the host version
python = use_extension("@rules_python//python:extensions.bzl", "python")
python.toolchain(
name = "python3_9",
python_version = "3.9",
)
use_repo(python, "python3_9_toolchains")
register_toolchains(
"@python3_9_toolchains//:all",
)
\`\`\`
## Using WORKSPACE
Expand Down
9 changes: 9 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ use_repo(
# We need to do another use_extension call to expose the "pythons_hub"
# repo.
python = use_extension("@rules_python//python/extensions:python.bzl", "python")

# The default toolchain to use if nobody configures a toolchain.
# NOTE: This is not a stable version. It is provided for convenience, but will
# change frequently to track the most recent Python version.
# NOTE: The root module can override this.
python.toolchain(
is_default = True,
python_version = "3.11",
)
use_repo(python, "pythons_hub")

# This call registers the Python toolchains.
Expand Down
37 changes: 29 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,31 +45,52 @@ the older way of configuring bazel with a `WORKSPACE` file.

### Using bzlmod

NOTE: bzlmod support is still experimental; APIs subject to change.

To import rules_python in your project, you first need to add it to your
`MODULE.bazel` file, using the snippet provided in the
[release you choose](https://github.com/bazelbuild/rules_python/releases).

Once the dependency is added, a Python toolchain will be automatically
registered and you'll be able to create runnable programs and tests.


#### Toolchain registration with bzlmod

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:
NOTE: bzlmod support is still experimental; APIs subject to change.

A default toolchain is automatically configured for by depending on
`rules_python`. Note, however, the version used tracks the most recent Python
release and will change often.

If you want to register specific Python versions, then use
`python.toolchain()` for each version you need:

```starlark
# Find the latest version number here: https://github.com/bazelbuild/rules_python/releases
# and change the version number if needed in the line below.
bazel_dep(name = "rules_python", version = "0.21.0")
python = use_extension("@rules_python//python:extensions.bzl", "python")

python.toolchain(
python_version = "3.9",
)
```

### Using pip with bzlmod

NOTE: bzlmod support is still experimental; APIs subject to change.

To use dependencies from PyPi, the `pip.parse()` extension is used to
convert a requirements file into Bazel dependencies.

```starlark
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
name = "python",
configure_coverage_tool = True,
is_default = True,
python_version = "3.9",
)

interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter")
interpreter.install(
name = "interpreter",
python_name = "python",
python_name = "python_3_9",
)
use_repo(interpreter, "interpreter")

Expand Down
19 changes: 13 additions & 6 deletions python/extensions/python.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,20 @@ def _python_impl(module_ctx):
module_name = mod.name,
)

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

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

# The last toolchain in the BUILD file is set as the default
# toolchain. We need the default last.
Expand Down

0 comments on commit 0a62a01

Please sign in to comment.