Support .pyi files in ruff analyze graph (#19611)
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 / mkdocs (push) Waiting to run
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (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 / 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-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions

## Summary

We now return both the `.pyi` and `.py` files. Previously, we only
returned the `.pyi` file.
This commit is contained in:
Charlie Marsh 2025-07-28 22:00:27 -04:00 committed by GitHub
parent c6a123290d
commit e0f4f25d28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 87 additions and 39 deletions

View file

@ -57,11 +57,16 @@ fn dependencies() -> Result<()> {
.write_str(indoc::indoc! {r#" .write_str(indoc::indoc! {r#"
def f(): pass def f(): pass
"#})?; "#})?;
root.child("ruff")
.child("e.pyi")
.write_str(indoc::indoc! {r#"
def f() -> None: ...
"#})?;
insta::with_settings!({ insta::with_settings!({
filters => INSTA_FILTERS.to_vec(), filters => INSTA_FILTERS.to_vec(),
}, { }, {
assert_cmd_snapshot!(command().current_dir(&root), @r###" assert_cmd_snapshot!(command().current_dir(&root), @r#"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
@ -77,13 +82,15 @@ fn dependencies() -> Result<()> {
"ruff/d.py" "ruff/d.py"
], ],
"ruff/d.py": [ "ruff/d.py": [
"ruff/e.py" "ruff/e.py",
"ruff/e.pyi"
], ],
"ruff/e.py": [] "ruff/e.py": [],
"ruff/e.pyi": []
} }
----- stderr ----- ----- stderr -----
"###); "#);
}); });
Ok(()) Ok(())

View file

@ -42,14 +42,12 @@ impl ModuleImports {
// Resolve the imports. // Resolve the imports.
let mut resolved_imports = ModuleImports::default(); let mut resolved_imports = ModuleImports::default();
for import in imports { for import in imports {
let Some(resolved) = Resolver::new(db).resolve(import) else { for resolved in Resolver::new(db).resolve(import) {
continue; if let Some(path) = resolved.as_system_path() {
};
let Some(path) = resolved.as_system_path() else {
continue;
};
resolved_imports.insert(path.to_path_buf()); resolved_imports.insert(path.to_path_buf());
} }
}
}
Ok(resolved_imports) Ok(resolved_imports)
} }

View file

@ -1,5 +1,5 @@
use ruff_db::files::FilePath; use ruff_db::files::FilePath;
use ty_python_semantic::resolve_module; use ty_python_semantic::{ModuleName, resolve_module, resolve_real_module};
use crate::ModuleDb; use crate::ModuleDb;
use crate::collector::CollectedImport; use crate::collector::CollectedImport;
@ -16,24 +16,67 @@ impl<'a> Resolver<'a> {
} }
/// Resolve the [`CollectedImport`] into a [`FilePath`]. /// Resolve the [`CollectedImport`] into a [`FilePath`].
pub(crate) fn resolve(&self, import: CollectedImport) -> Option<&'a FilePath> { pub(crate) fn resolve(&self, import: CollectedImport) -> impl Iterator<Item = &'a FilePath> {
match import { match import {
CollectedImport::Import(import) => { CollectedImport::Import(import) => {
let module = resolve_module(self.db, &import)?; // Attempt to resolve the module (e.g., given `import foo`, look for `foo`).
Some(module.file(self.db)?.path(self.db)) let file = self.resolve_module(&import);
// If the file is a stub, look for the corresponding source file.
let source_file = file
.is_some_and(|file| file.extension() == Some("pyi"))
.then(|| self.resolve_real_module(&import))
.flatten();
std::iter::once(file)
.chain(std::iter::once(source_file))
.flatten()
} }
CollectedImport::ImportFrom(import) => { CollectedImport::ImportFrom(import) => {
// Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`). // Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`).
let parent = import.parent(); if let Some(file) = self.resolve_module(&import) {
// If the file is a stub, look for the corresponding source file.
let source_file = (file.extension() == Some("pyi"))
.then(|| self.resolve_real_module(&import))
.flatten();
return std::iter::once(Some(file))
.chain(std::iter::once(source_file))
.flatten();
}
let module = resolve_module(self.db, &import).or_else(|| {
// Attempt to resolve the module (e.g., given `from foo import bar`, look for `foo`). // Attempt to resolve the module (e.g., given `from foo import bar`, look for `foo`).
let parent = import.parent();
let file = parent
.as_ref()
.and_then(|parent| self.resolve_module(parent));
resolve_module(self.db, &parent?) // If the file is a stub, look for the corresponding source file.
})?; let source_file = file
.is_some_and(|file| file.extension() == Some("pyi"))
.then(|| {
parent
.as_ref()
.and_then(|parent| self.resolve_real_module(parent))
})
.flatten();
std::iter::once(file)
.chain(std::iter::once(source_file))
.flatten()
}
}
}
/// Resolves a module name to a module.
fn resolve_module(&self, module_name: &ModuleName) -> Option<&'a FilePath> {
let module = resolve_module(self.db, module_name)?;
Some(module.file(self.db)?.path(self.db))
}
/// Resolves a module name to a module (stubs not allowed).
fn resolve_real_module(&self, module_name: &ModuleName) -> Option<&'a FilePath> {
let module = resolve_real_module(self.db, module_name)?;
Some(module.file(self.db)?.path(self.db)) Some(module.file(self.db)?.path(self.db))
} }
} }
}
}