microsoft / microsoft/vscode-python-environments

Terminal activation emits `source <prefix>/bin/activate` for uv-managed toolchains that have no activate script

Offen
#1,775 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

triage-needed
Vorherrschende Sprache
TypeScript
Sterne
138
Forks
62
Ø Merge
1 T. 4 Std.
Gemergte PRs (30 T.)
35

Beschreibung

## 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.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, getShellActivationCommands und isActivatableEnvironment zu finden, und verfolge dann den dirname(executable)-Aufruf für von uv verwaltete Interpreter. Reproduziere das mit einer uv python install-Toolchain und verifiziere, dass Umgebungen ohne bin/activate keinen Aktivierungsbefehl ausgeben, während echte virtuelle Umgebungen weiterhin korrekt aktiviert werden.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python, typescript, vscode
Bereich
developer-experience, devtools, tooling
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
76/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.