diff --git a/e2e/cases/python-version-flag/test.sh b/e2e/cases/python-version-flag/test.sh index c69b1cead..10143db02 100755 --- a/e2e/cases/python-version-flag/test.sh +++ b/e2e/cases/python-version-flag/test.sh @@ -36,3 +36,10 @@ for version in 3.9 3.10 3.11 3.12 3.13; do "--@rules_python//python/config_settings:python_version=${version}" \ -- //python-version-flag:version_check "${version}" done + +# The native flag takes precedence over the legacy fallback when both are set. +"$BAZEL" run \ + --lockfile_mode=off \ + --@aspect_rules_py//py:python_version=3.12 \ + --@rules_python//python/config_settings:python_version=3.11 \ + -- //python-version-flag:version_check 3.12 diff --git a/py/private/transitions.bzl b/py/private/transitions.bzl index c81f1dc38..bb2fd4a04 100644 --- a/py/private/transitions.bzl +++ b/py/private/transitions.bzl @@ -19,9 +19,6 @@ def _baseline(settings, flag, current): return current return baseline -def _python_version(settings): - return settings[PYTHON_VERSION_FLAG] or settings[_RPY_VERSION_FLAG] - def _python_transition_impl(settings, attr): acc = {} acc[_PYTHON_VERSION_BASELINE_FLAG] = _baseline( @@ -36,11 +33,14 @@ def _python_transition_impl(settings, attr): ) if attr.python_version: version = str(attr.python_version) + acc[PYTHON_VERSION_FLAG] = version + acc[_RPY_VERSION_FLAG] = version else: - version = _python_version(settings) - - acc[PYTHON_VERSION_FLAG] = version - acc[_RPY_VERSION_FLAG] = version + # No explicit pin: pass the flags through unchanged rather than + # writing a resolved value, which can flip them from unset/default + # and fork a new configuration for the whole transitive closure. + acc[PYTHON_VERSION_FLAG] = settings[PYTHON_VERSION_FLAG] + acc[_RPY_VERSION_FLAG] = settings[_RPY_VERSION_FLAG] # Set the dep_group transition. The attr is only present on `py_venv` # (rules without it propagate the inherited setting; `py_venv_exec` diff --git a/py/tests/reset-data-edges/BUILD.bazel b/py/tests/reset-data-edges/BUILD.bazel index 66176b2b5..033829a0f 100644 --- a/py/tests/reset-data-edges/BUILD.bazel +++ b/py/tests/reset-data-edges/BUILD.bazel @@ -1,5 +1,5 @@ load("//py:defs.bzl", "py_binary", "py_library", "py_venv") -load(":tests.bzl", "probe", "reset_data_edges_test_suite", "root", "terminal") +load(":tests.bzl", "probe", "reset_data_edges_test_suite", "root", "seeded_root", "terminal") probe(name = "probe") @@ -51,6 +51,12 @@ terminal( tags = ["manual"], ) +terminal( + name = "unversioned_terminal", + tags = ["manual"], + deps = [":probe"], +) + py_venv( name = "second", srcs = ["main.py"], @@ -75,4 +81,12 @@ root( ], ) +seeded_root( + name = "seeded_root", + deps = [ + ":probe", + ":unversioned_terminal", + ], +) + reset_data_edges_test_suite() diff --git a/py/tests/reset-data-edges/tests.bzl b/py/tests/reset-data-edges/tests.bzl index b24ada8c8..8f7f60e95 100644 --- a/py/tests/reset-data-edges/tests.bzl +++ b/py/tests/reset-data-edges/tests.bzl @@ -4,8 +4,11 @@ load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") load("//py/private:transitions.bzl", "python_transition", "reset_python_flags_transition") _DEP_GROUP_FLAG = "@aspect_rules_py//uv/private/constraints/dep_group:dep_group" +_DEP_GROUP_BASELINE_FLAG = "@aspect_rules_py//uv/private/constraints/dep_group:baseline" _PYTHON_VERSION_FLAG = "@aspect_rules_py//py/private/interpreter:python_version" +_PYTHON_VERSION_BASELINE_FLAG = "@aspect_rules_py//py/private/interpreter:baseline_python_version" _RPY_VERSION_FLAG = "@rules_python//python/config_settings:python_version" +_RPY_VERSION_BASELINE_FLAG = "@aspect_rules_py//py/private/interpreter:baseline_rules_python_version" _ProbeInfo = provider(fields = ["file"]) _ProbeFilesInfo = provider(fields = ["files"]) @@ -96,6 +99,45 @@ root = rule( }, ) +# Give both dependency paths the same transition scratch state while preserving +# the default/unset state of the version flags. An unpinned terminal used to +# turn those version flags into explicit resolved values, creating a second +# configured target for :probe. +def _seed_baselines_transition_impl(settings, _attr): + return { + _DEP_GROUP_BASELINE_FLAG: settings[_DEP_GROUP_FLAG], + _PYTHON_VERSION_BASELINE_FLAG: settings[_PYTHON_VERSION_FLAG], + _RPY_VERSION_BASELINE_FLAG: settings[_RPY_VERSION_FLAG], + } + +_seed_baselines_transition = transition( + implementation = _seed_baselines_transition_impl, + inputs = [ + _DEP_GROUP_FLAG, + _PYTHON_VERSION_FLAG, + _RPY_VERSION_FLAG, + ], + outputs = [ + _DEP_GROUP_BASELINE_FLAG, + _PYTHON_VERSION_BASELINE_FLAG, + _RPY_VERSION_BASELINE_FLAG, + ], +) + +seeded_root = rule( + implementation = _root_impl, + attrs = { + "deps": attr.label_list( + aspects = [_probe_aspect], + allow_empty = False, + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + cfg = _seed_baselines_transition, +) + def _reset_data_edges_test_impl(ctx): env = analysistest.begin(ctx) files = analysistest.target_under_test(env)[_ProbeFilesInfo].files.to_list() @@ -114,3 +156,7 @@ def reset_data_edges_test_suite(): name = "reset_data_edges_test", target_under_test = ":root", ) + _reset_data_edges_test( + name = "unversioned_terminal_noop_transition_test", + target_under_test = ":seeded_root", + )