aspect-build / aspect-build/rules_py
[Bug]: _aspect.pth entries anchored two level above the runfiles root when the target lives in an external repo.
- Dominant language
- Starlark
- Stars
- 145
- Forks
- 97
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 71
Description
### What happened?
What happened:
In a multi-module bzlmod workspace where the test target itself lives in an external repo (each component is its own module brought in with local_path_override), every relative entry in the generated _aspect.pth uses seven ../:
# Generated by Aspect py_binary
# Contains relative import paths to non site-package trees within the .runfiles
../../../../../../../aspect_rules_py+/py/private/pytest_shard
../../../../../../../sonic-py-swsssdk+/src
../../../../../../../sonic-swss-common+/pybind
But the venv's site-packages is only 5 levels deep inside the runfiles tree (/+/./lib/python3.13/site-packages), so 7 × .. overshoots the runfiles root by two and lands in /bin/external/. That is a different namespace: runfiles is a flat per-repo layout, while bin/external/ is the output-tree layout that only contains repos which actually produce outputs. Consequences:
Source-only external repos have no bin/external// at all, so those entries never resolve — sandboxed or with --spawn_strategy=local.
Repos with generated outputs resolve only outside the sandbox, where the path happens to exist in the real output tree.
Because CPython's site silently ignores .pth lines pointing at non-existent directories, there is no diagnostic; the symptom surfaces later as a ModuleNotFoundError for a dependency that is declared and is present in runfiles.
What expect:
_aspect.pth entries resolve to // — matching the header comment rules_py writes itself — regardless of whether the target lives in @_main or in an external module, and regardless of spawn strategy. Re-anchoring the same entries against TEST_SRCDIR in a custom entrypoint makes the identical target pass both sandboxed and non-sandboxed.
### Version
Output of bazel --version:
bazel 8.6.0
Version of the Aspect rules, or other relevant rules from your WORKSPACE or MODULE.bazel file:
bazel_dep(name = "aspect_rules_py", version = "1.11.7") — bzlmod only, no WORKSPACE. Rules in use: py_venv_test from @aspect_rules_py//py/unstable:defs.bzl, py_pytest_main from @aspect_rules_py//py:defs.bzl, third-party deps via uv.declare_hub / uv.project from @aspect_rules_py//uv/unstable:extension.bzl. The workspace shape that matters: first-party Python libraries are separate bzlmod modules brought in with local_path_override, so test targets live in external repos rather than @_main.
Language(s) and/or frameworks involved:
Python 3.13 (hermetic toolchain), pytest. The dependency closure mixes source-only py_library targets from sibling modules with one SWIG-generated C-extension py_library — both kinds of .pth entry are affected.
### How to reproduce
```shell
```
### Any other information?
_No response_
Contributor guide
Research direction
Start by tracing _aspect.pth generation from py_venv_test and py_pytest_main, comparing the relative paths with TEST_SRCDIR for an external-repository target. Reproduce under sandboxed and non-sandboxed spawn strategies, then verify that source-only and generated-output dependencies resolve under the runfiles root without ModuleNotFoundError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100