From aacbb9c2f458fb362689b477e7bc85678e707030 Mon Sep 17 00:00:00 2001 From: Thiago Pacheco Date: Mon, 2 Jun 2025 09:29:34 -0400 Subject: [PATCH] python: Respect picked toolchain (when it's not at the root) when running tests (#31150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Fix Python venv Detection for Test Runner ## Problem Zed’s Python test runner was not reliably detecting and activating the project’s Python virtual environment (.venv or venv), causing it to default to the system Python. This led to issues such as missing dependencies (e.g., pytest) when running tests. ## Solution Project Root Awareness: The Python context provider now receives the project root path, ensuring venv detection always starts from the project root rather than the test file’s directory. Robust venv Activation: The test runner now correctly detects and activates the Python interpreter from .venv or venv in the project root, setting VIRTUAL_ENV and updating PATH as needed. Minimal Impact: The change is limited in scope, affecting only the necessary code paths for Python test runner venv detection. No broad architectural changes were made. ## Additional Improvements Updated trait and function signatures to thread the project root path where needed. Cleaned up linter warnings and unused code. ## Result Python tests now reliably run using the project’s virtual environment, matching the behavior of other IDEs and ensuring all dependencies are available. Release Notes: - Fixed Python tasks always running with a toolchain selected for the root of a workspace. --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> --- crates/languages/src/python.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 5ff9156ed90bf5156838284037254779290d5262..0a5c9dfc9eb5ebbfd04bc25205b836278f052e27 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -379,17 +379,19 @@ impl ContextProvider for PythonContextProvider { }; let module_target = self.build_module_target(variables); - let worktree_id = location - .file_location - .buffer - .read(cx) - .file() - .map(|f| f.worktree_id(cx)); + let location_file = location.file_location.buffer.read(cx).file().cloned(); + let worktree_id = location_file.as_ref().map(|f| f.worktree_id(cx)); cx.spawn(async move |cx| { let raw_toolchain = if let Some(worktree_id) = worktree_id { + let file_path = location_file + .as_ref() + .and_then(|f| f.path().parent()) + .map(Arc::from) + .unwrap_or_else(|| Arc::from("".as_ref())); + toolchains - .active_toolchain(worktree_id, Arc::from("".as_ref()), "Python".into(), cx) + .active_toolchain(worktree_id, file_path, "Python".into(), cx) .await .map_or_else( || String::from("python3"), @@ -398,14 +400,16 @@ impl ContextProvider for PythonContextProvider { } else { String::from("python3") }; + let active_toolchain = format!("\"{raw_toolchain}\""); let toolchain = (PYTHON_ACTIVE_TOOLCHAIN_PATH, active_toolchain); - let raw_toolchain = (PYTHON_ACTIVE_TOOLCHAIN_PATH_RAW, raw_toolchain); + let raw_toolchain_var = (PYTHON_ACTIVE_TOOLCHAIN_PATH_RAW, raw_toolchain); + Ok(task::TaskVariables::from_iter( test_target .into_iter() .chain(module_target.into_iter()) - .chain([toolchain, raw_toolchain]), + .chain([toolchain, raw_toolchain_var]), )) }) }