From 91bbdb7002b6e8298c9876ed4e4e22b0e021b98c Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 5 Aug 2025 00:37:06 +0200 Subject: [PATCH] debugger: Install debugpy into user's venv if there's one selected (#35617) Closes #35388 Release Notes: - debugger: Fixed Python debug sessions failing to launch due to a missing debugpy installation. Debugpy is now installed into user's venv if there's one available. --- crates/dap_adapters/src/python.rs | 61 ++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs index aa64fea6ed..455440d6d3 100644 --- a/crates/dap_adapters/src/python.rs +++ b/crates/dap_adapters/src/python.rs @@ -126,38 +126,42 @@ impl PythonDebugAdapter { } None } - + const BINARY_DIR: &str = if cfg!(target_os = "windows") { + "Scripts" + } else { + "bin" + }; async fn base_venv(&self, delegate: &dyn DapDelegate) -> Result, String> { - const BINARY_DIR: &str = if cfg!(target_os = "windows") { - "Scripts" - } else { - "bin" - }; self.python_venv_base .get_or_init(move || async move { let venv_base = Self::ensure_venv(delegate) .await .map_err(|e| format!("{e}"))?; - let pip_path = venv_base.join(BINARY_DIR).join("pip3"); - let installation_succeeded = util::command::new_smol_command(pip_path.as_path()) - .arg("install") - .arg("debugpy") - .arg("-U") - .output() - .await - .map_err(|e| format!("{e}"))? - .status - .success(); - if !installation_succeeded { - return Err("debugpy installation failed".into()); - } - + Self::install_debugpy_into_venv(&venv_base).await?; Ok(venv_base) }) .await .clone() } + async fn install_debugpy_into_venv(venv_path: &Path) -> Result<(), String> { + let pip_path = venv_path.join(Self::BINARY_DIR).join("pip3"); + let installation_succeeded = util::command::new_smol_command(pip_path.as_path()) + .arg("install") + .arg("debugpy") + .arg("-U") + .output() + .await + .map_err(|e| format!("{e}"))? + .status + .success(); + if !installation_succeeded { + return Err("debugpy installation failed".into()); + } + + Ok(()) + } + async fn get_installed_binary( &self, delegate: &Arc, @@ -629,11 +633,22 @@ impl DebugAdapter for PythonDebugAdapter { .await; } + let base_path = config + .config + .get("cwd") + .and_then(|cwd| { + cwd.as_str() + .map(Path::new)? + .strip_prefix(delegate.worktree_root_path()) + .ok() + }) + .unwrap_or_else(|| "".as_ref()) + .into(); let toolchain = delegate .toolchain_store() .active_toolchain( delegate.worktree_id(), - Arc::from("".as_ref()), + base_path, language::LanguageName::new(Self::LANGUAGE_NAME), cx, ) @@ -641,6 +656,10 @@ impl DebugAdapter for PythonDebugAdapter { if let Some(toolchain) = &toolchain { if let Some(path) = Path::new(&toolchain.path.to_string()).parent() { + if let Some(parent) = path.parent() { + Self::install_debugpy_into_venv(parent).await.ok(); + } + let debugpy_path = path.join("debugpy"); if delegate.fs().is_file(&debugpy_path).await { log::debug!(