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.

Open
#1,509 0 comments 0 reactions 0 assignees View on GitHub
bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.