Commit Graph

166 Commits

Author SHA1 Message Date
Luca Chiodini 5a9d6a91ea
[ty] Uniformly use "not supported" in diagnostics (#21916) 2025-12-11 15:03:55 +00:00
Jack O'Connor 1b44d7e2a7
[ty] add `SyntheticTypedDictType` and implement `normalized` and `is_equivalent_to` (#21784) 2025-12-10 20:36:36 +00:00
Ibraheem Ahmed ff7086d9ad
[ty] Infer type of implicit `cls` parameter in method bodies (#21685)
## Summary

Extends https://github.com/astral-sh/ruff/pull/20922 to infer
unannotated `cls` parameters as `type[Self]` in method bodies.

Part of https://github.com/astral-sh/ty/issues/159.
2025-12-10 10:31:28 +01:00
Alex Waygood 48f7f42784
[ty] Minor improvements to `assert_type` diagnostics (#21811) 2025-12-05 12:33:30 +00:00
Alex Waygood 14fce0d440
[ty] Improve the display of various special-form types (#21775) 2025-12-03 21:19:59 +00:00
Alex Waygood 8ebecb2a88
[ty] Add subdiagnostic hint if the user wrote `X = Any` rather than `X: Any` (#21777) 2025-12-03 20:42:21 +00:00
github-actions[bot] b08f0b2caa
[ty] Sync vendored typeshed stubs (#21715)
Co-authored-by: typeshedbot <>
Co-authored-by: David Peter <mail@david-peter.de>
2025-12-03 15:49:51 +00:00
Alex Waygood cd079bd92e
[ty] Improve `@override`, `@final` and Liskov checks in cases where there are multiple reachable definitions (#21767) 2025-12-03 12:51:36 +00:00
Alex Waygood 5756b3809c
[ty] Extend `invalid-explicit-override` to also cover properties decorated with `@override` that do not override anything (#21756) 2025-12-03 11:27:47 +00:00
Alex Waygood 392a8e4e50
[ty] Improve diagnostics for unsupported comparison operations (#21737) 2025-12-02 19:58:45 +00:00
Alex Waygood 3a11e714c6
[ty] Show the user where the type variable was defined in `invalid-type-arguments` diagnostics (#21727) 2025-12-01 12:25:49 +00:00
Alex Waygood a2096ee2cb
[ty] Emit `invalid-named-tuple` on namedtuple classes that have field names starting with underscores (#21697) 2025-12-01 11:36:02 +00:00
Alex Waygood b02e8212c9
[ty] Don't introduce invalid syntax when autofixing override-of-final-method (#21699) 2025-11-30 13:40:33 +00:00
Alex Waygood 594b7b04d3
[ty] Preserve quoting style when autofixing `TypedDict` keys (#21682) 2025-11-28 18:40:34 +00:00
Alex Waygood 8bcfc198b8
[ty] Implement `typing.final` for methods (#21646)
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-11-28 15:18:02 +00:00
Ibraheem Ahmed 3ed537e9f1
[ty] Support `type[T]` with type variables (#21650)
## Summary

Adds support for `type[T]`, where `T` is a type variable.

- Resolves https://github.com/astral-sh/ty/issues/501
- Resolves https://github.com/astral-sh/ty/issues/783
- Resolves https://github.com/astral-sh/ty/issues/662
2025-11-28 09:20:24 +01:00
Alex Waygood aef2fad0c5
[ty] Add IDE autofixes for two "Did you mean...?" suggestions (#21667) 2025-11-27 18:20:02 +00:00
Alex Waygood a7d48ffd40
[ty] Add subdiagnostic hint if a variable with type `Never` is used in a type expression (#21660) 2025-11-27 12:48:18 +00:00
Alex Waygood 81c97e9e94
[ty] Implement `typing.override` (#21627)
## Summary

Part of https://github.com/astral-sh/ty/issues/155. This implements the
basic check (`@override`-decorated methods should override things!), but
not the strict check specified in
https://typing.python.org/en/latest/spec/class-compat.html#strict-enforcement-per-project,
which should be a separate error code.

## Test Plan

mdtests and snapshots

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-11-25 10:42:40 -08:00
Ibraheem Ahmed 294f863523
[ty] Avoid expression reinference for diagnostics (#21267)
## Summary

We now use the type context for a lot of things, so re-inferring without
type context actually makes diagnostics more confusing (in most cases).
2025-11-25 09:24:00 -08:00
Micha Reiser 15cb41c1f9
[ty] Add 'remove unused ignore comment' code action (#21582)
## Summary

This PR adds a code action to remove unused ignore comments.

This PR also includes some infrastructure boilerplate to set up code
actions in the editor:

* Extend `snapshot-diagnostics` to render fixes
* Render fixes when using `--output-format=full`
* Hook up edits and the code action request in the LSP
* Add the `Unnecessary` tag to `unused-ignore-comment` diagnostics
* Group multiple unused codes into a single diagnostic

The same fix can be used on the CLI once we add `ty fix` 

Note: `unused-ignore-comment` is currently disabled by default.


https://github.com/user-attachments/assets/f9e21087-3513-4156-85d7-a90b1a7a3489
2025-11-25 08:08:21 -05:00
Alex Waygood b19ddca69b
[ty] Improve several "Did you mean?" suggestions (#21597) 2025-11-25 10:29:01 +00:00
Alex Waygood adf095e889
[ty] Extend Liskov checks to also cover classmethods and staticmethods (#21598)
## Summary

Building on https://github.com/astral-sh/ruff/pull/21436.

There's nothing conceptually more complicated about this, it just
requires its own set of tests and its own subdiagnostic hint.

I also uncovered another inconsistency between mypy/pyright/pyrefly,
which is fun. In this case, I suggest we go with pyright's behaviour.

## Test Plan

mdtests/snapshots
2025-11-24 23:14:06 +00:00
Alex Waygood 0c6d652b5f
[ty] Switch the error code from `unresolved-attribute` to `possibly-missing-attribute` for submodules that may not be available (#21618) 2025-11-24 19:15:45 +00:00
Alex Waygood a57e291311
[ty] Add hint about resolved Python version when a user attempts to import a member added on a newer version (#21615)
## Summary

Fixes https://github.com/astral-sh/ty/issues/1620. #20909 added hints if
you do something like this and your Python version is set to 3.10 or
lower:

```py
import typing

typing.LiteralString
```

And we also have hints if you try to do something like this and your
Python version is set too low:

```py
from stdlib_module import new_submodule
```

But we don't currently have any subdiagnostic hint if you do something
like _this_ and your Python version is set too low:

```py
from typing import LiteralString
```

This PR adds that hint!

## Test Plan

snapshots

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
2025-11-24 15:12:01 +00:00
Alex Waygood e642874cf1
[ty] Check method definitions on subclasses for Liskov violations (#21436) 2025-11-23 18:08:15 +00:00
Micha Reiser d24c891a4b
[ty] Fix rendering of unused suppression diagnostic (#21580) 2025-11-22 18:42:56 +01:00
Alex Waygood 3410041b4c
[ty] Improve diagnostics when a submodule is not available as an attribute on a module-literal type (#21561) 2025-11-22 14:07:48 +00:00
Alex Waygood 54dba15088
[ty] Improve debug messages when imports fail (#21555) 2025-11-21 13:45:57 +00:00
Alex Waygood 6178822427
[ty] Attach subdiagnostics to `unresolved-import` errors for relative imports as well as absolute imports (#21554) 2025-11-21 12:40:53 +00:00
Jack O'Connor eb7c098d6b
[ty] implement `TypedDict` structural assignment (#21467)
Closes https://github.com/astral-sh/ty/issues/1387.
2025-11-20 13:15:28 -08:00
Alex Waygood a8f7ccf2ca
[ty] Improve diagnostics when `NotImplemented` is called (#21523)
## Summary

Fixes https://github.com/astral-sh/ty/issues/1571.

I realised I was overcomplicating things when I described what we should
do in that issue description. The simplest thing to do here is just to
special-case call expressions and short-circuit the call-binding
machinery entirely if we see it's `NotImplemented` being called. It
doesn't really matter if the subdiagnostic doesn't fire when a union is
called and one element of the union is `NotImplemented` -- the
subdiagnostic doesn't need to be exhaustive; it's just to help people in
some common cases.

## Test Plan

Added snapshots
2025-11-19 19:27:12 +00:00
David Peter 5ca9c15fc8
[ty] Better invalid-assignment diagnostics (#21476)
## Summary

Improve the diagnostic range for `invalid-assignment` diagnostics, and
add source annotations for the value and target type.

closes https://github.com/astral-sh/ty/issues/1556

### Before

<img width="836" height="601" alt="image"
src="https://github.com/user-attachments/assets/a48219bb-58a8-4a83-b290-d09ef50ce5f0"
/>

### After

<img width="857" height="742" alt="image"
src="https://github.com/user-attachments/assets/cfcaa4f4-94fb-459e-8d64-97050dfecb50"
/>

## Ecosystem impact

Very good! Due to the wider diagnostic range, we now pick up more `#
type: ignore` directives that were supposed to suppress an invalid
assignment diagnostic.

## Test Plan

New snapshot tests
2025-11-18 14:31:04 +01:00
David Peter 7a739d6b76
[ty] Custom concise diagnostic messages (#21498)
## Summary

This PR proposes that we add a new `set_concise_message` functionality
to our `Diagnostic` construction API. When used, the concise message
that is otherwise auto-generated from the main diagnostic message and
the primary annotation will be overwritten with the custom message.

To understand why this is desirable, let's look at the `invalid-key`
diagnostic. This is how I *want* the full diagnostic to look like:

<img width="620" height="282" alt="image"
src="https://github.com/user-attachments/assets/3bf70f52-9d9f-4817-bc16-fb0ebf7c2113"
/>

However, without the change in this PR, the concise message would have
the following form:

```
error[invalid-key]: Unknown key "Age" for TypedDict `Person`: Unknown key "Age" - did you mean "age"?
```

This duplication is why the full `invalid-key` diagnostic used a main
diagnostic message that is only "Invalid key for TypedDict `Person`", to
make that bearable:

```
error[invalid-key] Invalid key for TypedDict `Person`: Unknown key "Age" - did you mean "age"?
```

This is still less than ideal, *and* we had to make the "full"
diagnostic worse. With the new API here, we have to make no such
compromises. We need to do slightly more work (provide one additional
custom-designed message), but we get to keep the "full" diagnostic that
we actually want, and we can make the concise message more terse and
readable:

```
error[invalid-key] Unknown key "Age" for TypedDict `Person` - did you mean "age"?
```

Similar problems exist for other diagnostics as well (I really want this
for https://github.com/astral-sh/ruff/pull/21476). In this PR, I only
changed `invalid-key` and `type-assertion-failure`.

The PR here is somewhat related to the discussion in
https://github.com/astral-sh/ty/issues/1418, but note that we are
solving a problem that is unrelated to sub-diagnostics.

## Test Plan

Updated tests
2025-11-18 09:35:40 +01:00
David Peter 1a86e13472
[ty] Subscript assignment diagnostics follow-up (#21452)
## Summary

Follow up from https://github.com/astral-sh/ruff/pull/21411. Again,
there are more things that could be improved here (like the diagnostics
for `lists`, or extending what we have for `dict` to `OrderedDict` etc),
but that will have to be postponed.
2025-11-17 11:14:58 +00:00
Alex Waygood 3065f8dbbc
[ty] Improve diagnostics for invalid exceptions (#21475)
## Summary

Not a high-priority task... but it _is_ a weekend :P

This PR improves our diagnostics for invalid exceptions. Specifically:
- We now give a special-cased ``help: Did you mean
`NotImplementedError`` subdiagnostic for `except NotImplemented`, `raise
NotImplemented` and `raise <EXCEPTION> from NotImplemented`
- If the user catches a tuple of exceptions (`except (foo, bar, baz):`)
and multiple elements in the tuple are invalid, we now collect these
into a single diagnostic rather than emitting a separate diagnostic for
each tuple element
- The explanation of why the `except`/`raise` was invalid ("must be a
`BaseException` instance or `BaseException` subclass", etc.) is
relegated to a subdiagnostic. This makes the top-level diagnostic
summary much more concise.

## Test Plan

Lots of snapshots. And here's some screenshots:

<details>
<summary>Screenshots</summary>

<img width="1770" height="1520" alt="image"
src="https://github.com/user-attachments/assets/7f27fd61-c74d-4ddf-ad97-ea4fd24d06fd"
/>

<img width="1916" height="1392" alt="image"
src="https://github.com/user-attachments/assets/83e5027c-8798-48a6-a0ec-1babfc134000"
/>

<img width="1696" height="588" alt="image"
src="https://github.com/user-attachments/assets/1bc16048-6eb4-4dfa-9ace-dd271074530f"
/>

</details>
2025-11-15 22:12:00 +00:00
github-actions[bot] efa2b5167f
[ty] Sync vendored typeshed stubs (#21466)
Co-authored-by: typeshedbot <>
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2025-11-15 17:12:32 +00:00
Alex Waygood d63b4b0383
[ty] Improve diagnostic range for `non-subscriptable` diagnostics (#21461)
## Summary

Currently our diagnostic only covers the range of the thing being
subscripted:

<img width="1702" height="312" alt="image"
src="https://github.com/user-attachments/assets/7e630431-e846-46ca-93c1-139f11aaba11"
/>

But it should probably cover the _whole_ subscript expression (arguably
the more "incorrect" bit is the `["foo"]` part of this expression, not
the `x` part of this expression!)

## Test Plan

Added a snapshot

Co-authored-by: Brent Westbrook
<36778786+ntBre@users.noreply.github.com>
2025-11-14 21:15:14 +00:00
Bhuminjay Soni 8529d79a70
[ty] name is parameter and global is a syntax error (#21312)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-11-14 18:15:34 +00:00
David Peter 04ab9170d6
[ty] Further improve subscript assignment diagnostics (#21411)
## Summary

Further improve subscript assignment diagnostics, especially for
`dict`s:

```py
config: dict[str, int] = {}

config["retries"] = "three"
```

<img width="1276" height="274" alt="image"
src="https://github.com/user-attachments/assets/9762c733-8d1c-4a57-8c8a-99825071dc7d"
/>

I have many more ideas, but this looks like a reasonable first step.
Thank you @AlexWaygood for some of the suggestions here.

## Test Plan

Update tests
2025-11-13 13:31:14 +01:00
David Peter 2f6f3e1042
[ty] Faster subscript assignment checks for (unions of) `TypedDict`s (#21378)
## Summary

We synthesize a (potentially large) set of `__setitem__` overloads for
every item in a `TypedDict`. Previously, validation of subscript
assignments on `TypedDict`s relied on actually calling `__setitem__`
with the provided key and value types, which implied that we needed to
do the full overload call evaluation for this large set of overloads.
This PR improves the performance of subscript assignment checks on
`TypedDict`s by validating the assignment directly instead of calling
`__setitem__`.

This PR also adds better handling for assignments to subscripts on union
and intersection types (but does not attempt to make it perfect). It
achieves this by distributing the check over unions and intersections,
instead of calling `__setitem__` on the union/intersection directly. We
already do something similar when validating *attribute* assignments.

## Ecosystem impact

* A lot of diagnostics change their rule type, and/or split into
multiple diagnostics. The new version is more verbose, but easier to
understand, in my opinion
* Almost all of the invalid-key diagnostics come from pydantic, and they
should all go away (including many more) when we implement
https://github.com/astral-sh/ty/issues/1479
* Everything else looks correct to me. There may be some new diagnostics
due to the fact that we now check intersections.

## Test Plan

New Markdown tests.
2025-11-12 20:16:38 +01:00
David Peter 84c3cecad6
[ty] Baseline for subscript assignment diagnostics (#21404)
## Summary

Add (snapshot) tests for subscript assignment diagnostics. This is
mainly intended to establish a baseline before I hope to improve some of
these messages.
2025-11-12 15:29:26 +01:00
Jack O'Connor 5f3e086ee4 [ty] implement `typing.NewType` by adding `Type::NewTypeInstance` 2025-11-10 14:55:47 -08:00
David Peter 238f151371
[ty] Add support for `Optional` and `Annotated` in implicit type aliases (#21321)
## Summary

Add support for `Optional` and `Annotated` in implicit type aliases

part of https://github.com/astral-sh/ty/issues/221

## Typing conformance changes

New expected diagnostics.

## Ecosystem

A lot of true positives, some known limitations unrelated to this PR.

## Test Plan

New Markdown tests
2025-11-10 10:24:38 +01:00
Alex Waygood 73b1fce74a
[ty] Add diagnostics for `isinstance()` and `issubclass()` calls that use invalid PEP-604 unions for their second argument (#21343)
## Summary

This PR adds extra validation for `isinstance()` and `issubclass()`
calls that use `UnionType` instances for their second argument.
According to typeshed's annotations, any `UnionType` is accepted for the
second argument, but this isn't true at runtime: at runtime, all
elements in the `UnionType` must either be class objects or be `None` in
order for the `isinstance()` or `issubclass()` call to reliably succeed:

```pycon
% uvx python3.14                            
Python 3.14.0 (main, Oct 10 2025, 12:54:13) [Clang 20.1.4 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import LiteralString
>>> import types
>>> type(LiteralString | int) is types.UnionType
True
>>> isinstance(42, LiteralString | int)
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    isinstance(42, LiteralString | int)
    ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/alexw/Library/Application Support/uv/python/cpython-3.14.0-macos-aarch64-none/lib/python3.14/typing.py", line 559, in __instancecheck__
    raise TypeError(f"{self} cannot be used with isinstance()")
TypeError: typing.LiteralString cannot be used with isinstance()
```

## Test Plan

Added mdtests/snapshots
2025-11-10 08:46:31 +00:00
Ibraheem Ahmed 3c8fb68765
[ty] `dict` is not assignable to `TypedDict` (#21238)
## Summary

A lot of the bidirectional inference work relies on `dict` not being
assignable to `TypedDict`, so I think it makes sense to add this before
fully implementing https://github.com/astral-sh/ty/issues/1387.
2025-11-03 16:57:49 -05:00
Carl Meyer 3179b05221
[ty] don't assume in diagnostic messages that a TypedDict key error is about subscript access (#21166)
## Summary

Before this PR, we would emit diagnostics like "Invalid key access" for
a TypedDict literal with invalid key, which doesn't make sense since
there's no "access" in that case. This PR just adjusts the wording to be
more general, and adjusts the documentation of the lint rule too.

I noticed this in the playground and thought it would be a quick fix. As
usual, it turned out to be a bit more subtle than I expected, but for
now I chose to punt on the complexity. We may ultimately want to have
different rules for invalid subscript vs invalid TypedDict literal,
because an invalid key in a TypedDict literal is low severity: it's a
typo detector, but not actually a type error. But then there's another
wrinkle there: if the TypedDict is `closed=True`, then it _is_ a type
error. So would we want to separate the open and closed cases into
separate rules, too? I decided to leave this as a question for future.

If we wanted to use separate rules, or use specific wording for each
case instead of the generalized wording I chose here, that would also
involve a bit of extra work to distinguish the cases, since we use a
generic set of functions for reporting these errors.

## Test Plan

Added and updated mdtests.
2025-10-31 10:49:59 -04:00
David Peter 5139f76d1f
[ty] Infer type of `self` for decorated methods and properties (#21123)
## Summary

Infer a type of unannotated `self` parameters in decorated methods /
properties.

closes https://github.com/astral-sh/ty/issues/1448

## Test Plan

Existing tests, some new tests.
2025-10-29 21:22:38 +00:00
Alex Waygood db0e921db1
[ty] Fix bug where ty would think all types had an `__mro__` attribute (#20995) 2025-10-27 11:19:12 +00:00
Alex Waygood dab3d4e917
[ty] Improve `invalid-argument-type` diagnostics where a union type was provided (#21044) 2025-10-23 13:16:21 +00:00