[ty] Add a test capturing sub-optimal auto-import heuristic

Specifically, here, we'd probably like to add `TypedDict` to
the existing `from typing import ...` statement instead of
using the fully qualified `typing.TypedDict` form.

To test this, we add another snapshot mode for including imports
that a completion will insert when selected.

Ref https://github.com/astral-sh/ty/issues/1274#issuecomment-3352233790
This commit is contained in:
Andrew Gallant 2025-12-11 14:07:58 -05:00
parent 1e00300c2a
commit 550f43feb6
No known key found for this signature in database
GPG Key ID: 5518C8B38E0693E0
1 changed files with 47 additions and 0 deletions

View File

@ -6613,6 +6613,27 @@ def f(zqzqzq: str):
); );
} }
#[test]
fn auto_import_prioritizes_reusing_import_from_statements() {
let builder = completion_test_builder(
"\
import typing
from typing import Callable
TypedDi<CURSOR>
",
);
assert_snapshot!(
builder.imports().build().snapshot(),
@r"
typing.TypedDict :: <no import edit>
typing.is_typeddict :: <no import edit>
_FilterConfigurationTypedDict :: from logging.config import _FilterConfigurationTypedDict
_FormatterConfigurationTypedDict :: from logging.config import _FormatterConfigurationTypedDict
",
);
}
/// A way to create a simple single-file (named `main.py`) completion test /// A way to create a simple single-file (named `main.py`) completion test
/// builder. /// builder.
/// ///
@ -6638,6 +6659,7 @@ def f(zqzqzq: str):
skip_builtins: bool, skip_builtins: bool,
skip_keywords: bool, skip_keywords: bool,
type_signatures: bool, type_signatures: bool,
imports: bool,
module_names: bool, module_names: bool,
// This doesn't seem like a "very complex" type to me... ---AG // This doesn't seem like a "very complex" type to me... ---AG
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
@ -6670,6 +6692,7 @@ def f(zqzqzq: str):
original, original,
filtered, filtered,
type_signatures: self.type_signatures, type_signatures: self.type_signatures,
imports: self.imports,
module_names: self.module_names, module_names: self.module_names,
} }
} }
@ -6730,6 +6753,15 @@ def f(zqzqzq: str):
self self
} }
/// When set, include the import associated with the
/// completion.
///
/// Not enabled by default.
fn imports(mut self) -> CompletionTestBuilder {
self.imports = true;
self
}
/// When set, the module name for each symbol is included /// When set, the module name for each symbol is included
/// in the snapshot (if available). /// in the snapshot (if available).
fn module_names(mut self) -> CompletionTestBuilder { fn module_names(mut self) -> CompletionTestBuilder {
@ -6762,6 +6794,9 @@ def f(zqzqzq: str):
/// Whether type signatures should be included in the snapshot /// Whether type signatures should be included in the snapshot
/// generated by `CompletionTest::snapshot`. /// generated by `CompletionTest::snapshot`.
type_signatures: bool, type_signatures: bool,
/// Whether to show the import that will be inserted when this
/// completion is selected.
imports: bool,
/// Whether module names should be included in the snapshot /// Whether module names should be included in the snapshot
/// generated by `CompletionTest::snapshot`. /// generated by `CompletionTest::snapshot`.
module_names: bool, module_names: bool,
@ -6797,6 +6832,17 @@ def f(zqzqzq: str):
.unwrap_or("<no import required>"); .unwrap_or("<no import required>");
snapshot = format!("{snapshot} :: {module_name}"); snapshot = format!("{snapshot} :: {module_name}");
} }
if self.imports {
if let Some(ref edit) = c.import {
if let Some(import) = edit.content() {
snapshot = format!("{snapshot} :: {import}");
} else {
snapshot = format!("{snapshot} :: <import deletion>");
}
} else {
snapshot = format!("{snapshot} :: <no import edit>");
}
}
snapshot snapshot
}) })
.collect::<Vec<String>>() .collect::<Vec<String>>()
@ -6845,6 +6891,7 @@ def f(zqzqzq: str):
skip_builtins: false, skip_builtins: false,
skip_keywords: false, skip_keywords: false,
type_signatures: false, type_signatures: false,
imports: false,
module_names: false, module_names: false,
predicate: None, predicate: None,
} }