fix(debugger): debug Python with python, not python3, on Windows (#2159)

Debugging a Python configuration with no interpreter path (a global `pytest`, `uv run`, `poetry run`) set debugpy's adapter Python to a hardcoded `python3`. On Windows that is at most a Store alias, and the debugpy venv the IDE installs has only `python.exe`, so the managed debugpy was skipped.

The launch now uses `python` on Windows, based on the host OS so remote sessions follow the server. Other platforms are unchanged.

Sibling covered: `debugLauncherPython` uses the same fallback.

Co-authored-by: Bortlesboat <[email protected]>
This commit is contained in:
Andrew Barnes authored and GitHub committed 2026-11-08 22:57:58 +08:00
1 parent db16214306
commit 152b71f5e0
2 files changed
+26 -3

No files matched your search

+18 -1
View File
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { RunConfig } from "@/platform/ipc";
import { usePlatform } from "@/platform/platformInfo";
import { debugUnsupportedReason, launchConfigFor } from "../launch";
const rc = (p: Partial<RunConfig>): RunConfig => ({
@@ -18,6 +19,10 @@ const rc = (p: Partial<RunConfig>): RunConfig => ({
const extra = (l: { extraJson: string | null } | null) => JSON.parse(l?.extraJson ?? "{}");
const originalPlatform = usePlatform.getState();
beforeEach(() => usePlatform.setState({ os: "linux" }));
afterEach(() => usePlatform.setState(originalPlatform));
describe("run config → launch config", () => {
it("returns null without an adapter", () => {
expect(launchConfigFor(rc({}), "/p")).toBeNull();
@@ -136,6 +141,18 @@ describe("run config → launch config", () => {
expect(extra(django)).toMatchObject({ django: true, python: ["pdm", "run", "python"] });
});
it("debugpy: Windows falls back to python, not the python3 Store alias", () => {
usePlatform.setState({ os: "windows" });
const globalPytest = launchConfigFor(rc({ kind: "pytest", command: "pytest", debugAdapter: "debugpy" }), "/p")!;
expect(extra(globalPytest).python).toBe("python");
const uv = launchConfigFor(
rc({ kind: "python", command: "uv", args: ["run", "python", "main.py"], debugAdapter: "debugpy" }),
"/p",
)!;
expect(extra(uv)).toMatchObject({ python: ["uv", "run", "python"], debugLauncherPython: "python" });
});
it("js-debug: npm scripts run through the package manager, node scripts directly", () => {
const npm = launchConfigFor(
rc({ kind: "npm", command: "pnpm", args: ["run", "dev"], cwd: "web", debugAdapter: "js-debug" }),
+8 -2
View File
@@ -2,6 +2,7 @@ import { parseArgs, formatArgs } from "@/platform/commandLine";
/** Run configuration → DAP launch configuration, per adapter. */
import { workflowSettings } from "@/platform/workflowSettings";
import type { LaunchConfig, RunConfig } from "@/platform/ipc";
import { hostOs } from "@/platform/remote";
function isAbsolute(p: string) {
return p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p);
@@ -60,13 +61,18 @@ function cargoLaunch(rc: RunConfig, cwd: string, adapter: string): LaunchConfig
const PYTHON_NAME = /^python[\d.]*(\.exe)?$/;
/** `python` on Windows (`python3` is at most a Store alias there, and venvs have no `python3.exe`), `python3` elsewhere. */
function systemPython(): string {
return hostOs() === "windows" ? "python" : "python3";
}
function pythonFor(rc: RunConfig, cwd: string): string {
const cmd = rc.command;
const name = cmd.split("/").pop() ?? cmd;
if (PYTHON_NAME.test(name)) return resolveCommand(cmd, cwd);
// A venv tool such as `.venv/bin/pytest`: use the interpreter next to it.
if (cmd.includes("/")) return resolveCommand(cmd.slice(0, cmd.lastIndexOf("/") + 1) + "python", cwd);
return "python3";
return systemPython();
}
/** Project managers whose `run` executes in the project's environment (`uv run python …`). */
@@ -91,7 +97,7 @@ function debugpyLaunch(rc: RunConfig, cwd: string): LaunchConfig {
// environment; the adapter and its launcher need a plain interpreter.
const python = PYTHON_NAME.test(args[1]) ? args[1] : "python";
extra.python = [resolveCommand(rc.command, cwd), "run", python];
extra.debugLauncherPython = "python3";
extra.debugLauncherPython = systemPython();
tool = PYTHON_NAME.test(args[1]) ? null : args[1];
args = args.slice(2);
}