microsoft / microsoft/vscode-python-environments
Terminal activation emits `source <prefix>/bin/activate` for uv-managed toolchains that have no activate script
- Ngôn ngữ chính
- TypeScript
- Star
- 138
- Fork
- 62
- Merge trung bình
- 1 ngày 4 giờ
- Pull request đã merge (30 ngày)
- 35
Mô tả
## Environment
| | |
|---|---|
| Extension | `ms-python.vscode-python-envs` **1.36.0** (also present in **1.37.2026090401**, published 2026-09-04) |
| VS Code | 1.137.0 |
| OS | macOS 15.6 (arm64) |
| Shell | zsh |
| Environment manager | `uv` (plus `ms-python.python:system` for comparison) |
## Steps to reproduce
1. `uv python install 3.13` — installs a toolchain to `~/.local/share/uv/python/cpython-3.13.9-macos-aarch64-none/`.
2. Open a folder in VS Code whose selected interpreter is that toolchain:
`Ctrl/Cmd+Shift+P` → **Python: Select Interpreter** → **Enter interpreter path…** →
`~/.local/share/uv/python/cpython-3.13.9-macos-aarch64-none/bin/python`
3. Open an integrated terminal.
## Actual behavior
```
source /Users//.local/share/uv/python/cpython-3.13.9-macos-aarch64-none/bin/activate
source: no such file or directory: /Users//.local/share/uv/python/cpython-3.13.9-macos-aarch64-none/bin/activate
```
The toolchain's `bin/` contains `python3.13`, `python`, `pip`, `idle3` — there is no `activate`.
A `uv python install` toolchain is a base interpreter, not a virtual environment, so the failure
is not a broken install: the activation command itself should never have been emitted.
Once persisted, the same command is emitted on **every** new terminal in that folder and
survives restarts — this is not a one-off.
Python Environments log for the same window:
```
[interpreterSelection] deven367: cpython-3.13.9-macos-aarch64-none (3.13.9) (source: autoDiscovery)
Terminal is activated: /Users//.local/share/uv/python/cpython-3.13.9-macos-aarch64-none/bin/python
```
(The extension also auto-discovered and selected this toolchain for a folder with no
environment at all, with no user selection — same outcome.)
## Expected behavior
No activation command is emitted for an environment that cannot be activated; either the
toolchain is reported as non-activatable (like `system` environments, which correctly emit
nothing), or the activation command is gated on the activation script existing.
## Cause
`getShellActivationCommands(dir)` sets the sh/bash/zsh/gitbash (`and "unknown"`) activation
entries **unconditionally**, while fish/csh/xsh/nu are gated on `pathExists`:
```js
t.getShellActivationCommands = async function (e) {
const t = new Map(), n = new Map();
return isWindows()
? t.set("unknown", [{ executable: join(e, "activate") }])
: t.set("unknown", [{ executable: "source", args: [join(e, "activate")] }]), // no pathExists
t.set(SH, [{ executable: "source", args: [join(e, "activate")] }]), // no pathExists
t.set(BASH, [{ executable: "source", args: [join(e, "activate")] }]), // no pathExists
t.set(GITBASH, [{ executable: "source", args: [v(join(e, "activate"))] }]), // no pathExists
t.set(ZSH, [{ executable: "source", args: [join(e, "activate")] }]), // no pathExists
...
await pathExists(join(e, "activate.csh")) && t.set(CSH, ...); // gated
await pathExists(join(e, "activate.fish")) && t.set(FISH, ...); // gated
await pathExists(join(e, "activate.xsh")) && t.set(XSH, ...); // gated
await pathExists(join(e, "activate.nu")) && t.set(NU, ...); // gated
return { shellActivation: t, shellDeactivation: n };
};
```
It is called with `dirname(executable)`, i.e. `/bin`:
```js
const a = dirname(e.executable),
{ shellActivation: o, shellDeactivation: s } = await getShellActivationCommands(a);
```
So for any prefix without `bin/activate`, a failing command is produced instead of an
environment with no activation. `isActivatableEnvironment()` then returns `true`, because it
only checks that `shellActivation` is non-empty:
```js
t.isActivatableEnvironment = function (e) {
return !!e.execInfo?.activation || !!e.execInfo?.shellActivation;
};
```
The uv manager registers these toolchains through the venv path — the log shows
`Found venv environment: cpython-3.13.9-macos-aarch64-none (3.13.9)` for a directory that has
no `pyvenv.cfg` and no `activate`. `system` environments, which carry no `shellActivation`,
behave correctly and emit nothing.
## Suggested fix
- Gate the sh/bash/zsh/gitbash/unknown entries on `pathExists(join(dir, "activate"))`, matching
the existing fish/csh/xsh/nu checks, so a prefix without an activation script yields an
effectively non-activatable environment.
- Optionally, additionally report `uv python install` toolchains as non-activatable (they have
no `pyvenv.cfg`), so they are not offered as activatable venv environments.
## Workaround
Pin the folder to the system manager, which emits no activation command:
```json
"python-envs.pythonProjects": [
{ "path": "", "envManager": "ms-python.python:system" }
]
```
or select a real `.venv` / system interpreter instead of the uv toolchain.
## Additional context
Reproduced by selecting the interpreter through **Python: Select Interpreter → Enter interpreter
path…** in the GUI, and independently by restoring the persisted
`ms-python.vscode-python-envs:venv:WORKSPACE_SELECTED` entry the picker writes.
Unrelated observation from the same session, in case it is useful: activating the extension
wrote `"python-envs.defaultEnvManager": "ms-python.python:venv"` into the workspace
`settings.json` (`~/.vscode/settings.json`) by itself.
Hướng dẫn đóng góp
Hướng nghiên cứu
Bắt đầu bằng cách tìm getShellActivationCommands và isActivatableEnvironment, sau đó lần theo lời gọi dirname(executable) đối với các trình thông dịch do uv quản lý. Tái hiện bằng một toolchain uv python install và xác minh rằng các môi trường không có bin/activate không phát ra lệnh kích hoạt nào, trong khi các môi trường ảo thực vẫn được kích hoạt chính xác.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python, typescript, vscode
- Lĩnh vực
- developer-experience, devtools, tooling
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 76/100