[ty] Improve error messages for unresolved attribute diagnostics (#20963)

## Summary

- Type checkers (and type-checker authors) think in terms of types, but
I think most Python users think in terms of values. Rather than saying
that a _type_ `X` "has no attribute `foo`" (which I think sounds strange
to many users), say that "an object of type `X` has no attribute `foo`"
- Special-case certain types so that the diagnostic messages read more
like normal English: rather than saying "Type `<class 'Foo'>` has no
attribute `bar`" or "Object of type `<class 'Foo'>` has no attribute
`bar`", just say "Class `Foo` has no attribute `bar`"

## Test Plan

Mdtests and snapshots updated
This commit is contained in:
Alex Waygood 2025-10-19 10:58:25 +01:00 committed by GitHub
parent b6b96d75eb
commit 1f8297cfe6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 102 additions and 63 deletions

View file

@ -758,16 +758,16 @@ def _(flag: bool):
non_data: NonDataDescriptor = NonDataDescriptor()
data: DataDescriptor = DataDescriptor()
# error: [possibly-missing-attribute] "Attribute `non_data` on type `<class 'PossiblyUnbound'>` may be missing"
# error: [possibly-missing-attribute] "Attribute `non_data` may be missing on class `PossiblyUnbound`"
reveal_type(PossiblyUnbound.non_data) # revealed: int
# error: [possibly-missing-attribute] "Attribute `non_data` on type `PossiblyUnbound` may be missing"
# error: [possibly-missing-attribute] "Attribute `non_data` may be missing on object of type `PossiblyUnbound`"
reveal_type(PossiblyUnbound().non_data) # revealed: int
# error: [possibly-missing-attribute] "Attribute `data` on type `<class 'PossiblyUnbound'>` may be missing"
# error: [possibly-missing-attribute] "Attribute `data` may be missing on class `PossiblyUnbound`"
reveal_type(PossiblyUnbound.data) # revealed: int
# error: [possibly-missing-attribute] "Attribute `data` on type `PossiblyUnbound` may be missing"
# error: [possibly-missing-attribute] "Attribute `data` may be missing on object of type `PossiblyUnbound`"
reveal_type(PossiblyUnbound().data) # revealed: int
```