From ebcb6135f41483e61c40dbefdf768816e09d97d0 Mon Sep 17 00:00:00 2001 From: Alex Faxa Date: Tue, 24 Feb 2026 16:59:39 +0000 Subject: [PATCH 1/4] Fix manual runfiles path construction --- python/private/py_executable.bzl | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/python/private/py_executable.bzl b/python/private/py_executable.bzl index 284aea6bff..495c7dddcf 100644 --- a/python/private/py_executable.bzl +++ b/python/private/py_executable.bzl @@ -510,10 +510,7 @@ def _create_zip_main(ctx, *, stage2_bootstrap, runtime_details, venv): substitutions = { "%python_binary%": python_binary, "%python_binary_actual%": python_binary_actual, - "%stage2_bootstrap%": "{}/{}".format( - ctx.workspace_name, - stage2_bootstrap.short_path, - ), + "%stage2_bootstrap%": runfiles_root_path(ctx, stage2_bootstrap.short_path), "%workspace_name%": ctx.workspace_name, }, ) @@ -616,7 +613,7 @@ def _create_venv(ctx, output_prefix, imports, runtime_details, add_runfiles_root "%add_runfiles_root_to_sys_path%": add_runfiles_root_to_sys_path, "%coverage_tool%": _get_coverage_tool_runfiles_path(ctx, runtime), "%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), + "%site_init_runfiles_path%": runfiles_root_path(ctx, site_init.short_path), "%workspace_name%": ctx.workspace_name, }, computed_substitutions = computed_subs, @@ -671,10 +668,7 @@ def _get_coverage_tool_runfiles_path(ctx, runtime): if (ctx.configuration.coverage_enabled and runtime and runtime.coverage_tool): - return "{}/{}".format( - ctx.workspace_name, - runtime.coverage_tool.short_path, - ) + return runfiles_root_path(ctx, runtime.coverage_tool.short_path) else: return "" @@ -777,10 +771,7 @@ def _create_stage1_bootstrap( if (ctx.configuration.coverage_enabled and runtime and runtime.coverage_tool): - coverage_tool_runfiles_path = "{}/{}".format( - ctx.workspace_name, - runtime.coverage_tool.short_path, - ) + coverage_tool_runfiles_path = runfiles_root_path(ctx, runtime.coverage_tool.short_path) else: coverage_tool_runfiles_path = "" if runtime: @@ -793,7 +784,7 @@ def _create_stage1_bootstrap( subs["%coverage_tool%"] = coverage_tool_runfiles_path 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) + subs["%main%"] = runfiles_root_path(ctx, main_py.short_path) ctx.actions.expand_template( template = template, From a19f4d1a1753e01a3dc0a667205b996da3219966 Mon Sep 17 00:00:00 2001 From: Alex Faxa Date: Tue, 24 Feb 2026 17:06:22 +0000 Subject: [PATCH 2/4] Add entry to CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d908992c9c..4843e373a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,9 @@ Other changes: configuration. See the {any}`RULES_PYTHON_PYCACHE_DIR` environment variable for more information. ([#3643](https://github.com/bazel-contrib/rules_python/issues/3643)). +* (bootstrap) Fixed incorrect runfiles path construction in bootstrap + scripts when binary is defined in another bazel module + ([#3563](https://github.com/bazel-contrib/rules_python/issues/3563)). {#v0-0-0-added} ### Added From e182831562243eeaa75fbf01cafd0e553bbe70ad Mon Sep 17 00:00:00 2001 From: Alex Faxa Date: Tue, 10 Mar 2026 18:29:45 +0000 Subject: [PATCH 3/4] Add test --- .../other_module/other_module/pkg/BUILD.bazel | 10 +++++++++ .../bzlmod/tests/other_module/BUILD.bazel | 8 +++++++ .../other_module/other_module_import_test.py | 22 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 examples/bzlmod/tests/other_module/other_module_import_test.py diff --git a/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel b/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel index 53344c708a..318822d888 100644 --- a/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel +++ b/examples/bzlmod/other_module/other_module/pkg/BUILD.bazel @@ -1,5 +1,6 @@ load("@rules_python//python:py_binary.bzl", "py_binary") load("@rules_python//python:py_library.bzl", "py_library") +load("@rules_python//python/zipapp:py_zipapp_binary.bzl", "py_zipapp_binary") py_library( name = "lib", @@ -26,4 +27,13 @@ py_binary( ], ) +# This is used for regression testing runfiles paths in submodules. +# https://github.com/bazel-contrib/rules_python/issues/3563. +py_zipapp_binary( + name = "bin_zipapp", + testonly = True, + binary = ":bin", + visibility = ["//visibility:public"], +) + exports_files(["data/data.txt"]) diff --git a/examples/bzlmod/tests/other_module/BUILD.bazel b/examples/bzlmod/tests/other_module/BUILD.bazel index 1bd8a900a9..1e657c8431 100644 --- a/examples/bzlmod/tests/other_module/BUILD.bazel +++ b/examples/bzlmod/tests/other_module/BUILD.bazel @@ -5,6 +5,7 @@ # in the root module. load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@rules_python//python:py_test.bzl", "py_test") build_test( name = "other_module_bin_build_test", @@ -12,3 +13,10 @@ build_test( "@our_other_module//other_module/pkg:bin", ], ) + +py_test( + name = "other_module_import_test", + srcs = ["other_module_import_test.py"], + data = ["@our_other_module//other_module/pkg:bin_zipapp"], + env = {"ZIPAPP_PATH": "$(location @our_other_module//other_module/pkg:bin_zipapp)"}, +) diff --git a/examples/bzlmod/tests/other_module/other_module_import_test.py b/examples/bzlmod/tests/other_module/other_module_import_test.py new file mode 100644 index 0000000000..6b92a853e0 --- /dev/null +++ b/examples/bzlmod/tests/other_module/other_module_import_test.py @@ -0,0 +1,22 @@ +"""Regression test for https://github.com/bazel-contrib/rules_python/issues/3563""" +import os +import subprocess +import sys + +def main(): + # The rlocation path for the bin_zipapp. It is in the "our_other_module" repository. + zipapp_path = os.environ.get("ZIPAPP_PATH") + print(f"Running bin_zipapp at: {zipapp_path}") + + result = subprocess.run([zipapp_path], capture_output=True, text=True) + print("--- bin_zippapp stdout ---") + print(result.stdout) + print("--- bin_zippapp stderr ---") + print(result.stderr) + + if result.returncode != 0: + print(f"bin_zippapp failed with return code {result.returncode}") + sys.exit(result.returncode) + +if __name__ == "__main__": + main() From 891046370944f45fe2cb122bf38873e267620394 Mon Sep 17 00:00:00 2001 From: Alex Faxa Date: Sat, 14 Mar 2026 10:08:16 +0100 Subject: [PATCH 4/4] Disable test on windows --- examples/bzlmod/tests/other_module/BUILD.bazel | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/bzlmod/tests/other_module/BUILD.bazel b/examples/bzlmod/tests/other_module/BUILD.bazel index 1e657c8431..24231e651a 100644 --- a/examples/bzlmod/tests/other_module/BUILD.bazel +++ b/examples/bzlmod/tests/other_module/BUILD.bazel @@ -19,4 +19,10 @@ py_test( srcs = ["other_module_import_test.py"], data = ["@our_other_module//other_module/pkg:bin_zipapp"], env = {"ZIPAPP_PATH": "$(location @our_other_module//other_module/pkg:bin_zipapp)"}, + # For now, skip this test on Windows because it fails for reasons + # other than the code path being tested. + target_compatible_with = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), )