Skip to content
19 changes: 17 additions & 2 deletions crates/ty/tests/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 during module resolution:
info: 1. <temp_dir>/ (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

Expand Down Expand Up @@ -477,7 +480,7 @@ fn check_specific_paths() -> anyhow::Result<()> {

assert_cmd_snapshot!(
case.command(),
@r###"
@r"
success: false
exit_code: 1
----- stdout -----
Expand All @@ -489,6 +492,9 @@ fn check_specific_paths() -> anyhow::Result<()> {
3 |
4 | print(z)
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Expand All @@ -498,14 +504,17 @@ fn check_specific_paths() -> anyhow::Result<()> {
2 | import does_not_exist # error: unresolved-import
| ^^^^^^^^^^^^^^
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Found 2 diagnostics

----- 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.
Expand All @@ -524,6 +533,9 @@ fn check_specific_paths() -> anyhow::Result<()> {
3 |
4 | print(z)
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Expand All @@ -533,6 +545,9 @@ fn check_specific_paths() -> anyhow::Result<()> {
2 | import does_not_exist # error: unresolved-import
| ^^^^^^^^^^^^^^
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Expand Down
25 changes: 25 additions & 0 deletions crates/ty/tests/cli/python_environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ import bar",
| ^^^
2 | import bar
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (first-party code)
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
info: 3. <temp_dir>/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

Expand Down Expand Up @@ -378,6 +382,11 @@ fn lib64_site_packages_directory_on_unix() -> anyhow::Result<()> {
1 | import foo, bar, baz
| ^^^
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (first-party code)
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
info: 3. <temp_dir>/.venv/lib/python3.13/site-packages (site-packages)
info: 4. <temp_dir>/.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

Expand Down Expand Up @@ -1273,6 +1282,9 @@ home = ./
3 | from package1 import ChildConda
4 | from package1 import WorkingVenv
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/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

Expand All @@ -1285,6 +1297,9 @@ home = ./
4 | from package1 import WorkingVenv
5 | from package1 import BaseConda
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/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

Expand All @@ -1297,6 +1312,9 @@ home = ./
| ^^^^^^^^
5 | from package1 import BaseConda
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/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

Expand All @@ -1308,6 +1326,9 @@ home = ./
5 | from package1 import BaseConda
| ^^^^^^^^
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/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

Expand Down Expand Up @@ -1716,6 +1737,10 @@ fn default_root_tests_package() -> anyhow::Result<()> {
4 |
5 | print(f"{foo} {bar}")
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (first-party code)
info: 2. <temp_dir>/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

Expand Down
10 changes: 8 additions & 2 deletions crates/ty/tests/cli/rule_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----
Expand All @@ -101,6 +101,9 @@ fn cli_rule_severity() -> anyhow::Result<()> {
3 |
4 | y = 4 / 0
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Expand All @@ -118,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
Expand All @@ -141,6 +144,9 @@ fn cli_rule_severity() -> anyhow::Result<()> {
3 |
4 | y = 4 / 0
|
info: Searched in the following paths during module resolution:
info: 1. <temp_dir>/ (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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 during module resolution:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 during module resolution:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ error[unresolved-import]: Cannot resolve imported module `a.foo`
3 |
4 | # Topmost component unresolvable:
|
info: Searched in the following paths during module resolution:
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

Expand All @@ -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 during module resolution:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 during module resolution:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 during module resolution:
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

Expand Down
3 changes: 1 addition & 2 deletions crates/ty_python_semantic/src/module_resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
use resolver::SearchPathIterator;
pub(crate) use resolver::{ModuleResolveMode, SearchPathIterator, search_paths};

mod list;
mod module;
Expand Down
19 changes: 19 additions & 0 deletions crates/ty_python_semantic/src/module_resolver/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Comment on lines +709 to +715
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally I feel like we'd be able to tell the user whether it was a CLI option or a config-file setting that caused us to look at an extra search path (or a custom stdlib search paths) during module resolution. But that would involve a fair bit of refactoring probably; I think it's best to leave it out of this PR.

SearchPathInner::StandardLibraryReal(_) => "runtime stdlib source code",
SearchPathInner::SitePackages(_) => "site-packages",
SearchPathInner::Editable(_) => "editable install",
SearchPathInner::StandardLibraryVendored(_) => "stdlib typeshed stubs vendored by ty",
}
}
}

impl PartialEq<SystemPath> for SearchPath {
Expand Down
24 changes: 23 additions & 1 deletion crates/ty_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, file_to_module, resolve_module};
use crate::module_resolver::{
KnownModule, ModuleResolveMode, file_to_module, resolve_module, search_paths,
};
use crate::node_key::NodeKey;
use crate::place::{
Boundness, ConsideredDefinitions, LookupError, Place, PlaceAndQualifiers,
Expand Down Expand Up @@ -4989,6 +4991,26 @@ 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 =
search_paths(self.db(), ModuleResolveMode::StubsAllowed).peekable();

if search_paths.peek().is_some() {
diagnostic.info(format_args!(
"Searched in the following paths during module resolution:"
));

for (index, path) in search_paths.enumerate() {
diagnostic.info(format_args!(
" {}. {} ({})",
index + 1,
path,
path.describe_kind()
));
}
}

diagnostic.info(
"make sure your Python environment is properly configured: \
https://docs.astral.sh/ty/modules/#python-environment",
Expand Down
Loading