From 0b269a2edde0a72f2c230b3aec99e93babcda23c Mon Sep 17 00:00:00 2001 From: Maxim Popov Date: Thu, 30 Jul 2026 16:14:23 +0200 Subject: [PATCH] PY-91265 [debugger]: Activate the virtualenv for the debugged process The debugpy/DAP backend does not launch the debuggee through PythonCommandLineState.startProcess: DebugpyConfigProvider.createConfig assembles the environment from scratch and serializes it into the DAP launch request. Compared with PythonCommandLineState.prepareEnv it was missing setupVirtualEnvVariables (VIRTUAL_ENV and the venv-prefixed PATH) and addCommonEnvironmentVariables (PYCHARM_HOSTED, PYTHONUNBUFFERED, resetHomePathChanges), so a debugged process ran without its virtualenv activated and subprocess calls to tools installed in the venv failed with FileNotFoundError. The pydevd backend was unaffected because it goes through PythonCommandLineState.execute. Extract those two steps into PythonCommandLineState.addCommonAndVirtualEnvVariables, along with the PYCHARM_HOSTED decision inlined in initEnvironment (shouldAddPyCharmHosted), and call them from the default createConfig at the same ordering point, so run-configuration envs still win over the activated ones and PATH is prefix-merged. Placing the call in the interface default means every provider inherits it. Add PyDebuggerVirtualEnvTest, which runs against both backends and so asserts the parity directly. IJ-MR-216263 (cherry picked from commit 21b59a59a1a1f9550c68e4c1d61d4e27a376ead2) IJ-MR-216551 GitOrigin-RevId: 81080faed737880d84ffdab470791be629a293b0 --- .../python/run/PythonCommandLineState.java | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index a1f418606367..ba96c479dc3a 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -743,11 +743,7 @@ public abstract class PythonCommandLineState extends CommandLineState { boolean isDebug, @NotNull HelpersAwareTargetEnvironmentRequest helpersAwareTargetRequest, @Nullable Sdk sdk) { - boolean addPyCharmHosted = true; - if (sdk != null && !CondaPythonExecKt.getUsePythonForLocalConda()) { - addPyCharmHosted = PySdkExtKt.getOrCreateAdditionalData(sdk).getFlavor().providePyCharmHosted(); - } - final Map env = prepareEnv(project, runParams, addPyCharmHosted); + final Map env = prepareEnv(project, runParams, shouldAddPyCharmHosted(sdk)); setupEncodingEnvs(commandLine, commandLine.getCharset()); @@ -772,12 +768,40 @@ public abstract class PythonCommandLineState extends CommandLineState { if (runParams.getEnvs() != null) { env.putAll(runParams.getEnvs()); } - addCommonEnvironmentVariables(getInterpreterPath(project, runParams), env, addPyCharmHosted); - - setupVirtualEnvVariables(runParams, env); + addCommonAndVirtualEnvVariables(project, runParams, env, addPyCharmHosted); return env; } + /** + * @see PythonSdkFlavor#providePyCharmHosted() + */ + @ApiStatus.Internal + public static boolean shouldAddPyCharmHosted(@Nullable Sdk sdk) { + if (sdk == null || CondaPythonExecKt.getUsePythonForLocalConda()) return true; + return PySdkExtKt.getOrCreateAdditionalData(sdk).getFlavor().providePyCharmHosted(); + } + + /** + * Adds the environment variables every launched Python process is expected to have: the common ones + * ({@code PYTHONUNBUFFERED}, {@code PYCHARM_HOSTED}, …) and the ones produced by activating the + * virtualenv of {@link PythonRunParams#getSdk()}. + *

+ * {@code env} is expected to already contain the environment variables from the run configuration + * (env files and {@link PythonRunParams#getEnvs()}), because the user-specified ones win over the + * activated ones. + *

+ * Meant for launchers that don't build their command line through {@link #startProcess}, most notably + * the debugpy DAP backend, which passes the environment to the debug adapter instead. + */ + @ApiStatus.Internal + public static void addCommonAndVirtualEnvVariables(@NotNull Project project, + @NotNull PythonRunParams runParams, + @NotNull Map env, + boolean addPyCharmHosted) { + addCommonEnvironmentVariables(getInterpreterPath(project, runParams), env, addPyCharmHosted); + setupVirtualEnvVariables(runParams, env); + } + private static void setupVirtualEnvVariables(PythonRunParams runParams, Map env) { Sdk sdk = runParams.getSdk(); if (sdk == null) return;