Repository navigation
py_binary/py_test targets with slash names can share the same venv output directory #3844
Description
🐞 bug report
Affected Rule
The issue is caused by the rule: `py_binary`py_test likely has the same issue because it shares the executable creation
implementation, but the minimal reproduction below uses py_binary.
Is this a regression?
Unknown. I reproduced this with `rules_python` 2.0.3, but I have notidentified the last version where this worked correctly.
Description
When two Python executable targets in the same package have namescontaining path separators and the same basename, rules_python derives the
venv output directory from the executable basename. Because the venv outputs are
declared package-relative, distinct labels can declare the same venv output
paths.
For example, both of these labels are distinct:
//:foo/tool
//:bar/toolBut both generated executables have basename tool, so unpatched
rules_python 2.0.3 declares the same venv root for both targets:
bazel-out/.../bin/_tool.venv
Expected behavior: distinct executable labels should use distinct venv output
directories, for example _foo_tool.venv and _bar_tool.venv.
This looks related to the slash target handling fixed in #3790 for bootstrap
stub placement, but this issue affects the venv output prefix.
🔬 Minimal Reproduction
Create a fresh bzlmod workspace with these files:
MODULE.bazel
module(
name = "rules_python_slash_venv_repro",
version = "0.0.0",
)
bazel_dep(
name = "rules_python",
version = "2.0.3",
)
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
python_version = "3.11",
)
use_repo(python, "python_3_11")
register_toolchains("@python_3_11//:all")BUILD.bazel
load("@rules_python//python:defs.bzl", "py_binary")
py_binary(
name = "foo/tool",
srcs = ["foo_tool.py"],
main = "foo_tool.py",
)
py_binary(
name = "bar/tool",
srcs = ["bar_tool.py"],
main = "bar_tool.py",
)foo_tool.py
def main():
print("foo")
if __name__ == "__main__":
main()bar_tool.py
def main():
print("bar")
if __name__ == "__main__":
main()Then run:
bazel clean --expunge
bazel build //:foo/tool //:bar/tool
bazel aquery 'outputs(".*_tool[.]venv/pyvenv[.]cfg", deps(//:foo/tool + //:bar/tool))'🔥 Exception or Error
Bazel 9.1.1 completes the build in this minimal reproduction, apparently
because these FileWrite actions are identical. However, filtered aquery shows
that two distinct targets declare the same package-relative venv output:
action 'Writing file _tool.venv/pyvenv.cfg'
Target: //:bar/tool
Outputs: [bazel-out/k8-fastbuild/bin/_tool.venv/pyvenv.cfg]
action 'Writing file _tool.venv/pyvenv.cfg'
Target: //:foo/tool
Outputs: [bazel-out/k8-fastbuild/bin/_tool.venv/pyvenv.cfg]
🌍 Your Environment
Operating System:
Ubuntu 24.04.3 LTS
Linux 6.8.0-124-generic x86_64
Output of bazel version:
Bazelisk version: v1.27.0
Build label: 9.1.1
Build target: @@//src/main/java/com/google/devtools/build/lib/bazel:BazelServer
Build time: Wed Jun 03 15:41:13 2026 (1780501273)
Build timestamp: 1780501273
Build timestamp as int: 1780501273
Rules_python version:
2.0.3
Anything else relevant?
The reproduction uses the rules_python Python toolchain extension with
python_version = "3.11".
Activity
fix(rules): disambiguate slash target venv outputs (bazel-contrib#3845)