debugger: Install debugpy into user's venv if there's one selected (#35617)
Piotr Osiewicz
created 3 months ago
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.
Change summary
crates/dap_adapters/src/python.rs | 61 +++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 21 deletions(-)
Detailed changes
@@ -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<Arc<Path>, 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<dyn DapDelegate>,
@@ -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!(