fix(toolchains): use target Python version for exec tools on Bazel 10 (#4335) Bazel 10 enables `--incompatible_exclude_starlark_flags_from_exec_config` by default (bazelbuild/bazel#26909), which resets Starlark flags to their defaults in the exec configuration unless they set `scope = "universal"`. The `//python/config_settings:python_version` flag had no scope, so exec tools, such as the precompiler, ran with the default Python version instead of the target's, e.g. compiling pyc files for the wrong Python version. To fix, give the `python_version` flag universal scope so its value reaches the exec configuration again, as it did before Bazel 10. The flag target sets the scope explicitly because Bazel ignores rule-level scope defaults for flags set on the command line (bazelbuild/bazel#31806). Along the way, run the bazel-in-bazel integration tests with Bazel 10.0.0rc2, accept Bazel 10's reworded "no matching toolchains" error in an integration test, and disable `--incompatible_no_implicit_file_export` in the gazelle dev workspace because the pinned rules_go version isn't compatible with it. Fixes #3566 Fixes #3613 Work towards #3581
diff --git a/MODULE.bazel b/MODULE.bazel index 8e7e9b6..a03eb49 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -433,12 +433,14 @@ bazel_binaries.download(version = "7.7.0") bazel_binaries.download(version = "8.5.1") bazel_binaries.download(version = "9.1.0") +bazel_binaries.download(version = "10.0.0rc2") use_repo( bazel_binaries, "bazel_binaries", # These don't appear necessary, but are reported as direct dependencies # that should be use_repo()'d, so we add them as requested "bazel_binaries_bazelisk", + "build_bazel_bazel_10_0_0rc2", "build_bazel_bazel_7_7_0", "build_bazel_bazel_8_5_1", "build_bazel_bazel_9_1_0",
diff --git a/gazelle/.bazelrc b/gazelle/.bazelrc index e302168..c098d0c 100644 --- a/gazelle/.bazelrc +++ b/gazelle/.bazelrc
@@ -19,4 +19,11 @@ # Windows makes use of runfiles for some rules build --enable_runfiles +# Bazel 10 enables --incompatible_no_implicit_file_export by default, which +# breaks @io_bazel_rules_go//go/private:context: its bzl_library depends on +# @bazel_tools//tools/cpp:toolchain_utils.bzl, which bazel_tools doesn't +# export. rules_go v0.61.0+ drops that dep; remove this once rules_go is +# upgraded. +common --noincompatible_no_implicit_file_export + common:bazel7.x --incompatible_python_disallow_native_rules
diff --git a/news/3566.fixed.md b/news/3566.fixed.md new file mode 100644 index 0000000..301765b --- /dev/null +++ b/news/3566.fixed.md
@@ -0,0 +1,3 @@ +(toolchains) Fixed build tools, such as the precompiler, running with the +default Python version instead of the target's Python version under Bazel 10 +([#3566](https://github.com/bazel-contrib/rules_python/issues/3566)).
diff --git a/python/private/config_settings.bzl b/python/private/config_settings.bzl index e4f2cac..8711f20 100644 --- a/python/private/config_settings.bzl +++ b/python/private/config_settings.bzl
@@ -60,6 +60,14 @@ _python_version_flag( name = _PYTHON_VERSION_FLAG.name, build_setting_default = default_version, + # Propagate the flag into exec configurations so exec tools (e.g. the + # precompiler) use the target's Python version. Bazel 10 resets + # Starlark flags in exec configurations unless they have universal + # scope (https://github.com/bazelbuild/bazel/issues/26909). It's set + # here, not as an attr default, because Bazel ignores scope attr + # defaults for flags set on the command line + # (https://github.com/bazelbuild/bazel/issues/31806). + scope = "universal", visibility = ["//visibility:public"], ) @@ -206,7 +214,12 @@ _python_version_flag = rule( implementation = _python_version_flag_impl, build_setting = config.string(flag = True), - attrs = {}, + attrs = { + # Read by Bazel, not the implementation, to decide whether the flag + # propagates into exec configurations. No default because Bazel only + # honors an explicitly set value; see construct_config_settings. + "scope": attr.string(), + }, ) def _python_version_major_minor_flag_impl(ctx):
diff --git a/tests/integration/toolchain_target_settings_test.py b/tests/integration/toolchain_target_settings_test.py index a0c9d42..4be7d54 100644 --- a/tests/integration/toolchain_target_settings_test.py +++ b/tests/integration/toolchain_target_settings_test.py
@@ -29,9 +29,10 @@ """ result = self.run_bazel("build", "//:custom_no_toolchain_test", check=False) self.assertNotEqual(result.exit_code, 0, "Expected build to fail") + # Bazel 10 reworded "found for types" to "found for target platform". self.assert_result_matches( result, - r"No matching toolchains found for types", + r"No matching toolchains found for (types|target platform)", )