From e2deb1c3163431194044c7ba6866724fcdeef2f2 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Fri, 19 Sep 2025 23:18:10 +0000 Subject: [PATCH 01/13] Code infrastrcuture for Starlark/native flag references. --- python/private/flags.bzl | 86 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 710402ba68..a982f03425 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -17,10 +17,90 @@ NOTE: The transitive loads of this should be kept minimal. This avoids loading unnecessary files when all that are needed are flag definitions. """ - -load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") +load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo", "string_list_flag") load(":enum.bzl", "FlagEnum", "enum") +# Migration support for moving Python flags from Bazel to rules_python: +# https://github.com/bazel-contrib/rules_python/issues/3252). +# +# Maps "--myflag" to ("starlark|native", ). +# +# "starlark" means .bzl code should resolve the Starlark definition, which we +# assume is defined as a private attribute on the reading rule called "_myflag". +# +# "native" means .bzl code should resolve the native definition. +# +# is the Starlark accessor for the native definition. +_POSSIBLY_NATIVE_FLAGS = { + "disable_py2": ("native", lambda ctx: ctx.fragments.py.disable_py2), + "incompatible_default_to_explicit_init_py": ("native", lambda ctx: ctx.fragments.py.default_to_explicit_init_py), + "build_python_zip": ("native", lambda ctx: ctx.fragments.py.build_python_zip), + "experimental_python_import_all_repositories": ("native", lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories), + +} + +# Provides command-line overrides for which flags resolve to Starlark definitions +# vs. native Bazel. Offers a workaround in case a user experiences a problem with +# the Starllark switch. +# +# Usage: +# --use_starlark_flags=* - all flags use Starlark versions +# --use_starlark_flags=flag1,flag2 - only flag1, flag2 use Starlark versions +# --use_starlark_flags=flag1,-flag2 - flag1: Starlark, flag2: native version +# +# If not specified, apply defaults defined in _POSSIBLY_NATIVE_FLAGS. +string_list_flag( + name = "use_starlark_flags", + build_setting_default = [] +) + +# mylang/flags/flags.bzl +def _command_line_setting(use_starlark_flags, flag_name): + """Returns if --flag_name should use the Starlark or native definition. + + Rule logic can set its own defaults, for when this flag isn't set. + + Args: + use_starlark_flags: Value of --//mylang:flags:use_starlark_flags + flag_name: name of the flag to check, minus "--". Example: "javacopt". + + Returns: + "starlark": use the Starlark definition + "native": use the native definition + "language default": use the rule set's default choice + """ + if not use_starlark_flags: + return "language default" # --use_starlark_flags isn't set. + elif len(use_starlark_flags) == 1 and use_starlark_flags[0] == '*': + return "starlark" # --use_starlark_flags=* means "enable all flags". + elif len(use_starlark_flags) == 1 and use_starlark_flags[0] == '-': + return "native" # --use_starlark_flags=- means "disable all flags". + elif flag_name in use_starlark_flags: + return "starlark" # --use_starlark_flags=foo means "enable --foo". + elif "-" + flag_name in use_starlark_flags: + return "native" # --use_starlark_flags=-foo means "disable --foo". + else: + return "language default" # --use_starlark_flags=otherflag1,otherflag2 + +# Interface for reading flags that may be defined in Starlark or natively in +# Bazel. Automatically gets the value from the right flag definition. +def get_possibly_native_flag_value(ctx, flag_name): + flag_source_of_truth = _command_line_setting( + getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value, + flag_name) + if flag_source_of_truth == "language default": + if flag_name in _POSSIBLY_NATIVE_FLAGS: + flag_source_of_truth = _POSSIBLY_NATIVE_FLAGS[flag_name][0] + else: + flag_source_of_truth = "native" + + # Define lang support in https://github.com/bazel-contrib/bazel_features. + if bazel_features.flags.supports_starlark_flags_migration and flag_source_of_truth == "starlark": + return getattr(ctx.attr, "_" + flag_name) + else: + return _POSSIBLY_NATIVE_FLAGS[flag_name][1](ctx) + def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value if value == AddSrcsToRunfilesFlag.AUTO: @@ -117,7 +197,7 @@ PrecompileFlag = enum( def _precompile_source_retention_flag_get_effective_value(ctx): value = ctx.attr._precompile_source_retention_flag[BuildSettingInfo].value if value == PrecompileSourceRetentionFlag.AUTO: - value = PrecompileSourceRetentionFlag.KEEP_SOURCE +.KEEP_SOURCE return value # Determines if, when a source file is compiled, if the source file is kept From 0e1af59df4f2a641d3ac37c7b2064e714ba21e7e Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Fri, 19 Sep 2025 23:36:00 +0000 Subject: [PATCH 02/13] Commit rest. b/bazeldev build //testapp:py now works. --- python/config_settings/BUILD.bazel | 24 +++++++++++++++++++++++- python/private/flags.bzl | 25 +++++-------------------- python/private/py_executable.bzl | 16 +++++++++------- python/private/py_runtime_pair_rule.bzl | 3 ++- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 82a73cee6c..6d71c5750c 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -1,4 +1,4 @@ -load("@bazel_skylib//rules:common_settings.bzl", "string_flag") +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag", "string_list_flag") load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION", "MINOR_MAPPING", "PYTHON_VERSIONS") load( "//python/private:flags.bzl", @@ -240,3 +240,25 @@ label_flag( # NOTE: Only public because it is used in pip hub repos. visibility = ["//visibility:public"], ) + +# Provides command-line overrides for which flags resolve to Starlark definitions +# vs. native Bazel. Offers a workaround in case a user experiences a problem with +# the Starllark switch. +# +# Usage: +# --use_starlark_flags=* - all flags use Starlark versions +# --use_starlark_flags=flag1,flag2 - only flag1, flag2 use Starlark versions +# --use_starlark_flags=flag1,-flag2 - flag1: Starlark, flag2: native version +# +# If not specified, apply defaults defined in _POSSIBLY_NATIVE_FLAGS. +string_list_flag( + name = "use_starlark_flags", + build_setting_default = [], + visibility = ["//visibility:public"] +) + +bool_flag( + name = "experimental_python_import_all_repositories", + build_setting_default = True, + visibility = ["//visibility:public"] +) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index a982f03425..e8ca097d25 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -34,27 +34,12 @@ load(":enum.bzl", "FlagEnum", "enum") # is the Starlark accessor for the native definition. _POSSIBLY_NATIVE_FLAGS = { "disable_py2": ("native", lambda ctx: ctx.fragments.py.disable_py2), - "incompatible_default_to_explicit_init_py": ("native", lambda ctx: ctx.fragments.py.default_to_explicit_init_py), + "default_to_explicit_init_py": ("native", lambda ctx: ctx.fragments.py.default_to_explicit_init_py), "build_python_zip": ("native", lambda ctx: ctx.fragments.py.build_python_zip), - "experimental_python_import_all_repositories": ("native", lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories), - + "python_import_all_repositories": ("native", lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories), + "python_path": ("native", lambda ctx: ctx.fragments.bazel_py.python_path), } -# Provides command-line overrides for which flags resolve to Starlark definitions -# vs. native Bazel. Offers a workaround in case a user experiences a problem with -# the Starllark switch. -# -# Usage: -# --use_starlark_flags=* - all flags use Starlark versions -# --use_starlark_flags=flag1,flag2 - only flag1, flag2 use Starlark versions -# --use_starlark_flags=flag1,-flag2 - flag1: Starlark, flag2: native version -# -# If not specified, apply defaults defined in _POSSIBLY_NATIVE_FLAGS. -string_list_flag( - name = "use_starlark_flags", - build_setting_default = [] -) - # mylang/flags/flags.bzl def _command_line_setting(use_starlark_flags, flag_name): """Returns if --flag_name should use the Starlark or native definition. @@ -85,7 +70,7 @@ def _command_line_setting(use_starlark_flags, flag_name): # Interface for reading flags that may be defined in Starlark or natively in # Bazel. Automatically gets the value from the right flag definition. -def get_possibly_native_flag_value(ctx, flag_name): +def read_possibly_native_flag(ctx, flag_name): flag_source_of_truth = _command_line_setting( getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value, flag_name) @@ -197,7 +182,7 @@ PrecompileFlag = enum( def _precompile_source_retention_flag_get_effective_value(ctx): value = ctx.attr._precompile_source_retention_flag[BuildSettingInfo].value if value == PrecompileSourceRetentionFlag.AUTO: -.KEEP_SOURCE + value = PrecompileSourceRetentionFlag.KEEP_SOURCE return value # Determines if, when a source file is compiled, if the source file is kept diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 5993a4f003..44421d6082 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -53,7 +53,7 @@ load( "target_platform_has_any_constraint", ) load(":common_labels.bzl", "labels") -load(":flags.bzl", "BootstrapImplFlag", "VenvsUseDeclareSymlinkFlag") +load(":flags.bzl", "BootstrapImplFlag", "VenvsUseDeclareSymlinkFlag", "read_possibly_native_flag") load(":precompile.bzl", "maybe_precompile") load(":py_cc_link_params_info.bzl", "PyCcLinkParamsInfo") load(":py_executable_info.bzl", "PyExecutableInfo") @@ -231,6 +231,8 @@ accepting arbitrary Python versions. executable = True, default = "@bazel_tools//tools/zip:zipper", ), + "_use_starlark_flags": attr.label( + default = "//python/config_settings:use_starlark_flags") }, ) @@ -293,7 +295,7 @@ def _get_stamp_flag(ctx): def _should_create_init_files(ctx): if ctx.attr.legacy_create_init == -1: - return not ctx.fragments.py.default_to_explicit_init_py + return not read_possibly_native_flag(ctx, "default_to_explicit_init_py") else: return bool(ctx.attr.legacy_create_init) @@ -381,7 +383,7 @@ def _create_executable( extra_files_to_build = [] # NOTE: --build_python_zip defaults to true on Windows - build_zip_enabled = ctx.fragments.py.build_python_zip + build_zip_enabled = read_possibly_native_flag(ctx, "build_python_zip") # When --build_python_zip is enabled, then the zip file becomes # one of the default outputs. @@ -587,7 +589,7 @@ def _create_venv(ctx, output_prefix, imports, runtime_details): output = site_init, substitutions = { "%coverage_tool%": _get_coverage_tool_runfiles_path(ctx, runtime), - "%import_all%": "True" if ctx.fragments.bazel_py.python_import_all_repositories else "False", + "%import_all%": "True" if read_possibly_native_flag(ctx, "python_import_all_repositories") else "False", "%site_init_runfiles_path%": "{}/{}".format(ctx.workspace_name, site_init.short_path), "%workspace_name%": ctx.workspace_name, }, @@ -668,7 +670,7 @@ def _create_stage2_bootstrap( output = output, substitutions = { "%coverage_tool%": _get_coverage_tool_runfiles_path(ctx, runtime), - "%import_all%": "True" if ctx.fragments.bazel_py.python_import_all_repositories else "False", + "%import_all%": "True" if read_possibly_native_flag(ctx, "python_import_all_repositories") else "False", "%imports%": ":".join(imports.to_list()), "%main%": main_py_path, "%main_module%": ctx.attr.main_module, @@ -755,7 +757,7 @@ def _create_stage1_bootstrap( template = ctx.file._bootstrap_template subs["%coverage_tool%"] = coverage_tool_runfiles_path - subs["%import_all%"] = ("True" if ctx.fragments.bazel_py.python_import_all_repositories else "False") + subs["%import_all%"] = ("True" if read_possibly_native_flag(ctx, "python_import_all_repositories") else "False") subs["%imports%"] = ":".join(imports.to_list()) subs["%main%"] = "{}/{}".format(ctx.workspace_name, main_py.short_path) @@ -1135,7 +1137,7 @@ def _get_runtime_details(ctx, semantics): # # TOOD(bazelbuild/bazel#7901): Remove this once --python_path flag is removed. - flag_interpreter_path = ctx.fragments.bazel_py.python_path + flag_interpreter_path = read_possibly_native_flag(ctx, "python_path") toolchain_runtime, effective_runtime = _maybe_get_runtime_from_ctx(ctx) if not effective_runtime: # Clear these just in case diff --git a/python/private/py_runtime_pair_rule.bzl b/python/private/py_runtime_pair_rule.bzl index 775d53a0b8..2d8c90dd58 100644 --- a/python/private/py_runtime_pair_rule.bzl +++ b/python/private/py_runtime_pair_rule.bzl @@ -19,6 +19,7 @@ load("//python:py_runtime_info.bzl", "PyRuntimeInfo") load(":common_labels.bzl", "labels") load(":reexports.bzl", "BuiltinPyRuntimeInfo") load(":util.bzl", "IS_BAZEL_7_OR_HIGHER") +load(":flags.bzl", "read_possibly_native_flag") def _py_runtime_pair_impl(ctx): if ctx.attr.py2_runtime != None: @@ -69,7 +70,7 @@ def _is_py2_disabled(ctx): # TODO: Remove this once all supported Balze versions have this flag. if not hasattr(ctx.fragments.py, "disable_py"): return False - return ctx.fragments.py.disable_py2 + return read_possibly_native_flag(ctx, "disable_py2") _MaybeBuiltinPyRuntimeInfo = [[BuiltinPyRuntimeInfo]] if BuiltinPyRuntimeInfo != None else [] From b7a977002ec358dbc68a2703883e21c2c6a1846d Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Fri, 19 Sep 2025 23:47:45 +0000 Subject: [PATCH 03/13] Add bazel_features bzl_library dependency. --- python/private/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index 0c8ccdea99..2bbae88838 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -186,6 +186,7 @@ bzl_library( deps = [ ":enum_bzl", "@bazel_skylib//rules:common_settings", + "@bazel_features//:features", ], ) From a07ee140de9bea86cc9f8bdb6e1347f5ffe4d872 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 21:22:34 +0000 Subject: [PATCH 04/13] Simplify logic. --- python/config_settings/BUILD.bazel | 18 +------ python/private/BUILD.bazel | 1 - python/private/flags.bzl | 79 ++++++++---------------------- python/private/py_executable.bzl | 2 - 4 files changed, 22 insertions(+), 78 deletions(-) diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 6d71c5750c..56a41a41c2 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -1,4 +1,4 @@ -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag", "string_list_flag") +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag") load("@pythons_hub//:versions.bzl", "DEFAULT_PYTHON_VERSION", "MINOR_MAPPING", "PYTHON_VERSIONS") load( "//python/private:flags.bzl", @@ -241,22 +241,6 @@ label_flag( visibility = ["//visibility:public"], ) -# Provides command-line overrides for which flags resolve to Starlark definitions -# vs. native Bazel. Offers a workaround in case a user experiences a problem with -# the Starllark switch. -# -# Usage: -# --use_starlark_flags=* - all flags use Starlark versions -# --use_starlark_flags=flag1,flag2 - only flag1, flag2 use Starlark versions -# --use_starlark_flags=flag1,-flag2 - flag1: Starlark, flag2: native version -# -# If not specified, apply defaults defined in _POSSIBLY_NATIVE_FLAGS. -string_list_flag( - name = "use_starlark_flags", - build_setting_default = [], - visibility = ["//visibility:public"] -) - bool_flag( name = "experimental_python_import_all_repositories", build_setting_default = True, diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index 2bbae88838..0c8ccdea99 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -186,7 +186,6 @@ bzl_library( deps = [ ":enum_bzl", "@bazel_skylib//rules:common_settings", - "@bazel_features//:features", ], ) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index e8ca097d25..04b1fafcd6 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -17,74 +17,37 @@ NOTE: The transitive loads of this should be kept minimal. This avoids loading unnecessary files when all that are needed are flag definitions. """ -load("@bazel_features//:features.bzl", "bazel_features") -load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo", "string_list_flag") +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load(":enum.bzl", "FlagEnum", "enum") -# Migration support for moving Python flags from Bazel to rules_python: -# https://github.com/bazel-contrib/rules_python/issues/3252). +# Maps "--" to the ctx.fragments API that provides its value. # -# Maps "--myflag" to ("starlark|native", ). +# Builds that set --incompatible_remove_ctx_py_fragment or +# --incompatible_remove_ctx_bazel_py_fragment assume Python flags are defined +# in Starlark, so the ctx.framgent calls no longer resolve. # -# "starlark" means .bzl code should resolve the Starlark definition, which we -# assume is defined as a private attribute on the reading rule called "_myflag". +# This map lets callers determine if ctx.fragments.py and ctx.fragments.bazel_py +# are available before trying to read them. # -# "native" means .bzl code should resolve the native definition. -# -# is the Starlark accessor for the native definition. -_POSSIBLY_NATIVE_FLAGS = { - "disable_py2": ("native", lambda ctx: ctx.fragments.py.disable_py2), - "default_to_explicit_init_py": ("native", lambda ctx: ctx.fragments.py.default_to_explicit_init_py), - "build_python_zip": ("native", lambda ctx: ctx.fragments.py.build_python_zip), - "python_import_all_repositories": ("native", lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories), - "python_path": ("native", lambda ctx: ctx.fragments.bazel_py.python_path), +# See https://github.com/bazel-contrib/rules_python/issues/3252). +_NATIVE_FLAG_REFERENCES = { + "disable_py2": lambda ctx: ctx.fragments.py.disable_py2, + "default_to_explicit_init_py": lambda ctx: ctx.fragments.py.default_to_explicit_init_py, + "build_python_zip": lambda ctx: ctx.fragments.py.build_python_zip, + "python_import_all_repositories": lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, + "python_path": lambda ctx: ctx.fragments.bazel_py.python_path, } -# mylang/flags/flags.bzl -def _command_line_setting(use_starlark_flags, flag_name): - """Returns if --flag_name should use the Starlark or native definition. - - Rule logic can set its own defaults, for when this flag isn't set. - - Args: - use_starlark_flags: Value of --//mylang:flags:use_starlark_flags - flag_name: name of the flag to check, minus "--". Example: "javacopt". - - Returns: - "starlark": use the Starlark definition - "native": use the native definition - "language default": use the rule set's default choice - """ - if not use_starlark_flags: - return "language default" # --use_starlark_flags isn't set. - elif len(use_starlark_flags) == 1 and use_starlark_flags[0] == '*': - return "starlark" # --use_starlark_flags=* means "enable all flags". - elif len(use_starlark_flags) == 1 and use_starlark_flags[0] == '-': - return "native" # --use_starlark_flags=- means "disable all flags". - elif flag_name in use_starlark_flags: - return "starlark" # --use_starlark_flags=foo means "enable --foo". - elif "-" + flag_name in use_starlark_flags: - return "native" # --use_starlark_flags=-foo means "disable --foo". - else: - return "language default" # --use_starlark_flags=otherflag1,otherflag2 - # Interface for reading flags that may be defined in Starlark or natively in -# Bazel. Automatically gets the value from the right flag definition. +# Bazel. Automatically gets the value from the right source. def read_possibly_native_flag(ctx, flag_name): - flag_source_of_truth = _command_line_setting( - getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value, - flag_name) - if flag_source_of_truth == "language default": - if flag_name in _POSSIBLY_NATIVE_FLAGS: - flag_source_of_truth = _POSSIBLY_NATIVE_FLAGS[flag_name][0] - else: - flag_source_of_truth = "native" - - # Define lang support in https://github.com/bazel-contrib/bazel_features. - if bazel_features.flags.supports_starlark_flags_migration and flag_source_of_truth == "starlark": - return getattr(ctx.attr, "_" + flag_name) + # Bazel 9.0+ can disable these fragments with --incompatible_remove_ctx_py_fragment and + # --incompatible_remove_ctx_bazel_py_fragment. + if hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py"): + return _NATIVE_FLAG_REFERENCES[flag_name](ctx) else: - return _POSSIBLY_NATIVE_FLAGS[flag_name][1](ctx) + # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". + return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 44421d6082..dd0a1a1d6e 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -231,8 +231,6 @@ accepting arbitrary Python versions. executable = True, default = "@bazel_tools//tools/zip:zipper", ), - "_use_starlark_flags": attr.label( - default = "//python/config_settings:use_starlark_flags") }, ) From b6787cf4ac4d5541bc47dfcf16dc2f1875208e31 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 21:23:37 +0000 Subject: [PATCH 05/13] Whitespace cleanup. --- python/private/flags.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 04b1fafcd6..92e3545719 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -17,6 +17,7 @@ NOTE: The transitive loads of this should be kept minimal. This avoids loading unnecessary files when all that are needed are flag definitions. """ + load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load(":enum.bzl", "FlagEnum", "enum") From 2a43ced55f5d55a7b150a90c26a1afd2862a03a5 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 21:56:32 +0000 Subject: [PATCH 06/13] Allow dev overrides. --- python/private/flags.bzl | 53 ++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 92e3545719..db5e646283 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -21,34 +21,49 @@ unnecessary files when all that are needed are flag definitions. load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load(":enum.bzl", "FlagEnum", "enum") -# Maps "--" to the ctx.fragments API that provides its value. +# Maps "--myflag" to a tuple of: +# +# - the flag's ctx.fragments native API accessor +# -"native|starlark": which definition to use if the flag is available both +# from ctx.fragments and Starlark # # Builds that set --incompatible_remove_ctx_py_fragment or -# --incompatible_remove_ctx_bazel_py_fragment assume Python flags are defined -# in Starlark, so the ctx.framgent calls no longer resolve. +# --incompatible_remove_ctx_bazel_py_fragment disable ctx.fragments. These +# builds assume flags are solely defined in Starlark. # -# This map lets callers determine if ctx.fragments.py and ctx.fragments.bazel_py -# are available before trying to read them. +# The "native|starlark" override is only for devs who are testing flag +# Starlarkification. If ctx.fragments.[py|bazel_py] is available and +# a flag is set to "starlark", we exclusively read its starlark version. # -# See https://github.com/bazel-contrib/rules_python/issues/3252). -_NATIVE_FLAG_REFERENCES = { - "disable_py2": lambda ctx: ctx.fragments.py.disable_py2, - "default_to_explicit_init_py": lambda ctx: ctx.fragments.py.default_to_explicit_init_py, - "build_python_zip": lambda ctx: ctx.fragments.py.build_python_zip, - "python_import_all_repositories": lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, - "python_path": lambda ctx: ctx.fragments.bazel_py.python_path, +# See https://github.com/bazel-contrib/rules_python/issues/3252. +_POSSIBLY_NATIVE_FLAGS = { + "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native") + "default_to_explicit_init_py": (lambda ctx: + ctx.fragments.py.default_to_explicit_init_py, "native"), + "build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"), + "python_import_all_repositories": (lambda ctx: + ctx.fragments.bazel_py.python_import_all_repositories, "native"), + "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), } -# Interface for reading flags that may be defined in Starlark or natively in -# Bazel. Automatically gets the value from the right source. +# API for reading flags that might be defined in Starlark or in Bazel. All code +# that reads Python flags should read them through this function. +# +# This properly routes to the right flag source depending on Bazel version and +# the --incompatible* flags that disable native flag references. def read_possibly_native_flag(ctx, flag_name): # Bazel 9.0+ can disable these fragments with --incompatible_remove_ctx_py_fragment and - # --incompatible_remove_ctx_bazel_py_fragment. - if hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py"): - return _NATIVE_FLAG_REFERENCES[flag_name](ctx) + # --incompatible_remove_ctx_bazel_py_fragment. Disabling them means bazel expects + # Python to read Starlark flags. + use_native_def = hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py") + # Developer override to force the Starlark definition for testing. + if _POSSIBLY_NATIVE_FLAGSflag_name][1] == "starlark": + use_native_def = False + if use_native_def: + return _NATIVE_FLAG_REFERENCES[flag_name][0](ctx) else: - # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". - return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value + # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". + return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value From 9e1f045c9ff25bd1c06da9529e0b1c17628b7798 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 22:00:46 +0000 Subject: [PATCH 07/13] Syntax, indending fixes. --- python/private/flags.bzl | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index db5e646283..6f2b44b133 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -37,13 +37,13 @@ load(":enum.bzl", "FlagEnum", "enum") # # See https://github.com/bazel-contrib/rules_python/issues/3252. _POSSIBLY_NATIVE_FLAGS = { - "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native") - "default_to_explicit_init_py": (lambda ctx: - ctx.fragments.py.default_to_explicit_init_py, "native"), - "build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"), - "python_import_all_repositories": (lambda ctx: - ctx.fragments.bazel_py.python_import_all_repositories, "native"), - "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), + "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"), + "default_to_explicit_init_py": (lambda ctx: + ctx.fragments.py.default_to_explicit_init_py, "native"), + "build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"), + "python_import_all_repositories": (lambda ctx: + ctx.fragments.bazel_py.python_import_all_repositories, "native"), + "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), } # API for reading flags that might be defined in Starlark or in Bazel. All code @@ -52,18 +52,18 @@ _POSSIBLY_NATIVE_FLAGS = { # This properly routes to the right flag source depending on Bazel version and # the --incompatible* flags that disable native flag references. def read_possibly_native_flag(ctx, flag_name): - # Bazel 9.0+ can disable these fragments with --incompatible_remove_ctx_py_fragment and - # --incompatible_remove_ctx_bazel_py_fragment. Disabling them means bazel expects - # Python to read Starlark flags. - use_native_def = hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py") - # Developer override to force the Starlark definition for testing. - if _POSSIBLY_NATIVE_FLAGSflag_name][1] == "starlark": - use_native_def = False - if use_native_def: - return _NATIVE_FLAG_REFERENCES[flag_name][0](ctx) - else: - # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". - return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value + # Bazel 9.0+ can disable these fragments with --incompatible_remove_ctx_py_fragment and + # --incompatible_remove_ctx_bazel_py_fragment. Disabling them means bazel expects + # Python to read Starlark flags. + use_native_def = hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py") + # Developer override to force the Starlark definition for testing. + if _POSSIBLY_NATIVE_FLAGS[flag_name][1] == "starlark": + use_native_def = False + if use_native_def: + return _POSSIBLY_NATIVE_FLAGS[flag_name][0](ctx) + else: + # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". + return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value From 9593d6061e89af023929e03eb45dff2e959981f9 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 22:29:47 +0000 Subject: [PATCH 08/13] Fixes to get "bazelisk test //..." working. --- python/private/flags.bzl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 6f2b44b133..861fd8eec0 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -44,6 +44,7 @@ _POSSIBLY_NATIVE_FLAGS = { "python_import_all_repositories": (lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, "native"), "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), + "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native") } # API for reading flags that might be defined in Starlark or in Bazel. All code @@ -63,7 +64,7 @@ def read_possibly_native_flag(ctx, flag_name): return _POSSIBLY_NATIVE_FLAGS[flag_name][0](ctx) else: # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". - return getattr(ctx.attr, "_use_starlark_flags")[BuildSettingInfo].value + return getattr(ctx.attr, "_" + flag_name)[BuildSettingInfo].value def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value From 02ae2c2ff1bc17c03d23d8ef241c5bd7067f913b Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 22:43:46 +0000 Subject: [PATCH 09/13] Buildifier fixes. --- python/private/flags.bzl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 861fd8eec0..819c4d2865 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -38,13 +38,11 @@ load(":enum.bzl", "FlagEnum", "enum") # See https://github.com/bazel-contrib/rules_python/issues/3252. _POSSIBLY_NATIVE_FLAGS = { "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"), - "default_to_explicit_init_py": (lambda ctx: - ctx.fragments.py.default_to_explicit_init_py, "native"), + "default_to_explicit_init_py": (lambda ctx: ctx.fragments.py.default_to_explicit_init_py, "native"), "build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"), - "python_import_all_repositories": (lambda ctx: - ctx.fragments.bazel_py.python_import_all_repositories, "native"), + "python_import_all_repositories": (lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, "native"), "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), - "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native") + "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native"), } # API for reading flags that might be defined in Starlark or in Bazel. All code @@ -57,6 +55,7 @@ def read_possibly_native_flag(ctx, flag_name): # --incompatible_remove_ctx_bazel_py_fragment. Disabling them means bazel expects # Python to read Starlark flags. use_native_def = hasattr(ctx.fragments, "py") and hasattr(ctx.fragments, "bazel_py") + # Developer override to force the Starlark definition for testing. if _POSSIBLY_NATIVE_FLAGS[flag_name][1] == "starlark": use_native_def = False @@ -64,7 +63,7 @@ def read_possibly_native_flag(ctx, flag_name): return _POSSIBLY_NATIVE_FLAGS[flag_name][0](ctx) else: # Starlark definition of "--foo" is assumed to be a label dependency named "_foo". - return getattr(ctx.attr, "_" + flag_name)[BuildSettingInfo].value + return getattr(ctx.attr, "_" + flag_name)[BuildSettingInfo].value def _AddSrcsToRunfilesFlag_is_enabled(ctx): value = ctx.attr._add_srcs_to_runfiles_flag[BuildSettingInfo].value From 0d1809cafc0a860f922f58c8c80fecc02c937c16 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 22:52:33 +0000 Subject: [PATCH 10/13] More buildifier fixes. --- python/private/flags.bzl | 20 +++++++++++++++----- python/private/py_runtime_pair_rule.bzl | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 819c4d2865..15413bcf1a 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -45,12 +45,22 @@ _POSSIBLY_NATIVE_FLAGS = { "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native"), } -# API for reading flags that might be defined in Starlark or in Bazel. All code -# that reads Python flags should read them through this function. -# -# This properly routes to the right flag source depending on Bazel version and -# the --incompatible* flags that disable native flag references. def read_possibly_native_flag(ctx, flag_name): + """ + Canonical API for reading a Python build flag. + + Flags might be defined in Starlark or native-Bazel. This function reasd flags + from tbe correct source based on supporting Bazel version and --incompatible* + flags that disable native references. + + Args: + ctx: Rule's configuration context. + flag_name: Name of the flag to read, without preceding "--". + + Returns: + The flag's value. + """ + # Bazel 9.0+ can disable these fragments with --incompatible_remove_ctx_py_fragment and # --incompatible_remove_ctx_bazel_py_fragment. Disabling them means bazel expects # Python to read Starlark flags. diff --git a/python/private/py_runtime_pair_rule.bzl b/python/private/py_runtime_pair_rule.bzl index 2d8c90dd58..61cbdcd6f4 100644 --- a/python/private/py_runtime_pair_rule.bzl +++ b/python/private/py_runtime_pair_rule.bzl @@ -17,9 +17,9 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load("//python:py_runtime_info.bzl", "PyRuntimeInfo") load(":common_labels.bzl", "labels") +load(":flags.bzl", "read_possibly_native_flag") load(":reexports.bzl", "BuiltinPyRuntimeInfo") load(":util.bzl", "IS_BAZEL_7_OR_HIGHER") -load(":flags.bzl", "read_possibly_native_flag") def _py_runtime_pair_impl(ctx): if ctx.attr.py2_runtime != None: From 4288fd6bac4ebbb8a6110ae52a258812cb065932 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 22:55:48 +0000 Subject: [PATCH 11/13] More buildifier --- python/private/flags.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 15413bcf1a..94a9e46801 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -37,9 +37,9 @@ load(":enum.bzl", "FlagEnum", "enum") # # See https://github.com/bazel-contrib/rules_python/issues/3252. _POSSIBLY_NATIVE_FLAGS = { - "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"), - "default_to_explicit_init_py": (lambda ctx: ctx.fragments.py.default_to_explicit_init_py, "native"), "build_python_zip": (lambda ctx: ctx.fragments.py.build_python_zip, "native"), + "default_to_explicit_init_py": (lambda ctx: ctx.fragments.py.default_to_explicit_init_py, "native"), + "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"), "python_import_all_repositories": (lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, "native"), "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native"), From 300adfd3e8a18aad122ed5841504a4e0899efe70 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 23:16:02 +0000 Subject: [PATCH 12/13] Remove oudated --use_toolchains ref. --- python/private/flags.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/python/private/flags.bzl b/python/private/flags.bzl index 94a9e46801..82ec83294b 100644 --- a/python/private/flags.bzl +++ b/python/private/flags.bzl @@ -42,7 +42,6 @@ _POSSIBLY_NATIVE_FLAGS = { "disable_py2": (lambda ctx: ctx.fragments.py.disable_py2, "native"), "python_import_all_repositories": (lambda ctx: ctx.fragments.bazel_py.python_import_all_repositories, "native"), "python_path": (lambda ctx: ctx.fragments.bazel_py.python_path, "native"), - "use_toolchains": (lambda ctx: ctx.fragments.py.use_toolchains, "native"), } def read_possibly_native_flag(ctx, flag_name): From a7fc9544868cf9898cb3b004a32a49e7ae56a658 Mon Sep 17 00:00:00 2001 From: Greg Estren Date: Mon, 22 Sep 2025 23:19:26 +0000 Subject: [PATCH 13/13] Buildifier comma --- python/config_settings/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index 56a41a41c2..cc5c472fe7 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -244,5 +244,5 @@ label_flag( bool_flag( name = "experimental_python_import_all_repositories", build_setting_default = True, - visibility = ["//visibility:public"] + visibility = ["//visibility:public"], )