aspect-build / aspect-build/rules_py

[Bug]: uv based venv generator creates .venv not usable with uv

Open
#895 5 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?

I've got an environment that's [mocked here](https://github.com/ha1dfo/repro-py-proto/tree/use_uv).
I had previous ticket on venv generation [here](https://github.com/aspect-build/rules_py/issues/785).

I am generating the .venv so that my IDE (vscode) can pick it up.
Vscode uses `uv pip list --python=` to parse the .venv.

However, when generating a .venv with aspect_rules_py, it creates one that's not parseable by uv.

When looking at it with strace, I can see that it prints that we've got python 3.13 and nothing more.
```
$ strace -ff -o /tmp/uvpip uv pip list --python .<...>+orchestrator.venv/bin/python
Using Python 3.13.12 environment at: /home//.cache/bazel/_bazel_/09e1a13f6e7dc94649c8d65787235f07/execroot/_main/bazel-out/k8-fastbuild-ST-f38e6014d46d/bin/<...>/orchestrator.venv.runfiles/_main/<...>/.orchestrator.venv
```

We do have a `pyvenv.cfg`:
```
unix_users 359 Mar 26 06:44 pyvenv.cfg
$ cat /home//repos//.<...>+orchestrator.venv/pyvenv.cfg
home = ./bin/
implementation = CPython
version_info = 3.13.0
include-system-site-packages = false
aspect-include-user-site-packages = false
relocatable = true
# Non-standard extension keys used by the Aspect shim
aspect-runfiles-interpreter = aspect_rules_py++python_interpreters+python_3_13_x86_64_unknown_linux_gnu/bin/python3
aspect-runfiles-repo = _main
```

But uv pip list fails:
```
$ uv pip list --python /home//repos//.venv/bin/python
Using Python 3.13.12 environment at: /home//.cache/bazel/_bazel_/09e1a13f6e7dc94649c8d65787235f07/execroot/_main/bazel-out/k8-fastbuild-ST-f38e6014d46d/bin/<...>/venv.runfiles/_main/<...>/.venv
```
Strace:
```
$ strace -ff -o /tmp/uvpip uv pip list --python .<...>+orchestrator.venv/bin/python
Using Python 3.13.12 environment at: /home//.cache/bazel/_bazel_/09e1a13f6e7dc94649c8d65787235f07/execroot/_main/bazel-out/k8-fastbuild-ST-f38e6014d46d/bin/<...>/orchestrator.venv.runfiles/_main/<...>/.orchestrator.venv
```

It finds the proper directory: `lib/python3.13/site-packages`, but then the process exits:

```
statx(AT_FDCWD, "/home//.local/share/uv", AT_STATX_SYNC_AS_STAT, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFDIR|0775, stx_size=4096, ...}) = 0
getcwd("/home//repos/", 512) = 26
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "\33[2m", 4) = 4
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "Using Python 3.13.12 environment"..., 285) = 285
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "\33[0m", 4) = 4
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(2, "\n", 1) = 1
openat(AT_FDCWD, "/home//.cache/bazel/_bazel_/09e1a13f6e7dc94649c8d65787235f07/execroot/_main/bazel-out/k8-fastbuild-ST-f38e6014d46d/bin/<...>/orchestrator.venv.runfiles/_main/<...>/.orchestrator.venv/lib/python3.13/site-packages", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 10
newfstatat(10, "", {st_mode=S_IFDIR|0555, st_size=4096, ...}, AT_EMPTY_PATH) = 0
getdents64(10, 0x7f8038000f40 /* 74 entries */, 32768) = 3096
getdents64(10, 0x7f8038000f40 /* 0 entries */, 32768) = 0
close(10) = 0
```

Normally I would chalk this up as an `uv` failure, however, the main purpose of the `uv` based venv generation is to create one that's usable with uv, so I'm playing my luck and ask for help here.

To make things more interesting, when I'm trying to repro this with the mock repo, I am not even getting that far, not even the `python3.13` is found:
```
$ strace -ff -o /tmp/uvpip uv pip list --python /home//repos/repro-py-proto/.application+apple.venv
```
The strace details say we're trying to run a mock script (i guess it must be like what `./configure` used to be before bazel), it fails on loading `encodings`.

```
(...)
stat("/install/lib/python313.zip", 0x7ffcd1f596d8) = -1 ENOENT (No such file or directory)
stat("/install/lib", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib/python313.zip", 0x7ffcd1f59a08) = -1 ENOENT (No such file or directory)
stat("/install/lib/python3.13", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib/python3.13", 0x7ffcd1f59a08) = -1 ENOENT (No such file or directory)
stat("/install/lib/python3.13/lib-dynload", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib/python3.13", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("", 0x7ffcd1f59708) = -1 ENOENT (No such file or directory)
stat("/install/lib/python3.13/lib-dynload", 0x7ffcd1f59a08) = -1 ENOENT (No such file or directory)
write(2, "Fatal Python error: ", 20) = 20
write(2, "Failed to import encodings modul"..., 33) = 33
write(2, "\n", 1) = 1
write(2, "Python runtime state: ", 22) = 22
write(2, "core initialized", 16) = 16
write(2, "\n", 1) = 1
write(2, "ModuleNotFoundError", 19) = 19
write(2, ": ", 2) = 2
write(2, "No module named 'encodings'", 27) = 27
write(2, "\n", 1) = 1
write(2, "\n", 1) = 1
write(2, "Current thread 0x", 17) = 17
write(2, "00007f1721ee9740", 16) = 16
write(2, " (most recent call first):\n", 27) = 27
write(2, " \n", 20) = 20
exit_group(1) = ?
+++ exited with 1 +++
```

Interestingly, when I'm activating the .venv and try load the .venv with python, it works all fine:

```
$ . .application+apple.venv/bin/activate
$ which python
.application+apple.venv/bin/python
$ python
Python 3.13.11 (main, Dec 9 2025, 19:04:10) [Clang 21.1.4 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import encodings
>>>
$
```

At this point again could be a uv issue, but still; I was hoping to generate a venv with aspect_rules_py that is usable by vscode, and something is just not clicking.

I am happy to collect more data to work this out.

### Version

Development (host) and target OS/architectures:

Output of `bazel --version`: `9.0.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.10.0")`

Language(s) and/or frameworks involved: `Python`

### How to reproduce

Please advise, see above.

### Any other information?

Happy to gather.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the uv-based venv generation with aspect_rules_py 1.10.0 and the linked mock repository, then compare `uv pip list --python` with direct activation and Python execution. Inspect the generated `pyvenv.cfg`, runfiles layout, and interpreter paths; done means uv and VS Code can inspect the generated environment while Python still imports `encodings` successfully.

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
Quiet
Clarity
Needs clarification
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.