Skip to content

Commit d462221

Browse files
committed
[ty] Support type:ignore[ty:code] suppressions
1 parent 1a2e402 commit d462221

13 files changed

Lines changed: 215 additions & 66 deletions

File tree

crates/ruff_benchmark/benches/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ fn datetype(criterion: &mut Criterion) {
989989
max_dep_date: "2025-07-04",
990990
python_version: PythonVersion::PY313,
991991
},
992-
4,
992+
10,
993993
);
994994

995995
bench_project(&benchmark, criterion);

crates/ruff_benchmark/benches/ty_walltime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ static ALTAIR: Benchmark = Benchmark::new(
109109
max_dep_date: "2025-06-17",
110110
python_version: PythonVersion::PY312,
111111
},
112-
860,
112+
897,
113113
);
114114

115115
static COLOUR_SCIENCE: Benchmark = Benchmark::new(

crates/ty/docs/rules.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty_ide/src/code_action.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,75 @@ mod tests {
161161
");
162162
}
163163

164+
#[test]
165+
fn add_code_existing_type_ignore() {
166+
let test = CodeActionTest::with_source(
167+
r#"
168+
b = <START>a<END> / 0 # type:ignore[ty:division-by-zero]
169+
"#,
170+
);
171+
172+
assert_snapshot!(test.code_actions(&UNRESOLVED_REFERENCE), @"
173+
info[code-action]: Ignore 'unresolved-reference' for this line
174+
--> main.py:2:5
175+
|
176+
2 | b = a / 0 # type:ignore[ty:division-by-zero]
177+
| ^
178+
|
179+
1 |
180+
- b = a / 0 # type:ignore[ty:division-by-zero]
181+
2 + b = a / 0 # type:ignore[ty:division-by-zero, ty:unresolved-reference]
182+
");
183+
}
184+
185+
#[test]
186+
fn add_code_existing_type_ignore_without_any_ty_code() {
187+
let test = CodeActionTest::with_source(
188+
r#"
189+
b = <START>a<END> / 0 # type:ignore[mypy-code]
190+
"#,
191+
);
192+
193+
assert_snapshot!(test.code_actions(&UNRESOLVED_REFERENCE), @"
194+
info[code-action]: Ignore 'unresolved-reference' for this line
195+
--> main.py:2:5
196+
|
197+
2 | b = a / 0 # type:ignore[mypy-code]
198+
| ^
199+
|
200+
1 |
201+
- b = a / 0 # type:ignore[mypy-code]
202+
2 + b = a / 0 # type:ignore[mypy-code] # ty:ignore[unresolved-reference]
203+
");
204+
}
205+
206+
#[test]
207+
fn add_ignore_existing_file_level_ignore() {
208+
let test = CodeActionTest::with_source(
209+
r#"
210+
# ty:ignore[division-by-zero]
211+
212+
b = <START>a<END> / 0
213+
"#,
214+
);
215+
216+
assert_snapshot!(test.code_actions(&UNRESOLVED_REFERENCE), @"
217+
info[code-action]: Ignore 'unresolved-reference' for this line
218+
--> main.py:4:5
219+
|
220+
2 | # ty:ignore[division-by-zero]
221+
3 |
222+
4 | b = a / 0
223+
| ^
224+
|
225+
1 |
226+
2 | # ty:ignore[division-by-zero]
227+
3 |
228+
- b = a / 0
229+
4 + b = a / 0 # ty:ignore[unresolved-reference]
230+
");
231+
}
232+
164233
#[test]
165234
fn add_code_existing_ignore_trailing_comma() {
166235
let test = CodeActionTest::with_source(

crates/ty_python_semantic/resources/mdtest/mro.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,15 @@ the class "header":
507507

508508
class A: ...
509509

510-
class B( # type: ignore[duplicate-base]
510+
class B( # type: ignore[ty:duplicate-base]
511511
A,
512512
A,
513513
): ...
514514

515515
class C(
516516
A,
517517
A
518-
): # type: ignore[duplicate-base]
518+
): # type: ignore[ty:duplicate-base]
519519
x: int
520520

521521
# fmt: on
@@ -532,7 +532,7 @@ exception at runtime, not a sub-expression in the class's bases list.
532532
class D(
533533
A,
534534
# error: [unused-type-ignore-comment]
535-
A, # type: ignore[duplicate-base]
535+
A, # type: ignore[ty:duplicate-base]
536536
): ...
537537

538538
# error: [duplicate-base]
@@ -541,7 +541,7 @@ class E(
541541
A
542542
):
543543
# error: [unused-type-ignore-comment]
544-
x: int # type: ignore[duplicate-base]
544+
x: int # type: ignore[ty:duplicate-base]
545545

546546
# fmt: on
547547
```

crates/ty_python_semantic/resources/mdtest/snapshots/mro.md_-_Method_Resolution_Or…_-_`__bases__`_lists_wi…_(ea7ebc83ec359b54).snap

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
6666
51 |
6767
52 | class A: ...
6868
53 |
69-
54 | class B( # type: ignore[duplicate-base]
69+
54 | class B( # type: ignore[ty:duplicate-base]
7070
55 | A,
7171
56 | A,
7272
57 | ): ...
7373
58 |
7474
59 | class C(
7575
60 | A,
7676
61 | A
77-
62 | ): # type: ignore[duplicate-base]
77+
62 | ): # type: ignore[ty:duplicate-base]
7878
63 | x: int
7979
64 |
8080
65 | # fmt: on
@@ -84,7 +84,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
8484
69 | class D(
8585
70 | A,
8686
71 | # error: [unused-type-ignore-comment]
87-
72 | A, # type: ignore[duplicate-base]
87+
72 | A, # type: ignore[ty:duplicate-base]
8888
73 | ): ...
8989
74 |
9090
75 | # error: [duplicate-base]
@@ -93,7 +93,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
9393
78 | A
9494
79 | ):
9595
80 | # error: [unused-type-ignore-comment]
96-
81 | x: int # type: ignore[duplicate-base]
96+
81 | x: int # type: ignore[ty:duplicate-base]
9797
82 |
9898
83 | # fmt: on
9999
```
@@ -281,7 +281,7 @@ error[duplicate-base]: Duplicate base class `A`
281281
| _______^
282282
70 | | A,
283283
71 | | # error: [unused-type-ignore-comment]
284-
72 | | A, # type: ignore[duplicate-base]
284+
72 | | A, # type: ignore[ty:duplicate-base]
285285
73 | | ): ...
286286
| |_^
287287
74 |
@@ -295,7 +295,7 @@ info: The definition of class `D` will raise `TypeError` at runtime
295295
70 | A,
296296
| - Class `A` first included in bases list here
297297
71 | # error: [unused-type-ignore-comment]
298-
72 | A, # type: ignore[duplicate-base]
298+
72 | A, # type: ignore[ty:duplicate-base]
299299
| ^ Class `A` later repeated here
300300
73 | ): ...
301301
|
@@ -304,20 +304,20 @@ info: rule `duplicate-base` is enabled by default
304304
```
305305
306306
```
307-
warning[unused-type-ignore-comment]: Unused blanket `type: ignore` directive
307+
warning[unused-type-ignore-comment]: Unused `type: ignore` directive
308308
--> src/mdtest_snippet.py:72:9
309309
|
310310
70 | A,
311311
71 | # error: [unused-type-ignore-comment]
312-
72 | A, # type: ignore[duplicate-base]
313-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
312+
72 | A, # type: ignore[ty:duplicate-base]
313+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
314314
73 | ): ...
315315
|
316316
help: Remove the unused suppression comment
317317
69 | class D(
318318
70 | A,
319319
71 | # error: [unused-type-ignore-comment]
320-
- A, # type: ignore[duplicate-base]
320+
- A, # type: ignore[ty:duplicate-base]
321321
72 + A,
322322
73 | ): ...
323323
74 |
@@ -337,7 +337,7 @@ error[duplicate-base]: Duplicate base class `A`
337337
79 | | ):
338338
| |_^
339339
80 | # error: [unused-type-ignore-comment]
340-
81 | x: int # type: ignore[duplicate-base]
340+
81 | x: int # type: ignore[ty:duplicate-base]
341341
|
342342
info: The definition of class `E` will raise `TypeError` at runtime
343343
--> src/mdtest_snippet.py:77:5
@@ -356,21 +356,21 @@ info: rule `duplicate-base` is enabled by default
356356
```
357357
358358
```
359-
warning[unused-type-ignore-comment]: Unused blanket `type: ignore` directive
359+
warning[unused-type-ignore-comment]: Unused `type: ignore` directive
360360
--> src/mdtest_snippet.py:81:13
361361
|
362362
79 | ):
363363
80 | # error: [unused-type-ignore-comment]
364-
81 | x: int # type: ignore[duplicate-base]
365-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
364+
81 | x: int # type: ignore[ty:duplicate-base]
365+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
366366
82 |
367367
83 | # fmt: on
368368
|
369369
help: Remove the unused suppression comment
370370
78 | A
371371
79 | ):
372372
80 | # error: [unused-type-ignore-comment]
373-
- x: int # type: ignore[duplicate-base]
373+
- x: int # type: ignore[ty:duplicate-base]
374374
81 + x: int
375375
82 |
376376
83 | # fmt: on
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
source: crates/ty_test/src/lib.rs
3+
expression: snapshot
4+
---
5+
6+
---
7+
mdtest name: type_ignore.md - Suppressing errors with `type: ignore` - Unused ignore comment mixed with mypy comments
8+
mdtest path: crates/ty_python_semantic/resources/mdtest/suppressions/type_ignore.md
9+
---
10+
11+
# Python source files
12+
13+
## mdtest_snippet.py
14+
15+
```
16+
1 | # error: [unused-type-ignore-comment] "Unused `type: ignore` directive: 'division-by-zero'"
17+
2 | a = 10 / 2 # type: ignore[mypy-code, ty:division-by-zero]
18+
```
19+
20+
# Diagnostics
21+
22+
```
23+
warning[unused-type-ignore-comment]: Unused `type: ignore` directive: 'division-by-zero'
24+
--> src/mdtest_snippet.py:2:39
25+
|
26+
1 | # error: [unused-type-ignore-comment] "Unused `type: ignore` directive: 'division-by-zero'"
27+
2 | a = 10 / 2 # type: ignore[mypy-code, ty:division-by-zero]
28+
| ^^^^^^^^^^^^^^^^^^^
29+
|
30+
help: Remove the unused suppression code
31+
1 | # error: [unused-type-ignore-comment] "Unused `type: ignore` directive: 'division-by-zero'"
32+
- a = 10 / 2 # type: ignore[mypy-code, ty:division-by-zero]
33+
2 + a = 10 / 2 # type: ignore[mypy-code]
34+
35+
```

crates/ty_python_semantic/resources/mdtest/suppressions/ty_ignore.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,13 @@ a = 4 / 0 # ty: ignore[]
167167

168168
## File-level suppression comments
169169

170-
File level suppression comments are currently intentionally unsupported because we've yet to decide
171-
if they should use a different syntax that also supports enabling rules or changing the rule's
172-
severity: `ty: possibly-undefined-reference=error`
170+
File level suppression comments suppress all errors in a file with a given code.
173171

174172
```py
175-
# error: [unused-ignore-comment]
176173
# ty: ignore[division-by-zero]
177174

178-
a = 4 / 0 # error: [division-by-zero]
175+
a = 4 / 0
176+
b = a + c # error: [unresolved-reference]
179177
```
180178

181179
## Unknown rule

crates/ty_python_semantic/resources/mdtest/suppressions/type_ignore.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,19 @@ a = f"""
132132

133133
## Codes
134134

135-
Mypy supports `type: ignore[code]`. ty doesn't understand mypy's rule names. Therefore, ignore the
136-
codes and suppress all errors.
135+
Similar to mypy support `type: ignore[codes]` comments. But unlike mypy, ty only respects codes
136+
starting with `ty:` to avoid ambiguity with suppression comments from mypy and other type checkers.
137137

138138
```py
139-
a = test # type: ignore[name-defined]
139+
a = test # type: ignore[name-defined, ty:unresolved-reference]
140+
```
141+
142+
## Unknown codes starting with `ty`
143+
144+
```py
145+
# error: [unresolved-reference]
146+
# error: [ignore-comment-unknown-rule]
147+
a = test # type: ignore[ty:name-defined]
140148
```
141149

142150
## Nested comments
@@ -190,6 +198,15 @@ a = 10 / 0
190198
b = a / 0
191199
```
192200

201+
## File level suppression with code
202+
203+
```py
204+
# type: ignore[ty:division-by-zero]
205+
206+
a = 10 / 0
207+
b = a + c # error: [unresolved-reference]
208+
```
209+
193210
## File level suppression with leading shebang
194211

195212
```py
@@ -242,3 +259,26 @@ ty doesn't report invalid `type: ignore` comments:
242259
```py
243260
a = 10 + 4 # type: ignoreee
244261
```
262+
263+
## Unused ignore comment mixed with mypy comments
264+
265+
<!-- snapshot-diagnostics -->
266+
267+
```py
268+
# error: [unused-type-ignore-comment] "Unused `type: ignore` directive: 'division-by-zero'"
269+
a = 10 / 2 # type: ignore[mypy-code, ty:division-by-zero]
270+
```
271+
272+
## Unused ignore comment
273+
274+
```py
275+
# error: [unused-type-ignore-comment] "Unused `type: ignore` directive"
276+
a = 10 / 2 # type: ignore[ty:division-by-zero]
277+
```
278+
279+
## Unknown ignore code
280+
281+
```py
282+
# error: [ignore-comment-unknown-rule] "Unknown rule `division-by`. Did you mean"
283+
a = 10 / 2 # type: ignore[ty:division-by]
284+
```

0 commit comments

Comments
 (0)