[ty] Move search path resolution to Options::to_program_settings (#18937)

This commit is contained in:
Micha Reiser 2025-06-25 18:00:38 +02:00 committed by GitHub
parent 8b22992988
commit 5d546c600a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 481 additions and 549 deletions

View file

@ -142,9 +142,9 @@ pub(crate) fn search_paths(db: &dyn Db) -> SearchPathIterator {
Program::get(db).search_paths(db).iter(db)
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SearchPaths {
/// Search paths that have been statically determined purely from reading Ruff's configuration settings.
/// Search paths that have been statically determined purely from reading ty's configuration settings.
/// These shouldn't ever change unless the config settings themselves change.
static_paths: Vec<SearchPath>,
@ -174,8 +174,9 @@ impl SearchPaths {
///
/// [module resolution order]: https://typing.python.org/en/latest/spec/distributing.html#import-resolution-ordering
pub(crate) fn from_settings(
db: &dyn Db,
settings: &SearchPathSettings,
system: &dyn System,
vendored: &VendoredFileSystem,
) -> Result<Self, SearchPathValidationError> {
fn canonicalize(path: &SystemPath, system: &dyn System) -> SystemPathBuf {
system
@ -190,14 +191,10 @@ impl SearchPaths {
python_path,
} = settings;
let system = db.system();
let files = db.files();
let mut static_paths = vec![];
for path in extra_paths {
let path = canonicalize(path, system);
files.try_add_root(db.upcast(), &path, FileRootKind::LibrarySearchPath);
tracing::debug!("Adding extra search-path '{path}'");
static_paths.push(SearchPath::extra(system, path)?);
@ -212,8 +209,6 @@ impl SearchPaths {
let typeshed = canonicalize(typeshed, system);
tracing::debug!("Adding custom-stdlib search path '{typeshed}'");
files.try_add_root(db.upcast(), &typeshed, FileRootKind::LibrarySearchPath);
let versions_path = typeshed.join("stdlib/VERSIONS");
let versions_content = system.read_to_string(&versions_path).map_err(|error| {
@ -225,13 +220,13 @@ impl SearchPaths {
let parsed: TypeshedVersions = versions_content.parse()?;
let search_path = SearchPath::custom_stdlib(db, &typeshed)?;
let search_path = SearchPath::custom_stdlib(system, &typeshed)?;
(parsed, search_path)
} else {
tracing::debug!("Using vendored stdlib");
(
vendored_typeshed_versions(db),
vendored_typeshed_versions(vendored),
SearchPath::vendored_stdlib(),
)
};
@ -282,7 +277,6 @@ impl SearchPaths {
for path in site_packages_paths {
tracing::debug!("Adding site-packages search path '{path}'");
files.try_add_root(db.upcast(), &path, FileRootKind::LibrarySearchPath);
site_packages.push(SearchPath::site_packages(system, path)?);
}
@ -313,6 +307,17 @@ impl SearchPaths {
})
}
pub(crate) fn try_register_static_roots(&self, db: &dyn Db) {
let files = db.files();
for path in self.static_paths.iter().chain(self.site_packages.iter()) {
if let Some(system_path) = path.as_system_path() {
if !path.is_first_party() {
files.try_add_root(db.upcast(), system_path, FileRootKind::LibrarySearchPath);
}
}
}
}
pub(super) fn iter<'a>(&'a self, db: &'a dyn Db) -> SearchPathIterator<'a> {
SearchPathIterator {
db,
@ -1482,20 +1487,20 @@ mod tests {
Program::from_settings(
&db,
ProgramSettings {
python_version: Some(PythonVersionWithSource {
python_version: PythonVersionWithSource {
version: PythonVersion::PY38,
source: PythonVersionSource::default(),
}),
},
python_platform: PythonPlatform::default(),
search_paths: SearchPathSettings {
extra_paths: vec![],
src_roots: vec![src.clone()],
custom_typeshed: Some(custom_typeshed),
python_path: PythonPath::KnownSitePackages(vec![site_packages]),
},
..SearchPathSettings::new(vec![src.clone()])
}
.to_search_paths(db.system(), db.vendored())
.expect("Valid search path settings"),
},
)
.context("Invalid program settings")?;
);
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
let bar_module = resolve_module(&db, &ModuleName::new_static("bar").unwrap()).unwrap();
@ -2001,20 +2006,19 @@ not_a_directory
Program::from_settings(
&db,
ProgramSettings {
python_version: Some(PythonVersionWithSource::default()),
python_version: PythonVersionWithSource::default(),
python_platform: PythonPlatform::default(),
search_paths: SearchPathSettings {
extra_paths: vec![],
src_roots: vec![SystemPathBuf::from("/src")],
custom_typeshed: None,
python_path: PythonPath::KnownSitePackages(vec![
venv_site_packages,
system_site_packages,
]),
},
..SearchPathSettings::new(vec![SystemPathBuf::from("/src")])
}
.to_search_paths(db.system(), db.vendored())
.expect("Valid search path settings"),
},
)
.expect("Valid program settings");
);
// The editable installs discovered from the `.pth` file in the first `site-packages` directory
// take precedence over the second `site-packages` directory...
@ -2080,17 +2084,13 @@ not_a_directory
Program::from_settings(
&db,
ProgramSettings {
python_version: Some(PythonVersionWithSource::default()),
python_version: PythonVersionWithSource::default(),
python_platform: PythonPlatform::default(),
search_paths: SearchPathSettings {
extra_paths: vec![],
src_roots: vec![src],
custom_typeshed: None,
python_path: PythonPath::KnownSitePackages(vec![]),
},
search_paths: SearchPathSettings::new(vec![src])
.to_search_paths(db.system(), db.vendored())
.expect("valid search path settings"),
},
)
.expect("Valid program settings");
);
// Now try to resolve the module `A` (note the capital `A` instead of `a`).
let a_module_name = ModuleName::new_static("A").unwrap();
@ -2123,17 +2123,16 @@ not_a_directory
Program::from_settings(
&db,
ProgramSettings {
python_version: Some(PythonVersionWithSource::default()),
python_version: PythonVersionWithSource::default(),
python_platform: PythonPlatform::default(),
search_paths: SearchPathSettings {
extra_paths: vec![],
src_roots: vec![project_directory],
custom_typeshed: None,
python_path: PythonPath::KnownSitePackages(vec![site_packages.clone()]),
},
..SearchPathSettings::new(vec![project_directory])
}
.to_search_paths(db.system(), db.vendored())
.unwrap(),
},
)
.unwrap();
);
let foo_module_file = File::new(&db, FilePath::System(installed_foo_module));
let module = file_to_module(&db, foo_module_file).unwrap();