From 2a38395bc856dc741e4a991ea241d15c741ece4f Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 25 Nov 2025 14:02:59 -0500 Subject: [PATCH] [ty] Add some tests for re-exports and `__all__` to completions Note that the `Deprecated` symbols from `importlib.metadata` are no longer offered because 1) `importlib.metadata` defined `__all__` and 2) the `Deprecated` symbols aren't in it. These seem to not be a part of its public API according to the docs, so this seems right to me. --- crates/ty_ide/src/completion.rs | 128 ++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 15 deletions(-) diff --git a/crates/ty_ide/src/completion.rs b/crates/ty_ide/src/completion.rs index ae8e75cb9d..ba4c7e9e5b 100644 --- a/crates/ty_ide/src/completion.rs +++ b/crates/ty_ide/src/completion.rs @@ -5812,13 +5812,7 @@ from .imp let builder = completion_test_builder("deprecated") .auto_import() .module_names(); - assert_snapshot!(builder.build().snapshot(), @r" - Deprecated :: importlib.metadata - DeprecatedList :: importlib.metadata - DeprecatedNonAbstract :: importlib.metadata - DeprecatedTuple :: importlib.metadata - deprecated :: warnings - "); + assert_snapshot!(builder.build().snapshot(), @"deprecated :: warnings"); } #[test] @@ -5843,10 +5837,6 @@ from .imp .auto_import() .module_names(); assert_snapshot!(builder.build().snapshot(), @r" - Deprecated :: importlib.metadata - DeprecatedList :: importlib.metadata - DeprecatedNonAbstract :: importlib.metadata - DeprecatedTuple :: importlib.metadata deprecated :: typing_extensions deprecated :: warnings "); @@ -5872,15 +5862,123 @@ from .imp .auto_import() .module_names(); assert_snapshot!(builder.build().snapshot(), @r" - Deprecated :: importlib.metadata - DeprecatedList :: importlib.metadata - DeprecatedNonAbstract :: importlib.metadata - DeprecatedTuple :: importlib.metadata deprecated :: typing_extensions deprecated :: warnings "); } + #[test] + fn reexport_simple_import_noauto() { + let snapshot = CursorTest::builder() + .source( + "main.py", + r#" +import foo +foo.ZQ +"#, + ) + .source("foo.py", r#"from bar import ZQZQ"#) + .source("bar.py", r#"ZQZQ = 1"#) + .completion_test_builder() + .module_names() + .build() + .snapshot(); + assert_snapshot!(snapshot, @"ZQZQ :: Current module"); + } + + #[test] + fn reexport_simple_import_auto() { + let snapshot = CursorTest::builder() + .source( + "main.py", + r#" +ZQ +"#, + ) + .source("foo.py", r#"from bar import ZQZQ"#) + .source("bar.py", r#"ZQZQ = 1"#) + .completion_test_builder() + .auto_import() + .module_names() + .build() + .snapshot(); + // We're specifically looking for `ZQZQ` in `bar` + // here but *not* in `foo`. Namely, in `foo`, + // `ZQZQ` is a "regular" import that is not by + // convention considered a re-export. + assert_snapshot!(snapshot, @"ZQZQ :: bar"); + } + + #[test] + fn reexport_redundant_convention_import_noauto() { + let snapshot = CursorTest::builder() + .source( + "main.py", + r#" +import foo +foo.ZQ +"#, + ) + .source("foo.py", r#"from bar import ZQZQ as ZQZQ"#) + .source("bar.py", r#"ZQZQ = 1"#) + .completion_test_builder() + .module_names() + .build() + .snapshot(); + assert_snapshot!(snapshot, @"ZQZQ :: Current module"); + } + + #[test] + fn reexport_redundant_convention_import_auto() { + let snapshot = CursorTest::builder() + .source( + "main.py", + r#" +ZQ +"#, + ) + .source("foo.py", r#"from bar import ZQZQ as ZQZQ"#) + .source("bar.py", r#"ZQZQ = 1"#) + .completion_test_builder() + .auto_import() + .module_names() + .build() + .snapshot(); + assert_snapshot!(snapshot, @r" + ZQZQ :: bar + ZQZQ :: foo + "); + } + + #[test] + fn auto_import_respects_all() { + let snapshot = CursorTest::builder() + .source( + "main.py", + r#" +ZQ +"#, + ) + .source( + "bar.py", + r#" + ZQZQ1 = 1 + ZQZQ2 = 1 + __all__ = ['ZQZQ1'] + "#, + ) + .completion_test_builder() + .auto_import() + .module_names() + .build() + .snapshot(); + // We specifically do not want `ZQZQ2` here, since + // it is not part of `__all__`. + assert_snapshot!(snapshot, @r" + ZQZQ1 :: bar + "); + } + /// A way to create a simple single-file (named `main.py`) completion test /// builder. ///