Skip to content

Commit a5ebb3f

Browse files
authored
[ty] Support ephemeral uv virtual environments (#18335)
1 parent 9925910 commit a5ebb3f

File tree

6 files changed

+283
-97
lines changed

6 files changed

+283
-97
lines changed

crates/ruff_db/src/system/path.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,13 @@ impl AsRef<SystemPath> for Utf8PathBuf {
596596
}
597597
}
598598

599+
impl AsRef<SystemPath> for camino::Utf8Component<'_> {
600+
#[inline]
601+
fn as_ref(&self) -> &SystemPath {
602+
SystemPath::new(self.as_str())
603+
}
604+
}
605+
599606
impl AsRef<SystemPath> for str {
600607
#[inline]
601608
fn as_ref(&self) -> &SystemPath {
@@ -626,6 +633,22 @@ impl Deref for SystemPathBuf {
626633
}
627634
}
628635

636+
impl<P: AsRef<SystemPath>> FromIterator<P> for SystemPathBuf {
637+
fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> Self {
638+
let mut buf = SystemPathBuf::new();
639+
buf.extend(iter);
640+
buf
641+
}
642+
}
643+
644+
impl<P: AsRef<SystemPath>> Extend<P> for SystemPathBuf {
645+
fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
646+
for path in iter {
647+
self.push(path);
648+
}
649+
}
650+
}
651+
629652
impl std::fmt::Debug for SystemPath {
630653
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631654
self.0.fmt(f)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Tests for `site-packages` discovery
2+
3+
## Ephemeral uv environments
4+
5+
If you use the `--with` flag when invoking `uv run`, uv will create an "ephemeral" virtual
6+
environment that is layered on top of the pre-existing environment. `site-packages` directories from
7+
the pre-existing environment will be added as an import search path at runtime as well as the
8+
`site-packages` directory from the ephemeral environment. The `VIRTUAL_ENV` environment variable
9+
will only point to the ephemeral virtual environment, but, following uv commit
10+
`7bba3d00d4ad1fb3daba86b98eb25d8d9e9836ae`, uv writes the `sys.prefix` path of the parent
11+
environment to an `extends-environment` key in the ephemeral environment's `pyvenv.cfg` file.
12+
13+
This test ensures that we are able to resolve imports that point to packages in either
14+
`site-packages` directory (the one of the ephemeral environment or the one of the parent
15+
environment) if we detect that an ephemeral uv environment has been activated.
16+
17+
```toml
18+
[environment]
19+
python = "/.venv"
20+
```
21+
22+
`/.venv/pyvenv.cfg`:
23+
24+
```cfg
25+
home = /doo/doo/wop/cpython-3.13.2-macos-aarch64-none/bin
26+
implementation = CPython
27+
uv = 0.7.6
28+
version_info = 3.13.2
29+
include-system-site-packages = false
30+
prompt = ruff
31+
extends-environment = /.other-environment
32+
```
33+
34+
`/doo/doo/wop/cpython-3.13.2-macos-aarch64-none/bin/python`:
35+
36+
```text
37+
```
38+
39+
`/.venv/<path-to-site-packages>/foo.py`:
40+
41+
```py
42+
X: int = 42
43+
```
44+
45+
`/.other-environment/<path-to-site-packages>/bar.py`:
46+
47+
```py
48+
Y: "str" = "Y"
49+
```
50+
51+
`/src/main.py`:
52+
53+
```py
54+
from foo import X
55+
from bar import Y
56+
57+
reveal_type(X) # revealed: int
58+
reveal_type(Y) # revealed: str
59+
```

crates/ty_python_semantic/src/module_resolver/resolver.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use ruff_python_ast::PythonVersion;
1414
use crate::db::Db;
1515
use crate::module_name::ModuleName;
1616
use crate::module_resolver::typeshed::{TypeshedVersions, vendored_typeshed_versions};
17-
use crate::site_packages::{PythonEnvironment, SitePackagesDiscoveryError, SysPrefixPathOrigin};
17+
use crate::site_packages::{
18+
PythonEnvironment, SitePackagesDiscoveryError, SitePackagesPaths, SysPrefixPathOrigin,
19+
};
1820
use crate::{Program, PythonPath, SearchPathSettings};
1921

2022
use super::module::{Module, ModuleKind};
@@ -289,7 +291,7 @@ impl SearchPaths {
289291
virtual_env_path,
290292
error
291293
);
292-
vec![]
294+
SitePackagesPaths::default()
293295
};
294296

295297
match PythonEnvironment::new(
@@ -304,7 +306,7 @@ impl SearchPaths {
304306
}
305307
} else {
306308
tracing::debug!("No virtual environment found");
307-
vec![]
309+
SitePackagesPaths::default()
308310
}
309311
}
310312

0 commit comments

Comments
 (0)