[red-knot] Change venv discovery (#17099)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run

## Summary

Rewrites the virtual env discovery to:

* Only use of `System` APIs, this ensures that the discovery will also
work when using a memory file system (testing or WASM)
* Don't traverse ancestor directories. We're not convinced that this is
necessary. Let's wait until someone shows us a use case where it is
needed
* Start from the project root and not from the current working
directory. This ensures that Red Knot picks up the right venv even when
using `knot --project ../other-dir`

## Test Plan

Existing tests, @ntBre tested that the `file_watching` tests no longer
pick up his virtual env in a parent directory
This commit is contained in:
Micha Reiser 2025-03-31 19:39:05 +02:00 committed by GitHub
parent 4a6fa5fc27
commit a1535fbdbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 14 additions and 20 deletions

View file

@ -121,7 +121,7 @@ impl Options {
.ok() .ok()
.map(PythonPath::from_virtual_env_var) .map(PythonPath::from_virtual_env_var)
}) })
.unwrap_or(PythonPath::Discover), .unwrap_or_else(|| PythonPath::Discover(project_root.to_path_buf())),
} }
} }

View file

@ -133,20 +133,13 @@ pub(crate) fn search_paths(db: &dyn Db) -> SearchPathIterator {
Program::get(db).search_paths(db).iter(db) Program::get(db).search_paths(db).iter(db)
} }
/// Searches for a `.venv` directory in the current or any parent directory /// Searches for a `.venv` directory in `project_root` that contains a `pyvenv.cfg` file.
fn virtual_env_from_working_dir() -> Option<SystemPathBuf> { fn discover_venv_in(system: &dyn System, project_root: &SystemPath) -> Option<SystemPathBuf> {
let current_dir = std::env::current_dir().ok()?; let virtual_env_directory = project_root.join(".venv");
for dir in current_dir.ancestors() { system
let dot_venv = dir.join(".venv"); .is_file(&virtual_env_directory.join("pyvenv.cfg"))
if dot_venv.is_dir() { .then_some(virtual_env_directory)
if !dot_venv.join("pyvenv.cfg").is_file() {
return None;
}
return SystemPathBuf::from_path_buf(dot_venv).ok();
}
}
None
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -251,15 +244,15 @@ impl SearchPaths {
.and_then(|venv| venv.site_packages_directories(system))? .and_then(|venv| venv.site_packages_directories(system))?
} }
PythonPath::Discover => { PythonPath::Discover(root) => {
tracing::debug!("Discovering virtual environment"); tracing::debug!("Discovering virtual environment in `{root}`");
let virtual_env_path = virtual_env_from_working_dir(); let virtual_env_path = discover_venv_in(db.system(), root);
if let Some(virtual_env_path) = virtual_env_path { if let Some(virtual_env_path) = virtual_env_path {
tracing::debug!("Found `.venv` folder at '{}'", virtual_env_path); tracing::debug!("Found `.venv` folder at `{}`", virtual_env_path);
let handle_invalid_virtual_env = |error: SitePackagesDiscoveryError| { let handle_invalid_virtual_env = |error: SitePackagesDiscoveryError| {
tracing::debug!( tracing::debug!(
"Ignoring automatically detected virtual environment at '{}': {}", "Ignoring automatically detected virtual environment at `{}`: {}",
virtual_env_path, virtual_env_path,
error error
); );

View file

@ -145,7 +145,8 @@ pub enum PythonPath {
/// [`sys.prefix`]: https://docs.python.org/3/library/sys.html#sys.prefix /// [`sys.prefix`]: https://docs.python.org/3/library/sys.html#sys.prefix
SysPrefix(SystemPathBuf, SysPrefixPathOrigin), SysPrefix(SystemPathBuf, SysPrefixPathOrigin),
Discover, /// Tries to discover a virtual environment in the given path.
Discover(SystemPathBuf),
/// Resolved site packages paths. /// Resolved site packages paths.
/// ///