languages: Validate pylsp binary before returning from check_if_user_installed (#51034)

Run `pylsp --version` via `delegate.try_exec()` in both branches of
`PyLspAdapter::check_if_user_installed` before returning the binary. If
execution fails (broken shebang, missing interpreter, etc.), log a
warning and return None so the system falls through gracefully instead
of surfacing an error dialog.

This matches the existing validation pattern used by TyLspAdapter and
RuffLspAdapter in their `fetch_server_binary` implementations.

No idea if this closes an issue but it sure was annoying on a system
where I deleted the pylsp environment I had. It surprised me too since I
had pylsp disabled in settings.

Release Notes:

- Fixed detection of when `pylsp` is not installed properly on a user's
system so that it doesn't get launched as an LSP when it doesn't exist.
This commit is contained in:
Kyle Kelley authored and GitHub committed 2026-03-11 09:12:18 +01:00
1 parent b5666319b4
commit c08fd438ec
1 file changed
+26 -1
+26 -1
View File
@@ -1846,6 +1846,17 @@ impl LspInstaller for PyLspAdapter {
) -> Option<LanguageServerBinary> {
if let Some(pylsp_bin) = delegate.which(Self::SERVER_NAME.as_ref()).await {
let env = delegate.shell_env().await;
delegate
.try_exec(LanguageServerBinary {
path: pylsp_bin.clone(),
arguments: vec!["--version".into()],
env: Some(env.clone()),
})
.await
.inspect_err(|err| {
log::warn!("failed to validate user-installed pylsp at {pylsp_bin:?}: {err:#}")
})
.ok()?;
Some(LanguageServerBinary {
path: pylsp_bin,
env: Some(env),
@@ -1854,7 +1865,21 @@ impl LspInstaller for PyLspAdapter {
} else {
let toolchain = toolchain?;
let pylsp_path = Path::new(toolchain.path.as_ref()).parent()?.join("pylsp");
pylsp_path.exists().then(|| LanguageServerBinary {
if !pylsp_path.exists() {
return None;
}
delegate
.try_exec(LanguageServerBinary {
path: toolchain.path.to_string().into(),
arguments: vec![pylsp_path.clone().into(), "--version".into()],
env: None,
})
.await
.inspect_err(|err| {
log::warn!("failed to validate toolchain pylsp at {pylsp_path:?}: {err:#}")
})
.ok()?;
Some(LanguageServerBinary {
path: toolchain.path.to_string().into(),
arguments: vec![pylsp_path.into()],
env: None,