ty_module_resolver/environment.rs
1use ruff_db::files::File;
2use ruff_python_ast::PythonVersion;
3
4use crate::{Db, ModuleResolveMode, SearchPaths, search_paths};
5
6/// The Python version and search paths used to resolve modules.
7#[salsa::interned(debug, heap_size = ruff_memory_usage::heap_size)]
8pub struct ResolverEnvironment<'db> {
9 #[returns(copy)]
10 pub python_version: PythonVersion,
11
12 #[returns(ref)]
13 pub search_paths: SearchPaths,
14}
15
16impl get_size2::GetSize for ResolverEnvironment<'_> {}
17
18impl<'db> ResolverEnvironment<'db> {
19 pub fn display_search_paths(
20 self,
21 db: &'db dyn Db,
22 mode: ModuleResolveMode,
23 ) -> impl std::fmt::Display {
24 std::fmt::from_fn(move |f| {
25 let mut paths = search_paths(db, self, mode).peekable();
26
27 if paths.peek().is_none() {
28 return f.write_str("[]");
29 }
30
31 writeln!(f, "[")?;
32 for path in paths {
33 writeln!(f, " {path},")?;
34 }
35 f.write_str("]")
36 })
37 }
38}
39
40/// A file interpreted within a particular module-resolution environment.
41///
42/// The same file can resolve imports differently depending on the Python version and search paths
43/// used to interpret it.
44///
45/// For example, consider a file containing:
46///
47/// ```python
48/// from zipfile._path import Path
49/// ```
50///
51/// Typeshed makes `zipfile._path` available only on Python 3.12 and newer:
52///
53/// ```text
54/// resolve_module(ResolverFile(shared.py, Python 3.11), "zipfile._path")
55/// -> unresolved
56///
57/// resolve_module(ResolverFile(shared.py, Python 3.12), "zipfile._path")
58/// -> zipfile/_path/__init__.pyi
59/// ```
60///
61/// Search paths can also change which file an import resolves to, even when the Python version is
62/// identical:
63///
64/// ```text
65/// resolve_module(ResolverFile(shared.py, project environment), "dependency")
66/// -> .venv/lib/dependency.py
67///
68/// resolve_module(ResolverFile(shared.py, script environment), "dependency")
69/// -> .script-venv/lib/dependency.py
70/// ```
71///
72/// Including the resolver environment in the file's identity keeps these resolution results
73/// separate. Projects and scripts with equivalent resolver environments can still share resolution
74/// results.
75#[salsa::interned(debug, heap_size = ruff_memory_usage::heap_size)]
76pub struct ResolverFile<'db> {
77 #[returns(copy)]
78 pub file: File,
79
80 #[returns(copy)]
81 pub environment: ResolverEnvironment<'db>,
82}
83
84impl get_size2::GetSize for ResolverFile<'_> {}