Commit Graph

13715 Commits

Author SHA1 Message Date
chiri
f0534e9cfd [refurb] Make fix unsafe if it deletes comments (FURB164) (#22667)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 08:47:00 -08:00
chiri
1813a7032c [refurb] Make fix unsafe if it deletes comments (FURB157) (#22668)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 08:42:53 -08:00
chiri
991c31d48a [refurb] Make fix unsafe if it deletes comments (FURB154) (#22669)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 08:41:21 -08:00
Brent Westbrook
5c441523e3 Preserve required parentheses in lambda bodies (#22747)
Summary
--

This PR fixes the issues revealed in #22744 by adding an additional
branch to
the lambda body formatting that checks if the body `needs_parentheses`
before
falling back on the `Parentheses::Never` case. I also updated the
`ExprNamed::needs_parentheses` implementation to match the one from
#8465.

Test Plan
--

New test based on the failing cases in #22744. I also checked out #22744
and
checked that the tests pass after applying the changes from this PR.
2026-01-20 10:28:29 -05:00
chiri
c1491a7a72 [flake8-simplify] Make fix unsafe if it deletes comments (SIM911) (#22661)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 10:15:46 -05:00
chiri
94ccbd28cf [refurb] Make fix unsafe if it deletes comments (FURB145) (#22670)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 10:07:05 -05:00
chiri
7b16239f29 [ruff] Make fix unsafe if it deletes comments (RUF020) (#22664)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-20 10:02:42 -05:00
Andrew Gallant
7e1f07e5c6 [ty] Add README for ty_completion_bench CLI tool 2026-01-20 09:37:39 -05:00
Andrew Gallant
9065ac051e [ty] Update completion eval
I didn't dig into where this change came from, but 1) it's a small
change and 2) this one tends to be noisy since there are so many things
that match `array`.
2026-01-20 09:37:39 -05:00
Andrew Gallant
8cda95dd60 [ty] Collect completions into a max-heap
The previous commits made this change deliciously simple. The key point
is that we don't collect a completion if it has no way of being ranked
into the top 1000 that we return.

Before:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 554.746713ms
total elapsed: 5.435318983s, time per completion request: 181.177299ms

After:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 526.743638ms
total elapsed: 4.268009725s, time per completion request: 142.26699ms
```

This is an especially nice speed-up for the cached case, where lots of
time (proportionally) was being spent sorting potentially a very large
list of completions.

There is potential future wins here. For example, every auto-import
completion has an `import` statement generated for it. We could instead
defer to that work until the very end when we convert the max-heap into
a `Vec`. Since before then, the completion might get dropped and there's
no point in doing extra work. But that will require more refactoring
(and possibly another `CompletionIntermediate` type? blech).
2026-01-20 09:37:39 -05:00
Andrew Gallant
e4f9df9b6e [ty] Truncate imports and qualifications derived from completions
This is effectively what's going to happen when we switch to a max-heap
for collecting completions. This commit isolates that behavioral change
to ensure nothing unexpected happens. (I generally wouldn't expect it
to, since that would imply that imports/qualifications care about
results beyond the first 1,000.)
2026-01-20 09:37:39 -05:00
Andrew Gallant
2784461741 [ty] Get rid of high-level completion deduplication
It turns out this wasn't actually doing much and was just papering over
the possibility of duplicates being returned from `SemanticModel`. So
this was doing a fair bit of work for no good reason.

Instead, we push deduplication down into semantic completions directly.
This will run over a (typically) much smaller number of completions.

With that said, this doesn't seem to lead to improvement in ad hoc
benchmarking. However, perf wasn't really the main motivation here: this
change is primarily to prep for switching to a max-heap. This
deduplication was problematic because it was being done *after* sorting,
which meant it dependend on having the entire set of completions in
memory. But with a max-heap, we'll only keep around the top-K
completions, so deduplication has to be done "earlier" (if at all).
2026-01-20 09:37:39 -05:00
Andrew Gallant
61abbb94e3 [ty] Refactor how we sort completions
This should be a non-behavior-changing commit that tweaks how we rank
completions. We now use a wrapper type and include the module name for
more precise sorting when relevance and symbol name are identical.

The purpose of this is to prepare the code to switch to a max-heap.
2026-01-20 09:37:39 -05:00
Andrew Gallant
1f6a87f770 [ty] Optimize collection of "all symbols"
Instead of locking and unlocking the mutex for every symbol,
we gather what we can and only lock the mutex after processing
a module.

Before:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 579.057075ms
total elapsed: 5.627666455s, time per completion request: 187.588881ms
```

After:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 565.911487ms
total elapsed: 5.254306446s, time per completion request: 175.143548ms
```

This is a very naive/simplistic "improvement." We can probably do
better.
2026-01-20 09:37:39 -05:00
Andrew Gallant
79741c59c9 [ty] Speed up completions by tweaking sorts
A surprising amount of time is spent sorting and comparing
completions. This commit does a very simple thing: it switches
the sorts to unstable and optimizes some comparisons to avoid
retrieving data we don't need for sorting.

Before:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 603.491595ms
total elapsed: 7.36554807s, time per completion request: 245.518269ms
```

After:

```
$ ./target/profiling/ty_completion_bench ~/astral/relatedclones/scratch-home-assistant/homeassistant/scratch.py 1 -q --iters 30
total elapsed for initial completions request: 570.040193ms
total elapsed: 5.740541847s, time per completion request: 191.351394ms
```
2026-01-20 09:37:39 -05:00
Andrew Gallant
c1b3641544 [ty] Add new ty_completion_bench for ad hoc benchmarking
This is mostly just a stripped down version of
`ty_completion_eval`. Basically, you point it at
a Python file, give it a byte offset and it does
the rest. It also lets one repeat the completion
request after the initial request for benchmarking
the cached case.
2026-01-20 09:37:39 -05:00
Andrew Gallant
c470335329 gitignore: ignore scratch directories in completion eval truth directory
It's sometimes useful to just create a scratch environment for ad hoc
testing.
2026-01-20 09:37:39 -05:00
Brent Westbrook
83ca28679a [pyupgrade] Allow shadowing non-builtin bindings (UP029) (#22749)
Summary
--

I thought the fix unsafety example in the [rule
docs](https://docs.astral.sh/ruff/rules/unnecessary-builtin-import/#fix-safety)
looked a bit suspicious
while I was going through more potential default rules today
([playground](https://play.ruff.rs/f1a8b73d-6277-4414-b918-44bbba2863c2)):

```py
def str(x):
    return x

from builtins import str

str(1)  # `"1"` with the import, `1` without
```

Changing the behavior in this way seemed to go beyond fix unsafety and
into bug
territory. Sure enough, there was an existing bug report in #16182.

This PR fixes #16182 (and the fix safety example) by checking that the
builtin
import that the rule flags is actually shadowing a builtin binding. I
also left
an exception for `from builtins import *`, but we could consider
ignoring that
case too.

I initially tried reusing `SemanticModel::resolve_name` and
`only_binding`, but
they are specific to `ExprName`s because that seems to be all that is
inserted
into the `SemanticModel::resolved_names` map.

Test Plan
--

New tests based on #16182 and the fix safety docs
2026-01-20 08:52:05 -05:00
Charlie Marsh
0a1dddbf73 [ty] Emit invalid type form for stringified annotations (#22752)
## Summary

Closes https://github.com/astral-sh/ty/issues/2553.
2026-01-20 08:37:55 +00:00
Alex Waygood
af886b06c9 [ty] Allow if type(x) is Y narrowing for types other than class-literal types (#22729)
## Summary

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

This PR adds support for `if type(x) is Y` narrowing where `Y` is a
subclass-of type, type-alias type, or typevar type.

## Test Plan

mdtests
2026-01-20 08:23:00 +00:00
Dhruv Manilawala
0cbe2af18b [ty] Add basic support for overloads in ParamSpec (#21946)
## Summary

fixes: https://github.com/astral-sh/ty/issues/1838

This PR adds basic support for overloaded function when used to
specialize a `ParamSpec` type variable.

Following cases are still remaining:
1. Updating the specialization with the matching overload after the
paramspec sub-call logic
2. Updating the specialization with the matching overload using the
return type

Both of these cases are present in the mdtest file.

## Test Plan

Update mdtest with new cases.
2026-01-20 04:14:05 +00:00
chiri
d4a01501c7 [ruff] Make fix unsafe if it deletes comments (RUF019) (#22663)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:21:08 -08:00
chiri
a49d8af14c [flake8-bugbear] Make fix unsafe if it deletes comments (B014) (#22659)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:09:39 -08:00
chiri
230e455e93 [flake8-bugbear] Make fix unsafe if it deletes comments (B013) (#22658)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 13:08:04 -05:00
chiri
21dd6029f5 [flake8-bugbear] Make fix unsafe if it deletes comments (B009) (#22656)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:02:02 -08:00
chiri
a4ded5941c [flake8-bugbear] Make fix unsafe if it deletes comments (B010) (#22657)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:00:55 -08:00
chiri
336413b2f3 [refurb] Make fix unsafe if it deletes comments (FURB116) (#22681)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-01-19 16:56:50 +00:00
chiri
2b9fed3bbd [FastAPI] Document fix safety for FAST001 (#22655)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 11:23:51 -05:00
Alex Waygood
de0189618f Bump the typing conformance workflow to use the latest python/typing commit (#22727) 2026-01-19 16:20:37 +00:00
Hugo
8fab35019b [ty] Fix panic on malformed mdtest assertion (#22724) 2026-01-19 15:56:42 +00:00
chiri
c5902a3cdb [refurb] Make fix unsafe if it deletes comments (FURB140) (#22679)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:33:18 -05:00
chiri
bffc95873d [refurb] Make fix unsafe if it deletes comments (FURB136) (#22680)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
2026-01-19 10:17:24 -05:00
Micha Reiser
2bc4756716 PIE794: Detect duplicated declared class fields (#22717) 2026-01-19 15:35:58 +01:00
Charlie Marsh
7f9b10a193 [ty] Narrow on bool and byte subscripts (#22684)
## Summary

Low-hanging fruit...
2026-01-19 14:31:38 +00:00
Alex Waygood
5949fa0b93 [ty] Improve readability of some NamedTuple code (#22723) 2026-01-19 14:10:22 +00:00
Charlie Marsh
2abaff046e [ty] Narrow on negative subscript indexing (#22682)
## Summary

Negative subscripts are also indicative of a thing being subcriptable:

```python
class Subscriptable:
    def __getitem__(self, key: int) -> int:
        return 42

class NotSubscriptable: ...

def _(x: list[Subscriptable | NotSubscriptable]):
    if not isinstance(x[-1], NotSubscriptable):
        # After narrowing, x[-1] excludes NotSubscriptable, which means subscripting works
        reveal_type(x[-1])  # revealed: Subscriptable & ~NotSubscriptable
        reveal_type(x[-1][0])  # revealed: int
```
2026-01-19 09:04:08 -05:00
Charlie Marsh
0793bfdb16 [ty] Avoid overload errors when detecting dataclass-on-tuple (#22687)
## Summary

Fixes some TODOs introduced in #22672 around cases like the following:


```python
from collections import namedtuple
from dataclasses import dataclass

NT = namedtuple("NT", "x y")

# error: [invalid-dataclass] "Cannot use `dataclass()` on a `NamedTuple` class"
dataclass(NT)
```

On main, `dataclass(NT)` emits `# error: [no-matching-overload]`
instead, which is wrong -- the overload does match! On main, the logic
proceeds as follows:

1. `dataclass` has two overloads:
  - `dataclass(cls: type[_T], ...) -> type[_T]`
  - `dataclass(cls: None = None, ...) -> Callable[[type[_T]], type[_T]]`
2. When `dataclass(NT)` is called:
- Arity check: Both overloads accept one positional argument, so both
pass.
- Type checking on first overload: `NT` matches `type[_T]`... but then
`invalid_dataclass_target()` runs and adds `InvalidDataclassApplication`
error
- Type checking on second overload: `NT` doesn't match `None`, so we
have a type error.
3. After type checking, both overloads have errors.
4. `matching_overload_index()` filters by
`overload.as_result().is_ok()`, which checks if `errors.is_empty()`.
Since both overloads have errors, neither matches...
5. We emit the "No overload matches arguments" error.

Instead, we now differentiate between non-matching errors, and errors
that occur when we _do_ match, but the call has some other semantic
failure.
2026-01-19 13:55:11 +00:00
Alex Waygood
aac0562c28 [ty] Fix the inferred MRO of functional namedtuple classes (#22722) 2026-01-19 13:48:51 +00:00
Charlie Marsh
52ce26bd41 [ty] Avoid reporting overload errors for successful union variants (#22688)
## Summary

Consider `x: str | bytes` and then `x.split(" ")`. Because we have a
union, and at least one variant errors (`bytes` expects a `Buffer`, not
a `str`), we call `binding.report_diagnostics` for each variant. For the
`str` variant, it has two overloads that both match arity, but only one
actually matches the signature... So
`matching_overload_before_type_checking` is `None` (because they both
match arity), but we don't actually have an error, and we fall through
to `NO_MATCHING_OVERLOAD`.

If one variant succeeds, we should avoid reporting errors for it, even
if not _all_ variants matched.
2026-01-19 08:40:31 -05:00
K900
ebc59e81f6 Skip EXE0xx tests on WSL (#22721) 2026-01-19 13:31:54 +00:00
Alex Waygood
9eff10c79f [ty] Use smallvec_inline! more consistently (#22720) 2026-01-19 13:29:01 +00:00
Alex Waygood
d19c962d5e [ty] Use fluent style more, and reduce allocations, when constructing Parameters instances (#22719) 2026-01-19 13:23:28 +00:00
Micha Reiser
55a174ed95 [ty] Update 'added-in' version of some rules (#22713) 2026-01-19 09:39:35 +01:00
Zanie Blue
bc05cc3c6f [ty] Cache ClassType::nearest_disjoint_base (#22065) 2026-01-19 09:22:53 +01:00
Micha Reiser
65b7fc9e73 [ty] Support overriding respect-type-ignore-comments (#22615) 2026-01-19 08:09:42 +00:00
renovate[bot]
c50863a0ee Update dependency pyright to v1.1.408 (#22696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2026-01-19 07:59:38 +00:00
renovate[bot]
d6e0b013ba Update prek dependencies (#22698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Co-authored-by: Micha Reiser <micha@reiser.io>
2026-01-19 07:50:15 +00:00
renovate[bot]
a226611724 Update taiki-e/install-action action to v2.66.1 (#22712) 2026-01-18 20:57:07 -05:00
renovate[bot]
9db3d704d8 Update dependency mdformat-mkdocs to v5.1.2 (#22695) 2026-01-18 20:56:56 -05:00
renovate[bot]
09c526e312 Update NPM Development dependencies (#22709) 2026-01-18 20:55:40 -05:00