feat(python.toolchain): support file-based default Python version by vonschultz · Pull Request #2588 · bazel-contrib/rules_python
This change adds a new `default_version_file` attribute to `python.toolchain`. If set, the toolchain compares the file's contents to its `python_version`, and if they match, treats that toolchain as default (ignoring `is_default`). This allows Bazel to synchronize the default Python version with external tools (e.g., pyenv) that use a `.python-version` file or environment variables. Fixes bazel-contrib#2587.
As an alternative to python.toolchain.is_default, introduce a python.defaults tag class with attributes python_version, python_version_env and python_version_file. This allows to read the default python version from your projects .python-version files, similar to other tools. It also allows using an environment variable, with a fallback if the environment variable is not set.
Label("@@//:.python-version") resolves to the .python-version file of
the root module, if such a file exists.
Implement python.defaults.python_version_env in terms of module_ctx.getenv, which was introduced in Bazel 7.1. This means that Bazel 7.0 users who wish to use the new python_version_env will have to upgrade to Bazel 7.1 or later.
If we read a python_version_file (specified with the defaults tag class or the default @@//:.python-version file), explicitly start watching that file. There are some circumstances where such a watch wouldn't be allowed, but since it's new functionality it doesn't break anything for anyone to insist on the watch. If a specific use case requires the relaxation of the requirement, that can always be considered later.
The idea to read .python-version in the root module was problematic for two reasons. For one thing, if there is a .python-version file in the root module, but no BUILD or BUILD.bazel file on the top level, we produce an error that we can't catch. This would be a breaking change, requiring users to add a BUILD.bazel file. Also, if the user has a .python-version file, and also sets is_default on a toolchain, we would fail the build (or, if we didn't, we'd change the default Python version against the users explicit instructions). That would also be a breaking change. Removing the @@//:.python-version logic means the user needs to opt in by saying python_version_file="@@//.python-version". That's not necessarily a bad thing, as being explicit allows anyone to grep the repo for the label and find out what cares about that file (as pointed out by @fmeum on Slack; good point).
vonschultz added a commit to vonschultz/rules_python that referenced this pull request
May 22, 2025When there are multiple Python toolchains, there are currently two ways of setting the default version: the is_default attribute of python.toolchain() tag class and the python.defaults() tag class. The latter is more powerful, since it also supports files and environment variables. This patch updates the examples, docs and the MODULE.bazel file to use python.defaults(). Relates to pull request bazel-contrib#2588 and issue bazel-contrib#2587.
github-merge-queue bot pushed a commit that referenced this pull request
May 23, 2025When there are multiple Python toolchains, there are currently two ways of setting the default version: the `is_default` attribute of the `python.toolchain()` tag class and the `python.defaults()` tag class. The latter is more powerful, since it also supports files and environment variables. This patch updates the examples and the docs to use `python.defaults()`. Relates to pull request #2588 and issue #2587.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters