From 60a99065e20626d194a5d36f1ab14c636a86bbc8 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 15:47:06 +0800 Subject: [PATCH 01/15] Add search paths info to unresolved import diagnostics --- crates/ty_python_semantic/src/types/infer.rs | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 07f82a732949c..884c9587e402c 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -72,6 +72,7 @@ use crate::place::{ module_type_implicit_global_declaration, module_type_implicit_global_symbol, place, place_from_bindings, place_from_declarations, typing_extensions_symbol, }; + use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey; use crate::semantic_index::ast_ids::{HasScopedUseId, ScopedUseId}; use crate::semantic_index::definition::{ @@ -4960,11 +4961,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let Some(builder) = self.context.report_lint(&UNRESOLVED_IMPORT, range) else { return; }; + let mut diagnostic = builder.into_diagnostic(format_args!( "Cannot resolve imported module `{}{}`", ".".repeat(level as usize), module.unwrap_or_default() )); + if level == 0 { if let Some(module_name) = module.and_then(ModuleName::new) { let program = Program::get(self.db()); @@ -4989,6 +4992,27 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } } + // Add search paths information to the diagnostic + let mut search_paths: Vec = Vec::new(); + let mut path_index = 1; + + // Get all system paths (this includes first-party and site-packages) + for path in crate::module_resolver::system_module_search_paths(self.db()) { + search_paths.push(format!(" {}. {}", path_index, path)); + path_index += 1; + } + + // Note about vendored stdlib (since it's not included in system paths) + search_paths.push(format!( + " {}. (built-in Python standard library)", + path_index + )); + + diagnostic.info(format_args!( + "Searched in the following paths:\n{}", + search_paths.join("\n") + )); + diagnostic.info( "make sure your Python environment is properly configured: \ https://docs.astral.sh/ty/modules/#python-environment", From bd2db3fc6f6c275b730de3833fe148684989c68f Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:04:37 +0800 Subject: [PATCH 02/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 884c9587e402c..68c4bab30e261 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -64,7 +64,7 @@ use super::string_annotation::{ use super::subclass_of::SubclassOfInner; use super::{ClassBase, add_inferred_python_version_hint_to_diagnostic}; use crate::module_name::{ModuleName, ModuleNameResolutionError}; -use crate::module_resolver::{KnownModule, file_to_module, resolve_module}; +use crate::module_resolver::{KnownModule, SearchPath, file_to_module, resolve_module}; use crate::node_key::NodeKey; use crate::place::{ Boundness, ConsideredDefinitions, LookupError, Place, PlaceAndQualifiers, @@ -4998,14 +4998,18 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Get all system paths (this includes first-party and site-packages) for path in crate::module_resolver::system_module_search_paths(self.db()) { - search_paths.push(format!(" {}. {}", path_index, path)); + search_paths.push(format!( + " {}. {} (first-party or site-packages)", + path_index, path + )); path_index += 1; } - // Note about vendored stdlib (since it's not included in system paths) + // Add vendored stdlib path - create it and display it + let vendored_stdlib = SearchPath::vendored_stdlib(); search_paths.push(format!( - " {}. (built-in Python standard library)", - path_index + " {}. {} (vendored Python standard library)", + path_index, vendored_stdlib )); diagnostic.info(format_args!( From a277240199a4923fe45a28fd3a158bdcebe96d9e Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:15:44 +0800 Subject: [PATCH 03/15] Add diagnostic_search_paths and improve search path reporting --- .../src/module_resolver/mod.rs | 8 +++- crates/ty_python_semantic/src/types/infer.rs | 44 +++++++++++-------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/crates/ty_python_semantic/src/module_resolver/mod.rs b/crates/ty_python_semantic/src/module_resolver/mod.rs index 901adbf4ef667..63c20da68ea36 100644 --- a/crates/ty_python_semantic/src/module_resolver/mod.rs +++ b/crates/ty_python_semantic/src/module_resolver/mod.rs @@ -11,7 +11,7 @@ use ruff_db::system::SystemPath; use crate::Db; use crate::module_resolver::resolver::{ModuleResolveMode, search_paths}; -use resolver::SearchPathIterator; +pub(crate) use resolver::SearchPathIterator; mod list; mod module; @@ -31,6 +31,12 @@ pub fn system_module_search_paths(db: &dyn Db) -> SystemModuleSearchPathsIter<'_ } } +/// Returns an iterator over all search paths used in module resolution for diagnostics +/// This includes the same paths and order used by the actual module resolver +pub(crate) fn diagnostic_search_paths(db: &dyn Db) -> SearchPathIterator<'_> { + search_paths(db, ModuleResolveMode::StubsAllowed) +} + pub struct SystemModuleSearchPathsIter<'db> { inner: SearchPathIterator<'db>, } diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 68c4bab30e261..f7e6d2f901533 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -64,7 +64,9 @@ use super::string_annotation::{ use super::subclass_of::SubclassOfInner; use super::{ClassBase, add_inferred_python_version_hint_to_diagnostic}; use crate::module_name::{ModuleName, ModuleNameResolutionError}; -use crate::module_resolver::{KnownModule, SearchPath, file_to_module, resolve_module}; +use crate::module_resolver::{ + KnownModule, diagnostic_search_paths, file_to_module, resolve_module, +}; use crate::node_key::NodeKey; use crate::place::{ Boundness, ConsideredDefinitions, LookupError, Place, PlaceAndQualifiers, @@ -4993,29 +4995,33 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } // Add search paths information to the diagnostic - let mut search_paths: Vec = Vec::new(); + // Use the same search paths function that is used in actual module resolution + let mut search_paths_list: Vec = Vec::new(); let mut path_index = 1; - // Get all system paths (this includes first-party and site-packages) - for path in crate::module_resolver::system_module_search_paths(self.db()) { - search_paths.push(format!( - " {}. {} (first-party or site-packages)", - path_index, path - )); + // Use the same search paths that are used in actual module resolution + for path in diagnostic_search_paths(self.db()) { + let kind = if path.is_standard_library() { + if path.as_system_path().is_some() { + "custom stdlib" + } else { + "vendored stdlib" + } + } else if path.is_first_party() { + "first-party" + } else { + "site-packages" + }; + search_paths_list.push(format!(" {}. {} ({})", path_index, path, kind)); path_index += 1; } - // Add vendored stdlib path - create it and display it - let vendored_stdlib = SearchPath::vendored_stdlib(); - search_paths.push(format!( - " {}. {} (vendored Python standard library)", - path_index, vendored_stdlib - )); - - diagnostic.info(format_args!( - "Searched in the following paths:\n{}", - search_paths.join("\n") - )); + if !search_paths_list.is_empty() { + diagnostic.info(format_args!( + "Searched in the following paths:\n{}", + search_paths_list.join("\n") + )); + } diagnostic.info( "make sure your Python environment is properly configured: \ From 38a1d3cbeccf1aa622035473e09958a3e062ffc0 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:19:26 +0800 Subject: [PATCH 04/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 34 +++++++++----------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index f7e6d2f901533..f4cdfe62090f5 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4996,25 +4996,23 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Add search paths information to the diagnostic // Use the same search paths function that is used in actual module resolution - let mut search_paths_list: Vec = Vec::new(); - let mut path_index = 1; - - // Use the same search paths that are used in actual module resolution - for path in diagnostic_search_paths(self.db()) { - let kind = if path.is_standard_library() { - if path.as_system_path().is_some() { - "custom stdlib" + let search_paths_list: Vec = diagnostic_search_paths(self.db()) + .enumerate() + .map(|(index, path)| { + let kind = if path.is_standard_library() { + if path.as_system_path().is_some() { + "custom stdlib" + } else { + "vendored stdlib" + } + } else if path.is_first_party() { + "first-party" } else { - "vendored stdlib" - } - } else if path.is_first_party() { - "first-party" - } else { - "site-packages" - }; - search_paths_list.push(format!(" {}. {} ({})", path_index, path, kind)); - path_index += 1; - } + "site-packages" + }; + format!(" {}. {} ({})", index + 1, path, kind) + }) + .collect(); if !search_paths_list.is_empty() { diagnostic.info(format_args!( From d7e30963da7e0d7a79b26a4b3a9fc575f319df19 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:24:24 +0800 Subject: [PATCH 05/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index f4cdfe62090f5..d20bf6486fd58 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4999,16 +4999,15 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let search_paths_list: Vec = diagnostic_search_paths(self.db()) .enumerate() .map(|(index, path)| { - let kind = if path.is_standard_library() { - if path.as_system_path().is_some() { - "custom stdlib" - } else { - "vendored stdlib" - } - } else if path.is_first_party() { - "first-party" - } else { - "site-packages" + let kind = match path.is_standard_library() { + true => match path.as_system_path() { + Some(_) => "custom stdlib", + None => "vendored stdlib", + }, + false => match path.is_first_party() { + true => "first-party", + false => "site-packages", + }, }; format!(" {}. {} ({})", index + 1, path, kind) }) From 465a74692bc28dc690cb4db634aacc18591fc66d Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:32:23 +0800 Subject: [PATCH 06/15] cippy fix --- crates/ty_python_semantic/src/types/infer.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index d20bf6486fd58..fc8b401eb890c 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4999,15 +4999,15 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let search_paths_list: Vec = diagnostic_search_paths(self.db()) .enumerate() .map(|(index, path)| { - let kind = match path.is_standard_library() { - true => match path.as_system_path() { + let kind = if path.is_standard_library() { + match path.as_system_path() { Some(_) => "custom stdlib", None => "vendored stdlib", - }, - false => match path.is_first_party() { - true => "first-party", - false => "site-packages", - }, + } + } else if path.is_first_party() { + "first-party" + } else { + "site-packages" }; format!(" {}. {} ({})", index + 1, path, kind) }) From a567fd420e0405a3ee583186d865ad7e827cc7e7 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 16:58:02 +0800 Subject: [PATCH 07/15] fix test --- crates/ty/tests/cli/main.rs | 15 ++++++++++++++ crates/ty/tests/cli/python_environment.rs | 25 +++++++++++++++++++++++ crates/ty/tests/cli/rule_selection.rs | 6 ++++++ 3 files changed, 46 insertions(+) diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index 82edcda8c7ef5..41683a61b9f17 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -263,6 +263,9 @@ fn cli_arguments_are_relative_to_the_current_directory() -> anyhow::Result<()> { 3 | 4 | stat = add(10, 15) | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -489,6 +492,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 3 | 4 | print(z) | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -498,6 +504,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 2 | import does_not_exist # error: unresolved-import | ^^^^^^^^^^^^^^ | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -524,6 +533,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 3 | 4 | print(z) | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -533,6 +545,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 2 | import does_not_exist # error: unresolved-import | ^^^^^^^^^^^^^^ | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/python_environment.rs b/crates/ty/tests/cli/python_environment.rs index 3c9714d00ef8b..f90e5df88ec67 100644 --- a/crates/ty/tests/cli/python_environment.rs +++ b/crates/ty/tests/cli/python_environment.rs @@ -333,6 +333,10 @@ import bar", | ^^^ 2 | import bar | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) + 3. /strange-venv-location/lib/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -378,6 +382,11 @@ fn lib64_site_packages_directory_on_unix() -> anyhow::Result<()> { 1 | import foo, bar, baz | ^^^ | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) + 3. /.venv/lib/python3.13/site-packages (site-packages) + 4. /.venv/lib64/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1273,6 +1282,9 @@ home = ./ 3 | from package1 import ChildConda 4 | from package1 import WorkingVenv | + info: Searched in the following paths: + 1. /project (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1285,6 +1297,9 @@ home = ./ 4 | from package1 import WorkingVenv 5 | from package1 import BaseConda | + info: Searched in the following paths: + 1. /project (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1297,6 +1312,9 @@ home = ./ | ^^^^^^^^ 5 | from package1 import BaseConda | + info: Searched in the following paths: + 1. /project (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1308,6 +1326,9 @@ home = ./ 5 | from package1 import BaseConda | ^^^^^^^^ | + info: Searched in the following paths: + 1. /project (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1716,6 +1737,10 @@ fn default_root_tests_package() -> anyhow::Result<()> { 4 | 5 | print(f"{foo} {bar}") | + info: Searched in the following paths: + 1. / (first-party) + 2. /src (first-party) + 3. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/rule_selection.rs b/crates/ty/tests/cli/rule_selection.rs index 16a1d4eb74b66..28f291a57e1a4 100644 --- a/crates/ty/tests/cli/rule_selection.rs +++ b/crates/ty/tests/cli/rule_selection.rs @@ -101,6 +101,9 @@ fn cli_rule_severity() -> anyhow::Result<()> { 3 | 4 | y = 4 / 0 | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -141,6 +144,9 @@ fn cli_rule_severity() -> anyhow::Result<()> { 3 | 4 | y = 4 / 0 | + info: Searched in the following paths: + 1. / (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` was selected on the command line From 1a3feb3d8da21e118d21f56e3d9857f243bbda32 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Fri, 22 Aug 2025 17:14:40 +0800 Subject: [PATCH 08/15] fix test --- ...ultiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" | 3 +++ ...nresolvable_module_\342\200\246_(846453deaca1071c).snap" | 3 +++ ...nresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" | 6 ++++++ ...n_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" | 3 +++ ...sing_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" | 3 +++ 5 files changed, 18 insertions(+) diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" index 13b63a659f01c..6a926383bdfb8 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" @@ -26,6 +26,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | from does_not_exist import foo, bar, baz | ^^^^^^^^^^^^^^ | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" index faa9a6155f984..2609a0fbb1b9e 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" @@ -24,6 +24,9 @@ error[unresolved-import]: Cannot resolve imported module `zqzqzqzqzqzqzq` 1 | import zqzqzqzqzqzqzq # error: [unresolved-import] "Cannot resolve imported module `zqzqzqzqzqzqzq`" | ^^^^^^^^^^^^^^ | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" index 1bbe221bb7bc2..178df740e3afb 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" @@ -36,6 +36,9 @@ error[unresolved-import]: Cannot resolve imported module `a.foo` 3 | 4 | # Topmost component unresolvable: | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -49,6 +52,9 @@ error[unresolved-import]: Cannot resolve imported module `b.foo` 5 | import b.foo # error: [unresolved-import] "Cannot resolve imported module `b.foo`" | ^^^^^ | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" index 633cb50b16dd7..fb2fb37a66cb6 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" @@ -28,6 +28,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | 3 | x = does_not_exist.foo | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" index 0d687bf11c773..6e8ccba808b2f 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" @@ -28,6 +28,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | 3 | stat = add(10, 15) | +info: Searched in the following paths: + 1. /src (first-party) + 2. vendored://stdlib (vendored stdlib) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default From 71364a7caf038bfecee40e67ab134a84f62facea Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 23 Aug 2025 19:56:17 +0100 Subject: [PATCH 09/15] nitpicks --- crates/ty/tests/cli/main.rs | 34 +++++++------- crates/ty/tests/cli/python_environment.rs | 44 +++++++++---------- crates/ty/tests/cli/rule_selection.rs | 16 +++---- ...s_imp\342\200\246_(cbfbf5ff94e6e104).snap" | 6 +-- ...dule_\342\200\246_(846453deaca1071c).snap" | 6 +-- ...bmodu\342\200\246_(4fad4be9778578b7).snap" | 12 ++--- ..._impo\342\200\246_(72d090df51ea97b8).snap" | 6 +-- ...th_an\342\200\246_(9fa713dfa17cc404).snap" | 6 +-- .../src/module_resolver/mod.rs | 9 +--- .../src/module_resolver/path.rs | 19 ++++++++ crates/ty_python_semantic/src/types/infer.rs | 27 ++++-------- 11 files changed, 94 insertions(+), 91 deletions(-) diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index 41683a61b9f17..6ac0c91a10abe 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -263,9 +263,9 @@ fn cli_arguments_are_relative_to_the_current_directory() -> anyhow::Result<()> { 3 | 4 | stat = add(10, 15) | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -480,7 +480,7 @@ fn check_specific_paths() -> anyhow::Result<()> { assert_cmd_snapshot!( case.command(), - @r###" + @r" success: false exit_code: 1 ----- stdout ----- @@ -492,9 +492,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 3 | 4 | print(z) | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -504,9 +504,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 2 | import does_not_exist # error: unresolved-import | ^^^^^^^^^^^^^^ | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -514,7 +514,7 @@ fn check_specific_paths() -> anyhow::Result<()> { ----- stderr ----- WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. - "### + " ); // Now check only the `tests` and `other.py` files. @@ -533,9 +533,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 3 | 4 | print(z) | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -545,9 +545,9 @@ fn check_specific_paths() -> anyhow::Result<()> { 2 | import does_not_exist # error: unresolved-import | ^^^^^^^^^^^^^^ | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/python_environment.rs b/crates/ty/tests/cli/python_environment.rs index f90e5df88ec67..67bcff2229752 100644 --- a/crates/ty/tests/cli/python_environment.rs +++ b/crates/ty/tests/cli/python_environment.rs @@ -333,9 +333,9 @@ import bar", | ^^^ 2 | import bar | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) 3. /strange-venv-location/lib/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -382,9 +382,9 @@ fn lib64_site_packages_directory_on_unix() -> anyhow::Result<()> { 1 | import foo, bar, baz | ^^^ | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) 3. /.venv/lib/python3.13/site-packages (site-packages) 4. /.venv/lib64/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment @@ -1282,9 +1282,9 @@ home = ./ 3 | from package1 import ChildConda 4 | from package1 import WorkingVenv | - info: Searched in the following paths: - 1. /project (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. /project (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1297,9 +1297,9 @@ home = ./ 4 | from package1 import WorkingVenv 5 | from package1 import BaseConda | - info: Searched in the following paths: - 1. /project (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. /project (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1312,9 +1312,9 @@ home = ./ | ^^^^^^^^ 5 | from package1 import BaseConda | - info: Searched in the following paths: - 1. /project (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. /project (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1326,9 +1326,9 @@ home = ./ 5 | from package1 import BaseConda | ^^^^^^^^ | - info: Searched in the following paths: - 1. /project (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. /project (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1737,10 +1737,10 @@ fn default_root_tests_package() -> anyhow::Result<()> { 4 | 5 | print(f"{foo} {bar}") | - info: Searched in the following paths: - 1. / (first-party) - 2. /src (first-party) - 3. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. /src (first-party code) + 3. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/rule_selection.rs b/crates/ty/tests/cli/rule_selection.rs index 28f291a57e1a4..8ab435467d0ce 100644 --- a/crates/ty/tests/cli/rule_selection.rs +++ b/crates/ty/tests/cli/rule_selection.rs @@ -89,7 +89,7 @@ fn cli_rule_severity() -> anyhow::Result<()> { // Assert that there's an `unresolved-reference` diagnostic (error) // and an unresolved-import (error) diagnostic by default. - assert_cmd_snapshot!(case.command(), @r###" + assert_cmd_snapshot!(case.command(), @r" success: false exit_code: 1 ----- stdout ----- @@ -101,9 +101,9 @@ fn cli_rule_severity() -> anyhow::Result<()> { 3 | 4 | y = 4 / 0 | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -121,7 +121,7 @@ fn cli_rule_severity() -> anyhow::Result<()> { ----- stderr ----- WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. - "###); + "); assert_cmd_snapshot!( case @@ -144,9 +144,9 @@ fn cli_rule_severity() -> anyhow::Result<()> { 3 | 4 | y = 4 / 0 | - info: Searched in the following paths: - 1. / (first-party) - 2. vendored://stdlib (vendored stdlib) + info: Searched in the following paths during module resolution: + 1. / (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` was selected on the command line diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" index 6a926383bdfb8..bf5d2530e40d3 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" @@ -26,9 +26,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | from does_not_exist import foo, bar, baz | ^^^^^^^^^^^^^^ | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" index 2609a0fbb1b9e..523e901d8e314 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" @@ -24,9 +24,9 @@ error[unresolved-import]: Cannot resolve imported module `zqzqzqzqzqzqzq` 1 | import zqzqzqzqzqzqzq # error: [unresolved-import] "Cannot resolve imported module `zqzqzqzqzqzqzq`" | ^^^^^^^^^^^^^^ | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" index 178df740e3afb..2b0071a97f1a6 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" @@ -36,9 +36,9 @@ error[unresolved-import]: Cannot resolve imported module `a.foo` 3 | 4 | # Topmost component unresolvable: | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -52,9 +52,9 @@ error[unresolved-import]: Cannot resolve imported module `b.foo` 5 | import b.foo # error: [unresolved-import] "Cannot resolve imported module `b.foo`" | ^^^^^ | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" index fb2fb37a66cb6..65859e31c8964 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" @@ -28,9 +28,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | 3 | x = does_not_exist.foo | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" index 6e8ccba808b2f..d6e9cd759bbef 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" @@ -28,9 +28,9 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 2 | 3 | stat = add(10, 15) | -info: Searched in the following paths: - 1. /src (first-party) - 2. vendored://stdlib (vendored stdlib) +info: Searched in the following paths during module resolution: + 1. /src (first-party code) + 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty_python_semantic/src/module_resolver/mod.rs b/crates/ty_python_semantic/src/module_resolver/mod.rs index 63c20da68ea36..6754de0769788 100644 --- a/crates/ty_python_semantic/src/module_resolver/mod.rs +++ b/crates/ty_python_semantic/src/module_resolver/mod.rs @@ -10,8 +10,7 @@ pub use resolver::{resolve_module, resolve_real_module}; use ruff_db::system::SystemPath; use crate::Db; -use crate::module_resolver::resolver::{ModuleResolveMode, search_paths}; -pub(crate) use resolver::SearchPathIterator; +pub(crate) use resolver::{SearchPathIterator, search_paths, ModuleResolveMode}; mod list; mod module; @@ -31,12 +30,6 @@ pub fn system_module_search_paths(db: &dyn Db) -> SystemModuleSearchPathsIter<'_ } } -/// Returns an iterator over all search paths used in module resolution for diagnostics -/// This includes the same paths and order used by the actual module resolver -pub(crate) fn diagnostic_search_paths(db: &dyn Db) -> SearchPathIterator<'_> { - search_paths(db, ModuleResolveMode::StubsAllowed) -} - pub struct SystemModuleSearchPathsIter<'db> { inner: SearchPathIterator<'db>, } diff --git a/crates/ty_python_semantic/src/module_resolver/path.rs b/crates/ty_python_semantic/src/module_resolver/path.rs index 9a697f27f1fc2..cb524cb4aca11 100644 --- a/crates/ty_python_semantic/src/module_resolver/path.rs +++ b/crates/ty_python_semantic/src/module_resolver/path.rs @@ -700,6 +700,25 @@ impl SearchPath { SearchPathInner::StandardLibraryVendored(_) => "std-vendored", } } + + /// Returns a string suitable for describing what kind of search path this is + /// in user-facing diagnostics. + #[must_use] + pub(crate) fn describe_kind(&self) -> &'static str { + match *self.0 { + SearchPathInner::Extra(_) => { + "extra search path specified on the CLI or in your config file" + } + SearchPathInner::FirstParty(_) => "first-party code", + SearchPathInner::StandardLibraryCustom(_) => { + "custom stdlib stubs specified on the CLI or in your config file" + } + SearchPathInner::StandardLibraryReal(_) => "runtime stdlib source code", + SearchPathInner::SitePackages(_) => "site-packages", + SearchPathInner::Editable(_) => "editable install", + SearchPathInner::StandardLibraryVendored(_) => "stdlib typeshed stubs vendored by ty", + } + } } impl PartialEq for SearchPath { diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index fc8b401eb890c..001763350fdc5 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -65,7 +65,7 @@ use super::subclass_of::SubclassOfInner; use super::{ClassBase, add_inferred_python_version_hint_to_diagnostic}; use crate::module_name::{ModuleName, ModuleNameResolutionError}; use crate::module_resolver::{ - KnownModule, diagnostic_search_paths, file_to_module, resolve_module, + KnownModule, ModuleResolveMode, file_to_module, resolve_module, search_paths, }; use crate::node_key::NodeKey; use crate::place::{ @@ -4996,26 +4996,17 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Add search paths information to the diagnostic // Use the same search paths function that is used in actual module resolution - let search_paths_list: Vec = diagnostic_search_paths(self.db()) - .enumerate() - .map(|(index, path)| { - let kind = if path.is_standard_library() { - match path.as_system_path() { - Some(_) => "custom stdlib", - None => "vendored stdlib", - } - } else if path.is_first_party() { - "first-party" - } else { - "site-packages" - }; - format!(" {}. {} ({})", index + 1, path, kind) - }) - .collect(); + let search_paths_list: Vec = + search_paths(self.db(), ModuleResolveMode::StubsAllowed) + .enumerate() + .map(|(index, path)| { + format!(" {}. {} ({})", index + 1, path, path.describe_kind()) + }) + .collect(); if !search_paths_list.is_empty() { diagnostic.info(format_args!( - "Searched in the following paths:\n{}", + "Searched in the following paths during module resolution:\n{}", search_paths_list.join("\n") )); } From b6f172f6b57b995c9471a004c82d1eba34203445 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 23 Aug 2025 20:53:54 +0100 Subject: [PATCH 10/15] fix formatting --- crates/ty_python_semantic/src/module_resolver/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ty_python_semantic/src/module_resolver/mod.rs b/crates/ty_python_semantic/src/module_resolver/mod.rs index 6754de0769788..549ffa2c9678a 100644 --- a/crates/ty_python_semantic/src/module_resolver/mod.rs +++ b/crates/ty_python_semantic/src/module_resolver/mod.rs @@ -10,7 +10,7 @@ pub use resolver::{resolve_module, resolve_real_module}; use ruff_db::system::SystemPath; use crate::Db; -pub(crate) use resolver::{SearchPathIterator, search_paths, ModuleResolveMode}; +pub(crate) use resolver::{ModuleResolveMode, SearchPathIterator, search_paths}; mod list; mod module; From 6404f55a1ef4cef4259bd696155f9651533cb750 Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Tue, 26 Aug 2025 09:52:43 +0800 Subject: [PATCH 11/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 001763350fdc5..8afbd0293e29d 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -74,7 +74,6 @@ use crate::place::{ module_type_implicit_global_declaration, module_type_implicit_global_symbol, place, place_from_bindings, place_from_declarations, typing_extensions_symbol, }; - use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey; use crate::semantic_index::ast_ids::{HasScopedUseId, ScopedUseId}; use crate::semantic_index::definition::{ @@ -4963,13 +4962,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { let Some(builder) = self.context.report_lint(&UNRESOLVED_IMPORT, range) else { return; }; - let mut diagnostic = builder.into_diagnostic(format_args!( "Cannot resolve imported module `{}{}`", ".".repeat(level as usize), module.unwrap_or_default() )); - if level == 0 { if let Some(module_name) = module.and_then(ModuleName::new) { let program = Program::get(self.db()); From 6065f3de8ff930d61065bf69ad8fb4e08cc0be3d Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Tue, 26 Aug 2025 10:04:33 +0800 Subject: [PATCH 12/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 8afbd0293e29d..3c80695664fcf 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4993,19 +4993,22 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Add search paths information to the diagnostic // Use the same search paths function that is used in actual module resolution - let search_paths_list: Vec = - search_paths(self.db(), ModuleResolveMode::StubsAllowed) - .enumerate() - .map(|(index, path)| { - format!(" {}. {} ({})", index + 1, path, path.describe_kind()) - }) - .collect(); + let search_paths: Vec<_> = + search_paths(self.db(), ModuleResolveMode::StubsAllowed).collect(); - if !search_paths_list.is_empty() { + if !search_paths.is_empty() { diagnostic.info(format_args!( - "Searched in the following paths during module resolution:\n{}", - search_paths_list.join("\n") + "Searched in the following paths during module resolution:" )); + + for (index, path) in search_paths.iter().enumerate() { + diagnostic.info(format_args!( + " {}. {} ({})", + index + 1, + path, + path.describe_kind() + )); + } } diagnostic.info( From abc12e16d78b048a97f4547f4d9b769dbe18653c Mon Sep 17 00:00:00 2001 From: Renkai Ge Date: Tue, 26 Aug 2025 13:31:12 +0800 Subject: [PATCH 13/15] adjust errors --- crates/ty/tests/cli/main.rs | 20 ++++++------- crates/ty/tests/cli/python_environment.rs | 36 +++++++++++------------ crates/ty/tests/cli/rule_selection.rs | 8 ++--- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/ty/tests/cli/main.rs b/crates/ty/tests/cli/main.rs index 6ac0c91a10abe..f85f294842f7e 100644 --- a/crates/ty/tests/cli/main.rs +++ b/crates/ty/tests/cli/main.rs @@ -264,8 +264,8 @@ fn cli_arguments_are_relative_to_the_current_directory() -> anyhow::Result<()> { 4 | stat = add(10, 15) | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -493,8 +493,8 @@ fn check_specific_paths() -> anyhow::Result<()> { 4 | print(z) | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -505,8 +505,8 @@ fn check_specific_paths() -> anyhow::Result<()> { | ^^^^^^^^^^^^^^ | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -534,8 +534,8 @@ fn check_specific_paths() -> anyhow::Result<()> { 4 | print(z) | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -546,8 +546,8 @@ fn check_specific_paths() -> anyhow::Result<()> { | ^^^^^^^^^^^^^^ | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/python_environment.rs b/crates/ty/tests/cli/python_environment.rs index 67bcff2229752..d20a9c8add886 100644 --- a/crates/ty/tests/cli/python_environment.rs +++ b/crates/ty/tests/cli/python_environment.rs @@ -334,9 +334,9 @@ import bar", 2 | import bar | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) - 3. /strange-venv-location/lib/python3.13/site-packages (site-packages) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 3. /strange-venv-location/lib/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -383,10 +383,10 @@ fn lib64_site_packages_directory_on_unix() -> anyhow::Result<()> { | ^^^ | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) - 3. /.venv/lib/python3.13/site-packages (site-packages) - 4. /.venv/lib64/python3.13/site-packages (site-packages) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 3. /.venv/lib/python3.13/site-packages (site-packages) + info: 4. /.venv/lib64/python3.13/site-packages (site-packages) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1283,8 +1283,8 @@ home = ./ 4 | from package1 import WorkingVenv | info: Searched in the following paths during module resolution: - 1. /project (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. /project (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1298,8 +1298,8 @@ home = ./ 5 | from package1 import BaseConda | info: Searched in the following paths during module resolution: - 1. /project (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. /project (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1313,8 +1313,8 @@ home = ./ 5 | from package1 import BaseConda | info: Searched in the following paths during module resolution: - 1. /project (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. /project (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1327,8 +1327,8 @@ home = ./ | ^^^^^^^^ | info: Searched in the following paths during module resolution: - 1. /project (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. /project (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -1738,9 +1738,9 @@ fn default_root_tests_package() -> anyhow::Result<()> { 5 | print(f"{foo} {bar}") | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. /src (first-party code) - 3. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. /src (first-party code) + info: 3. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git a/crates/ty/tests/cli/rule_selection.rs b/crates/ty/tests/cli/rule_selection.rs index 8ab435467d0ce..8b5382f564390 100644 --- a/crates/ty/tests/cli/rule_selection.rs +++ b/crates/ty/tests/cli/rule_selection.rs @@ -102,8 +102,8 @@ fn cli_rule_severity() -> anyhow::Result<()> { 4 | y = 4 / 0 | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -145,8 +145,8 @@ fn cli_rule_severity() -> anyhow::Result<()> { 4 | y = 4 / 0 | info: Searched in the following paths during module resolution: - 1. / (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) + info: 1. / (first-party code) + info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` was selected on the command line From 70c895626a23f4adc92747d1b68e5fd6ae0c936e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AC=8B=E5=B9=B2?= Date: Tue, 26 Aug 2025 21:41:16 +0800 Subject: [PATCH 14/15] fix tests --- ...tiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" | 4 ++-- ...esolvable_module_\342\200\246_(846453deaca1071c).snap" | 4 ++-- ...esolvable_submodu\342\200\246_(4fad4be9778578b7).snap" | 8 ++++---- ...unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" | 4 ++-- ...ng_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" index bf5d2530e40d3..79600310ea275 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Multiple_objects_imp\342\200\246_(cbfbf5ff94e6e104).snap" @@ -27,8 +27,8 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` | ^^^^^^^^^^^^^^ | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" index 523e901d8e314..af7b769b1f562 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_module_\342\200\246_(846453deaca1071c).snap" @@ -25,8 +25,8 @@ error[unresolved-import]: Cannot resolve imported module `zqzqzqzqzqzqzq` | ^^^^^^^^^^^^^^ | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" index 2b0071a97f1a6..f6ecd692f30ad 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/basic.md_-_Structures_-_Unresolvable_submodu\342\200\246_(4fad4be9778578b7).snap" @@ -37,8 +37,8 @@ error[unresolved-import]: Cannot resolve imported module `a.foo` 4 | # Topmost component unresolvable: | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default @@ -53,8 +53,8 @@ error[unresolved-import]: Cannot resolve imported module `b.foo` | ^^^^^ | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" index 65859e31c8964..fbaa1abc00c9f 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_An_unresolvable_impo\342\200\246_(72d090df51ea97b8).snap" @@ -29,8 +29,8 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 3 | x = does_not_exist.foo | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" index d6e9cd759bbef..83f03b79296f5 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_an\342\200\246_(9fa713dfa17cc404).snap" @@ -29,8 +29,8 @@ error[unresolved-import]: Cannot resolve imported module `does_not_exist` 3 | stat = add(10, 15) | info: Searched in the following paths during module resolution: - 1. /src (first-party code) - 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) +info: 1. /src (first-party code) +info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment info: rule `unresolved-import` is enabled by default From 1c2fe863c80831be3c98d49dbeefd89ea37d9292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AC=8B=E5=B9=B2?= Date: Tue, 26 Aug 2025 21:45:31 +0800 Subject: [PATCH 15/15] Update infer.rs --- crates/ty_python_semantic/src/types/infer.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 3c80695664fcf..8a45309391a1c 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4993,15 +4993,15 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Add search paths information to the diagnostic // Use the same search paths function that is used in actual module resolution - let search_paths: Vec<_> = - search_paths(self.db(), ModuleResolveMode::StubsAllowed).collect(); + let mut search_paths = + search_paths(self.db(), ModuleResolveMode::StubsAllowed).peekable(); - if !search_paths.is_empty() { + if search_paths.peek().is_some() { diagnostic.info(format_args!( "Searched in the following paths during module resolution:" )); - for (index, path) in search_paths.iter().enumerate() { + for (index, path) in search_paths.enumerate() { diagnostic.info(format_args!( " {}. {} ({})", index + 1,