Skip to content

Commit 6813055

Browse files
committed
feat(python.toolchain): support file-based default Python version
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.
1 parent 309ee59 commit 6813055

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

python/private/python.bzl

+24-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ def parse_modules(*, module_ctx, _fail = fail):
104104
# * rules_python needs to set a soft default in case the root module doesn't,
105105
# e.g. if the root module doesn't use Python itself.
106106
# * The root module is allowed to override the rules_python default.
107-
is_default = toolchain_attr.is_default
107+
if toolchain_attr.default_version_file == None:
108+
is_default = toolchain_attr.is_default
109+
else:
110+
is_default = (
111+
module_ctx.read(toolchain_attr.default_version_file) == toolchain_version
112+
)
113+
if toolchain_attr.is_default and not is_default:
114+
fail("The 'is_default' attribute doesn't work if you set 'default_version_file'.")
108115

109116
# Also only the root module should be able to decide ignore_root_user_error.
110117
# Modules being depended upon don't know the final environment, so they aren't
@@ -560,6 +567,7 @@ def _create_toolchain_attrs_struct(*, tag = None, python_version = None, toolcha
560567
python_version = python_version if python_version else tag.python_version,
561568
configure_coverage_tool = getattr(tag, "configure_coverage_tool", False),
562569
ignore_root_user_error = getattr(tag, "ignore_root_user_error", False),
570+
default_version_file = getattr(tag, "default_version_file", None),
563571
)
564572

565573
def _get_bazel_version_specific_kwargs():
@@ -635,6 +643,18 @@ Then the python interpreter will be available as `my_python_name`.
635643
mandatory = False,
636644
doc = "Whether or not to configure the default coverage tool provided by `rules_python` for the compatible toolchains.",
637645
),
646+
"default_version_file": attr.label(
647+
mandatory = False,
648+
allow_single_file = True,
649+
doc = """\
650+
File saying what the default Python version should be. If the contents of the
651+
file match the `python_version` attribute, this toolchain is the default version.
652+
If this attribute is set, the `is_default` attribute is ignored.
653+
654+
:::{versionadded} VERSION_NEXT_FEATURE
655+
:::
656+
""",
657+
),
638658
"ignore_root_user_error": attr.bool(
639659
default = False,
640660
doc = """\
@@ -651,7 +671,9 @@ can result in spurious build failures.
651671
),
652672
"is_default": attr.bool(
653673
mandatory = False,
654-
doc = "Whether the toolchain is the default version",
674+
doc = """\
675+
Whether the toolchain is the default version. Ignored if `default_version_file`
676+
is set.""",
655677
),
656678
"python_version": attr.string(
657679
mandatory = True,

0 commit comments

Comments
 (0)