Skip to content

Commit abb3c6e

Browse files
authored
[flake8-pyi] Avoid rewriting invalid type expressions in unnecessary-type-union (PYI055) (#14660)
1 parent 224fe75 commit abb3c6e

File tree

5 files changed

+92
-68
lines changed

5 files changed

+92
-68
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
t: type[int] | type[str] | type[float]
66
u: builtins.type[int] | type[str] | builtins.type[complex]
77
v: Union[type[float], type[complex]]
8-
w: Union[type[float, int], type[complex]]
9-
x: Union[Union[type[float, int], type[complex]]]
10-
y: Union[Union[Union[type[float, int], type[complex]]]]
11-
z: Union[type[complex], Union[Union[type[float, int]]]]
8+
w: Union[type[float | int], type[complex]]
9+
x: Union[Union[type[Union[float, int]], type[complex]]]
10+
y: Union[Union[Union[type[float | int], type[complex]]]]
11+
z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
1212

1313

1414
def func(arg: type[int] | str | type[float]) -> None:
1515
...
1616

1717

1818
# OK
19-
x: type[int, str, float]
20-
y: builtins.type[int, str, complex]
19+
x: type[int | str | float]
20+
y: builtins.type[int | str | complex]
2121
z: Union[float, complex]
2222

2323

@@ -68,3 +68,11 @@ def convert_union(union: UnionType) -> _T | None:
6868
Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055
6969
] = union.__args__
7070
...
71+
72+
73+
# `type[float, int]`` is not valid, use `type[float|int]` or `type[Union[float, int]]`
74+
# OK for PYI055, should be covered by another check.
75+
a: Union[type[float, int], type[complex]]
76+
b: Union[Union[type[float, int], type[complex]]]
77+
c: Union[Union[Union[type[float, int], type[complex]]]]
78+
d: Union[type[complex], Union[Union[type[float, int]]]]

crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi

+13-6
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ s: builtins.type[int] | builtins.type[str] | builtins.type[complex]
55
t: type[int] | type[str] | type[float]
66
u: builtins.type[int] | type[str] | builtins.type[complex]
77
v: Union[type[float], type[complex]]
8-
w: Union[type[float, int], type[complex]]
9-
x: Union[Union[type[float, int], type[complex]]]
10-
y: Union[Union[Union[type[float, int], type[complex]]]]
11-
z: Union[type[complex], Union[Union[type[float, int]]]]
8+
w: Union[type[Union[float, int]], type[complex]]
9+
x: Union[Union[type[Union[float, int]], type[complex]]]
10+
y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
11+
z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
1212

1313
def func(arg: type[int] | str | type[float]) -> None: ...
1414

1515
# OK
16-
x: type[int, str, float]
17-
y: builtins.type[int, str, complex]
16+
x: type[int | str | float]
17+
y: builtins.type[int | str | complex]
1818
z: Union[float, complex]
1919

2020
def func(arg: type[int, float] | str) -> None: ...
@@ -29,3 +29,10 @@ def func():
2929
item3: Union[ # comment
3030
type[requests_mock.Mocker], # another comment
3131
type[httpretty], type[str]] = requests_mock.Mocker
32+
33+
34+
# OK
35+
w: Union[type[float, int], type[complex]]
36+
x: Union[Union[type[float, int], type[complex]]]
37+
y: Union[Union[Union[type[float, int], type[complex]]]]
38+
z: Union[type[complex], Union[Union[type[float, int]]]]

crates/ruff_linter/src/rules/flake8_pyi/rules/unnecessary_type_union.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr)
8989
}
9090
match expr {
9191
Expr::Subscript(ast::ExprSubscript { slice, value, .. }) => {
92-
if semantic.match_builtin_expr(value, "type") {
92+
// The annotation `type[a, b]` is not valid since `type` accepts
93+
// a single parameter. This likely is a confusion with `type[a | b]` or
94+
// `type[Union[a, b]]`. Do not emit a diagnostic for invalid type
95+
// annotations.
96+
if !matches!(**slice, Expr::Tuple(_)) && semantic.match_builtin_expr(value, "type")
97+
{
9398
type_exprs.push(slice);
9499
} else {
95100
other_exprs.push(expr);

crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap

+1
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,4 @@ PYI055.py:68:9: PYI055 [*] Multiple `type` members in a union. Combine them into
167167
68 |+ type[_T | Converter[_T]] | str | Converter[_T] | Callable[[str], _T], ... # PYI055
168168
69 69 | ] = union.__args__
169169
70 70 | ...
170+
71 71 |

crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap

+58-55
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ PYI055.pyi:5:4: PYI055 [*] Multiple `type` members in a union. Combine them into
4040
5 |+t: type[int | str | float]
4141
6 6 | u: builtins.type[int] | type[str] | builtins.type[complex]
4242
7 7 | v: Union[type[float], type[complex]]
43-
8 8 | w: Union[type[float, int], type[complex]]
43+
8 8 | w: Union[type[Union[float, int]], type[complex]]
4444

4545
PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`.
4646
|
@@ -49,7 +49,7 @@ PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into
4949
6 | u: builtins.type[int] | type[str] | builtins.type[complex]
5050
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
5151
7 | v: Union[type[float], type[complex]]
52-
8 | w: Union[type[float, int], type[complex]]
52+
8 | w: Union[type[Union[float, int]], type[complex]]
5353
|
5454
= help: Combine multiple `type` members
5555

@@ -60,17 +60,17 @@ PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into
6060
6 |-u: builtins.type[int] | type[str] | builtins.type[complex]
6161
6 |+u: type[int | str | complex]
6262
7 7 | v: Union[type[float], type[complex]]
63-
8 8 | w: Union[type[float, int], type[complex]]
64-
9 9 | x: Union[Union[type[float, int], type[complex]]]
63+
8 8 | w: Union[type[Union[float, int]], type[complex]]
64+
9 9 | x: Union[Union[type[Union[float, int]], type[complex]]]
6565

6666
PYI055.pyi:7:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, complex]]`.
6767
|
6868
5 | t: type[int] | type[str] | type[float]
6969
6 | u: builtins.type[int] | type[str] | builtins.type[complex]
7070
7 | v: Union[type[float], type[complex]]
7171
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
72-
8 | w: Union[type[float, int], type[complex]]
73-
9 | x: Union[Union[type[float, int], type[complex]]]
72+
8 | w: Union[type[Union[float, int]], type[complex]]
73+
9 | x: Union[Union[type[Union[float, int]], type[complex]]]
7474
|
7575
= help: Combine multiple `type` members
7676

@@ -80,96 +80,96 @@ PYI055.pyi:7:4: PYI055 [*] Multiple `type` members in a union. Combine them into
8080
6 6 | u: builtins.type[int] | type[str] | builtins.type[complex]
8181
7 |-v: Union[type[float], type[complex]]
8282
7 |+v: type[Union[float, complex]]
83-
8 8 | w: Union[type[float, int], type[complex]]
84-
9 9 | x: Union[Union[type[float, int], type[complex]]]
85-
10 10 | y: Union[Union[Union[type[float, int], type[complex]]]]
83+
8 8 | w: Union[type[Union[float, int]], type[complex]]
84+
9 9 | x: Union[Union[type[Union[float, int]], type[complex]]]
85+
10 10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
8686

87-
PYI055.pyi:8:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`.
87+
PYI055.pyi:8:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[Union[float, int], complex]]`.
8888
|
8989
6 | u: builtins.type[int] | type[str] | builtins.type[complex]
9090
7 | v: Union[type[float], type[complex]]
91-
8 | w: Union[type[float, int], type[complex]]
92-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
93-
9 | x: Union[Union[type[float, int], type[complex]]]
94-
10 | y: Union[Union[Union[type[float, int], type[complex]]]]
91+
8 | w: Union[type[Union[float, int]], type[complex]]
92+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
93+
9 | x: Union[Union[type[Union[float, int]], type[complex]]]
94+
10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
9595
|
9696
= help: Combine multiple `type` members
9797

9898
Safe fix
9999
5 5 | t: type[int] | type[str] | type[float]
100100
6 6 | u: builtins.type[int] | type[str] | builtins.type[complex]
101101
7 7 | v: Union[type[float], type[complex]]
102-
8 |-w: Union[type[float, int], type[complex]]
103-
8 |+w: type[Union[float, int, complex]]
104-
9 9 | x: Union[Union[type[float, int], type[complex]]]
105-
10 10 | y: Union[Union[Union[type[float, int], type[complex]]]]
106-
11 11 | z: Union[type[complex], Union[Union[type[float, int]]]]
102+
8 |-w: Union[type[Union[float, int]], type[complex]]
103+
8 |+w: type[Union[Union[float, int], complex]]
104+
9 9 | x: Union[Union[type[Union[float, int]], type[complex]]]
105+
10 10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
106+
11 11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
107107

108-
PYI055.pyi:9:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`.
108+
PYI055.pyi:9:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[Union[float, int], complex]]`.
109109
|
110110
7 | v: Union[type[float], type[complex]]
111-
8 | w: Union[type[float, int], type[complex]]
112-
9 | x: Union[Union[type[float, int], type[complex]]]
113-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
114-
10 | y: Union[Union[Union[type[float, int], type[complex]]]]
115-
11 | z: Union[type[complex], Union[Union[type[float, int]]]]
111+
8 | w: Union[type[Union[float, int]], type[complex]]
112+
9 | x: Union[Union[type[Union[float, int]], type[complex]]]
113+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
114+
10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
115+
11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
116116
|
117117
= help: Combine multiple `type` members
118118

119119
Safe fix
120120
6 6 | u: builtins.type[int] | type[str] | builtins.type[complex]
121121
7 7 | v: Union[type[float], type[complex]]
122-
8 8 | w: Union[type[float, int], type[complex]]
123-
9 |-x: Union[Union[type[float, int], type[complex]]]
124-
9 |+x: type[Union[float, int, complex]]
125-
10 10 | y: Union[Union[Union[type[float, int], type[complex]]]]
126-
11 11 | z: Union[type[complex], Union[Union[type[float, int]]]]
122+
8 8 | w: Union[type[Union[float, int]], type[complex]]
123+
9 |-x: Union[Union[type[Union[float, int]], type[complex]]]
124+
9 |+x: type[Union[Union[float, int], complex]]
125+
10 10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
126+
11 11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
127127
12 12 |
128128

129-
PYI055.pyi:10:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`.
129+
PYI055.pyi:10:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[Union[float, int], complex]]`.
130130
|
131-
8 | w: Union[type[float, int], type[complex]]
132-
9 | x: Union[Union[type[float, int], type[complex]]]
133-
10 | y: Union[Union[Union[type[float, int], type[complex]]]]
134-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
135-
11 | z: Union[type[complex], Union[Union[type[float, int]]]]
131+
8 | w: Union[type[Union[float, int]], type[complex]]
132+
9 | x: Union[Union[type[Union[float, int]], type[complex]]]
133+
10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
134+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
135+
11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
136136
|
137137
= help: Combine multiple `type` members
138138

139139
Safe fix
140140
7 7 | v: Union[type[float], type[complex]]
141-
8 8 | w: Union[type[float, int], type[complex]]
142-
9 9 | x: Union[Union[type[float, int], type[complex]]]
143-
10 |-y: Union[Union[Union[type[float, int], type[complex]]]]
144-
10 |+y: type[Union[float, int, complex]]
145-
11 11 | z: Union[type[complex], Union[Union[type[float, int]]]]
141+
8 8 | w: Union[type[Union[float, int]], type[complex]]
142+
9 9 | x: Union[Union[type[Union[float, int]], type[complex]]]
143+
10 |-y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
144+
10 |+y: type[Union[Union[float, int], complex]]
145+
11 11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
146146
12 12 |
147147
13 13 | def func(arg: type[int] | str | type[float]) -> None: ...
148148

149-
PYI055.pyi:11:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[complex, float, int]]`.
149+
PYI055.pyi:11:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[complex, Union[float, int]]]`.
150150
|
151-
9 | x: Union[Union[type[float, int], type[complex]]]
152-
10 | y: Union[Union[Union[type[float, int], type[complex]]]]
153-
11 | z: Union[type[complex], Union[Union[type[float, int]]]]
154-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
151+
9 | x: Union[Union[type[Union[float, int]], type[complex]]]
152+
10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
153+
11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
154+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
155155
12 |
156156
13 | def func(arg: type[int] | str | type[float]) -> None: ...
157157
|
158158
= help: Combine multiple `type` members
159159

160160
Safe fix
161-
8 8 | w: Union[type[float, int], type[complex]]
162-
9 9 | x: Union[Union[type[float, int], type[complex]]]
163-
10 10 | y: Union[Union[Union[type[float, int], type[complex]]]]
164-
11 |-z: Union[type[complex], Union[Union[type[float, int]]]]
165-
11 |+z: type[Union[complex, float, int]]
161+
8 8 | w: Union[type[Union[float, int]], type[complex]]
162+
9 9 | x: Union[Union[type[Union[float, int]], type[complex]]]
163+
10 10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
164+
11 |-z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
165+
11 |+z: type[Union[complex, Union[float, int]]]
166166
12 12 |
167167
13 13 | def func(arg: type[int] | str | type[float]) -> None: ...
168168
14 14 |
169169

170170
PYI055.pyi:13:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | float]`.
171171
|
172-
11 | z: Union[type[complex], Union[Union[type[float, int]]]]
172+
11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
173173
12 |
174174
13 | def func(arg: type[int] | str | type[float]) -> None: ...
175175
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055
@@ -179,14 +179,14 @@ PYI055.pyi:13:15: PYI055 [*] Multiple `type` members in a union. Combine them in
179179
= help: Combine multiple `type` members
180180

181181
Safe fix
182-
10 10 | y: Union[Union[Union[type[float, int], type[complex]]]]
183-
11 11 | z: Union[type[complex], Union[Union[type[float, int]]]]
182+
10 10 | y: Union[Union[Union[type[Union[float, int]], type[complex]]]]
183+
11 11 | z: Union[type[complex], Union[Union[type[Union[float, int]]]]]
184184
12 12 |
185185
13 |-def func(arg: type[int] | str | type[float]) -> None: ...
186186
13 |+def func(arg: type[int | float] | str) -> None: ...
187187
14 14 |
188188
15 15 | # OK
189-
16 16 | x: type[int, str, float]
189+
16 16 | x: type[int | str | float]
190190

191191
PYI055.pyi:23:7: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`.
192192
|
@@ -270,3 +270,6 @@ PYI055.pyi:29:12: PYI055 [*] Multiple `type` members in a union. Combine them in
270270
30 |- type[requests_mock.Mocker], # another comment
271271
31 |- type[httpretty], type[str]] = requests_mock.Mocker
272272
29 |+ item3: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker
273+
32 30 |
274+
33 31 |
275+
34 32 | # OK

0 commit comments

Comments
 (0)