[ty] Check typeshed VERSIONS for parent modules when reporting failed stdlib imports (#20908)

This is a drive-by improvement that I stumbled backwards into while
looking into

* https://github.com/astral-sh/ty/issues/296

I was writing some simple tests for "thing not in old version of stdlib"
diagnostics and checked what was added in 3.14, and saw
`compression.zstd` and to my surprise discovered that `import
compression.zstd` and `from compression import zstd` had completely
different quality diagnostics.

This is because `compression` and `compression.zstd` were *both*
introduced in 3.14, and so per VERSIONS policy only an entry for
`compression` was added, and so we don't actually have any definite info
on `compression.zstd` and give up on producing a diagnostic. However the
`from compression import zstd` form fails on looking up `compression`
and we *do* have an exact match for that, so it gets a better
diagnostic!

(aside: I have now learned about the VERSIONS format and I *really* wish
they would just enumerate all the submodules but, oh well!)

The fix is, when handling an import failure, if we fail to find an exact
match *we requery with the parent module*. In cases like
`compression.zstd` this lets us at least identify that, hey, not even
`compression` exists, and luckily that fixes the whole issue. In cases
where the parent module and submodule were introduced at different times
then we may discover that the parent module is in-range and that's fine,
we don't produce the richer stdlib diagnostic.
This commit is contained in:
Aria Desires 2025-10-16 09:25:08 -04:00 committed by GitHub
parent 3db5d5906e
commit 6a1e91ce97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 123 additions and 15 deletions

View file

@ -192,6 +192,26 @@ from string.templatelib import Template # error: [unresolved-import]
from importlib.resources import abc # error: [unresolved-import]
```
## Attempting to import a stdlib submodule when both parts haven't yet been added
`compression` and `compression.zstd` were both added in 3.14 so there is a typeshed `VERSIONS` entry
for `compression` but not `compression.zstd`. We can't be confident `compression.zstd` exists but we
do know `compression` does and can still give good diagnostics about it.
<!-- snapshot-diagnostics -->
```toml
[environment]
python-version = "3.10"
```
```py
import compression.zstd # error: [unresolved-import]
from compression import zstd # error: [unresolved-import]
import compression.fakebutwhocansay # error: [unresolved-import]
from compression import fakebutwhocansay # error: [unresolved-import]
```
## Attempting to import a stdlib module that was previously removed
<!-- snapshot-diagnostics -->

View file

@ -0,0 +1,83 @@
---
source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: basic.md - Structures - Attempting to import a stdlib submodule when both parts haven't yet been added
mdtest path: crates/ty_python_semantic/resources/mdtest/import/basic.md
---
# Python source files
## mdtest_snippet.py
```
1 | import compression.zstd # error: [unresolved-import]
2 | from compression import zstd # error: [unresolved-import]
3 | import compression.fakebutwhocansay # error: [unresolved-import]
4 | from compression import fakebutwhocansay # error: [unresolved-import]
```
# Diagnostics
```
error[unresolved-import]: Cannot resolve imported module `compression.zstd`
--> src/mdtest_snippet.py:1:8
|
1 | import compression.zstd # error: [unresolved-import]
| ^^^^^^^^^^^^^^^^
2 | from compression import zstd # error: [unresolved-import]
3 | import compression.fakebutwhocansay # error: [unresolved-import]
|
info: The stdlib module `compression` is only available on Python 3.14+
info: Python 3.10 was assumed when resolving modules because it was specified on the command line
info: rule `unresolved-import` is enabled by default
```
```
error[unresolved-import]: Cannot resolve imported module `compression`
--> src/mdtest_snippet.py:2:6
|
1 | import compression.zstd # error: [unresolved-import]
2 | from compression import zstd # error: [unresolved-import]
| ^^^^^^^^^^^
3 | import compression.fakebutwhocansay # error: [unresolved-import]
4 | from compression import fakebutwhocansay # error: [unresolved-import]
|
info: The stdlib module `compression` is only available on Python 3.14+
info: Python 3.10 was assumed when resolving modules because it was specified on the command line
info: rule `unresolved-import` is enabled by default
```
```
error[unresolved-import]: Cannot resolve imported module `compression.fakebutwhocansay`
--> src/mdtest_snippet.py:3:8
|
1 | import compression.zstd # error: [unresolved-import]
2 | from compression import zstd # error: [unresolved-import]
3 | import compression.fakebutwhocansay # error: [unresolved-import]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 | from compression import fakebutwhocansay # error: [unresolved-import]
|
info: The stdlib module `compression` is only available on Python 3.14+
info: Python 3.10 was assumed when resolving modules because it was specified on the command line
info: rule `unresolved-import` is enabled by default
```
```
error[unresolved-import]: Cannot resolve imported module `compression`
--> src/mdtest_snippet.py:4:6
|
2 | from compression import zstd # error: [unresolved-import]
3 | import compression.fakebutwhocansay # error: [unresolved-import]
4 | from compression import fakebutwhocansay # error: [unresolved-import]
| ^^^^^^^^^^^
|
info: The stdlib module `compression` is only available on Python 3.14+
info: Python 3.10 was assumed when resolving modules because it was specified on the command line
info: rule `unresolved-import` is enabled by default
```