Skip to content

Commit dc29f52

Browse files
authored
[flake8-pyi, ruff] Fix traversal of nested literals and unions (PYI016, PYI051, PYI055, PYI062, RUF041) (#14641)
1 parent d9cbf2f commit dc29f52

16 files changed

+319
-170
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,6 @@ def func2() -> str | str: # PYI016: Duplicate union member `str`
108108

109109
# Test case for mixed union type fix
110110
field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
111+
112+
# Test case for mixed union type
113+
field34: typing.Union[list[int], str] | typing.Union[bytes, list[int]] # Error

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,7 @@ field31: typing.Union[float, typing.Union[int | int]] # Error
107107
field32: typing.Union[float, typing.Union[int | int | int]] # Error
108108

109109
# Test case for mixed union type fix
110-
field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
110+
field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
111+
112+
# Test case for mixed union type
113+
field34: typing.Union[list[int], str] | typing.Union[bytes, list[int]] # Error

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

+47-3
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,16 @@ PYI016.py:89:41: PYI016 Duplicate union member `int`
330330
|
331331
= help: Remove duplicate union member `int`
332332

333+
PYI016.py:92:54: PYI016 Duplicate union member `int`
334+
|
335+
91 | # Should emit in cases with nested `typing.Union`
336+
92 | field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int`
337+
| ^^^ PYI016
338+
93 |
339+
94 | # Should emit in cases with mixed `typing.Union` and `|`
340+
|
341+
= help: Remove duplicate union member `int`
342+
333343
PYI016.py:95:29: PYI016 Duplicate union member `int`
334344
|
335345
94 | # Should emit in cases with mixed `typing.Union` and `|`
@@ -340,6 +350,16 @@ PYI016.py:95:29: PYI016 Duplicate union member `int`
340350
|
341351
= help: Remove duplicate union member `int`
342352

353+
PYI016.py:98:54: PYI016 Duplicate union member `int`
354+
|
355+
97 | # Should emit twice in cases with multiple nested `typing.Union`
356+
98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error
357+
| ^^^ PYI016
358+
99 |
359+
100 | # Should emit once in cases with multiple nested `typing.Union`
360+
|
361+
= help: Remove duplicate union member `int`
362+
343363
PYI016.py:98:59: PYI016 Duplicate union member `int`
344364
|
345365
97 | # Should emit twice in cases with multiple nested `typing.Union`
@@ -350,6 +370,16 @@ PYI016.py:98:59: PYI016 Duplicate union member `int`
350370
|
351371
= help: Remove duplicate union member `int`
352372

373+
PYI016.py:101:54: PYI016 Duplicate union member `int`
374+
|
375+
100 | # Should emit once in cases with multiple nested `typing.Union`
376+
101 | field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error
377+
| ^^^ PYI016
378+
102 |
379+
103 | # Should emit once, and fix to `typing.Union[float, int]`
380+
|
381+
= help: Remove duplicate union member `int`
382+
353383
PYI016.py:104:49: PYI016 Duplicate union member `int`
354384
|
355385
103 | # Should emit once, and fix to `typing.Union[float, int]`
@@ -385,21 +415,35 @@ PYI016.py:110:42: PYI016 Duplicate union member `int`
385415
109 | # Test case for mixed union type fix
386416
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
387417
| ^^^ PYI016
418+
111 |
419+
112 | # Test case for mixed union type
388420
|
389421
= help: Remove duplicate union member `int`
390422

391-
PYI016.py:110:49: PYI016 Duplicate union member `typing.Union[int | int]`
423+
PYI016.py:110:62: PYI016 Duplicate union member `int`
392424
|
393425
109 | # Test case for mixed union type fix
394426
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
395-
| ^^^^^^^^^^^^^^^^^^^^^^^ PYI016
427+
| ^^^ PYI016
428+
111 |
429+
112 | # Test case for mixed union type
396430
|
397-
= help: Remove duplicate union member `typing.Union[int | int]`
431+
= help: Remove duplicate union member `int`
398432

399433
PYI016.py:110:68: PYI016 Duplicate union member `int`
400434
|
401435
109 | # Test case for mixed union type fix
402436
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
403437
| ^^^ PYI016
438+
111 |
439+
112 | # Test case for mixed union type
404440
|
405441
= help: Remove duplicate union member `int`
442+
443+
PYI016.py:113:61: PYI016 Duplicate union member `list[int]`
444+
|
445+
112 | # Test case for mixed union type
446+
113 | field34: typing.Union[list[int], str] | typing.Union[bytes, list[int]] # Error
447+
| ^^^^^^^^^ PYI016
448+
|
449+
= help: Remove duplicate union member `list[int]`

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

+47-3
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,16 @@ PYI016.pyi:89:41: PYI016 Duplicate union member `int`
330330
|
331331
= help: Remove duplicate union member `int`
332332

333+
PYI016.pyi:92:54: PYI016 Duplicate union member `int`
334+
|
335+
91 | # Should emit in cases with nested `typing.Union`
336+
92 | field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int`
337+
| ^^^ PYI016
338+
93 |
339+
94 | # Should emit in cases with mixed `typing.Union` and `|`
340+
|
341+
= help: Remove duplicate union member `int`
342+
333343
PYI016.pyi:95:29: PYI016 Duplicate union member `int`
334344
|
335345
94 | # Should emit in cases with mixed `typing.Union` and `|`
@@ -340,6 +350,16 @@ PYI016.pyi:95:29: PYI016 Duplicate union member `int`
340350
|
341351
= help: Remove duplicate union member `int`
342352

353+
PYI016.pyi:98:54: PYI016 Duplicate union member `int`
354+
|
355+
97 | # Should emit twice in cases with multiple nested `typing.Union`
356+
98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error
357+
| ^^^ PYI016
358+
99 |
359+
100 | # Should emit once in cases with multiple nested `typing.Union`
360+
|
361+
= help: Remove duplicate union member `int`
362+
343363
PYI016.pyi:98:59: PYI016 Duplicate union member `int`
344364
|
345365
97 | # Should emit twice in cases with multiple nested `typing.Union`
@@ -350,6 +370,16 @@ PYI016.pyi:98:59: PYI016 Duplicate union member `int`
350370
|
351371
= help: Remove duplicate union member `int`
352372

373+
PYI016.pyi:101:54: PYI016 Duplicate union member `int`
374+
|
375+
100 | # Should emit once in cases with multiple nested `typing.Union`
376+
101 | field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error
377+
| ^^^ PYI016
378+
102 |
379+
103 | # Should emit once, and fix to `typing.Union[float, int]`
380+
|
381+
= help: Remove duplicate union member `int`
382+
353383
PYI016.pyi:104:49: PYI016 Duplicate union member `int`
354384
|
355385
103 | # Should emit once, and fix to `typing.Union[float, int]`
@@ -385,21 +415,35 @@ PYI016.pyi:110:42: PYI016 Duplicate union member `int`
385415
109 | # Test case for mixed union type fix
386416
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
387417
| ^^^ PYI016
418+
111 |
419+
112 | # Test case for mixed union type
388420
|
389421
= help: Remove duplicate union member `int`
390422

391-
PYI016.pyi:110:49: PYI016 Duplicate union member `typing.Union[int | int]`
423+
PYI016.pyi:110:62: PYI016 Duplicate union member `int`
392424
|
393425
109 | # Test case for mixed union type fix
394426
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
395-
| ^^^^^^^^^^^^^^^^^^^^^^^ PYI016
427+
| ^^^ PYI016
428+
111 |
429+
112 | # Test case for mixed union type
396430
|
397-
= help: Remove duplicate union member `typing.Union[int | int]`
431+
= help: Remove duplicate union member `int`
398432

399433
PYI016.pyi:110:68: PYI016 Duplicate union member `int`
400434
|
401435
109 | # Test case for mixed union type fix
402436
110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error
403437
| ^^^ PYI016
438+
111 |
439+
112 | # Test case for mixed union type
404440
|
405441
= help: Remove duplicate union member `int`
442+
443+
PYI016.pyi:113:61: PYI016 Duplicate union member `list[int]`
444+
|
445+
112 | # Test case for mixed union type
446+
113 | field34: typing.Union[list[int], str] | typing.Union[bytes, list[int]] # Error
447+
| ^^^^^^^^^ PYI016
448+
|
449+
= help: Remove duplicate union member `list[int]`

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

+32
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ PYI041.py:30:28: PYI041 Use `float` instead of `int | float`
2525
|
2626
= help: Remove redundant type
2727

28+
PYI041.py:34:26: PYI041 Use `float` instead of `int | float`
29+
|
30+
34 | def f3(arg1: int, *args: Union[int | int | float]) -> None:
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
32+
35 | ...
33+
|
34+
= help: Remove redundant type
35+
2836
PYI041.py:38:24: PYI041 Use `float` instead of `int | float`
2937
|
3038
38 | async def f4(**kwargs: int | int | float) -> None:
@@ -41,6 +49,30 @@ PYI041.py:42:26: PYI041 Use `float` instead of `int | float`
4149
|
4250
= help: Remove redundant type
4351

52+
PYI041.py:46:26: PYI041 Use `float` instead of `int | float`
53+
|
54+
46 | def f6(arg1: int, *args: Union[Union[int, int, float]]) -> None:
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
56+
47 | ...
57+
|
58+
= help: Remove redundant type
59+
60+
PYI041.py:50:26: PYI041 Use `float` instead of `int | float`
61+
|
62+
50 | def f7(arg1: int, *args: Union[Union[Union[int, int, float]]]) -> None:
63+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
64+
51 | ...
65+
|
66+
= help: Remove redundant type
67+
68+
PYI041.py:54:26: PYI041 Use `float` instead of `int | float`
69+
|
70+
54 | def f8(arg1: int, *args: Union[Union[Union[int | int | float]]]) -> None:
71+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
72+
55 | ...
73+
|
74+
= help: Remove redundant type
75+
4476
PYI041.py:59:10: PYI041 Use `complex` instead of `int | float | complex`
4577
|
4678
58 | def f9(

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

+28
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ PYI041.pyi:27:28: PYI041 Use `float` instead of `int | float`
2222
|
2323
= help: Remove redundant type
2424

25+
PYI041.pyi:30:26: PYI041 Use `float` instead of `int | float`
26+
|
27+
30 | def f3(arg1: int, *args: Union[int | int | float]) -> None: ... # PYI041
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
29+
|
30+
= help: Remove redundant type
31+
2532
PYI041.pyi:33:24: PYI041 Use `float` instead of `int | float`
2633
|
2734
33 | async def f4(**kwargs: int | int | float) -> None: ... # PYI041
@@ -66,6 +73,27 @@ PYI041.pyi:49:26: PYI041 Use `float` instead of `int | float`
6673
|
6774
= help: Remove redundant type
6875

76+
PYI041.pyi:52:26: PYI041 Use `float` instead of `int | float`
77+
|
78+
52 | def f6(arg1: int, *args: Union[Union[int, int, float]]) -> None: ... # PYI041
79+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
80+
|
81+
= help: Remove redundant type
82+
83+
PYI041.pyi:55:26: PYI041 Use `float` instead of `int | float`
84+
|
85+
55 | def f7(arg1: int, *args: Union[Union[Union[int, int, float]]]) -> None: ... # PYI041
86+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
87+
|
88+
= help: Remove redundant type
89+
90+
PYI041.pyi:58:26: PYI041 Use `float` instead of `int | float`
91+
|
92+
58 | def f8(arg1: int, *args: Union[Union[Union[int | int | float]]]) -> None: ... # PYI041
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI041
94+
|
95+
= help: Remove redundant type
96+
6997
PYI041.pyi:64:24: PYI041 Use `complex` instead of `int | float | complex`
7098
|
7199
62 | def good(self, arg: int) -> None: ...

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

+29
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ PYI051.py:7:51: PYI051 `Literal[42]` is redundant in a union with `int`
7070
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
7171
|
7272

73+
PYI051.py:8:76: PYI051 `Literal["foo"]` is redundant in a union with `str`
74+
|
75+
6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]]
76+
7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int]
77+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
78+
| ^^^^^ PYI051
79+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
80+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
81+
|
82+
83+
PYI051.py:9:81: PYI051 `Literal["foo"]` is redundant in a union with `str`
84+
|
85+
7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int]
86+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
87+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
88+
| ^^^^^ PYI051
89+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
90+
|
91+
92+
PYI051.py:10:69: PYI051 `Literal["foo"]` is redundant in a union with `str`
93+
|
94+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
95+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
96+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
97+
| ^^^^^ PYI051
98+
11 |
99+
12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ...
100+
|
101+
73102
PYI051.py:12:31: PYI051 `Literal[1J]` is redundant in a union with `complex`
74103
|
75104
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]

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

+29
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ PYI051.pyi:7:51: PYI051 `Literal[42]` is redundant in a union with `int`
7070
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
7171
|
7272

73+
PYI051.pyi:8:76: PYI051 `Literal["foo"]` is redundant in a union with `str`
74+
|
75+
6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]]
76+
7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int]
77+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
78+
| ^^^^^ PYI051
79+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
80+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
81+
|
82+
83+
PYI051.pyi:9:81: PYI051 `Literal["foo"]` is redundant in a union with `str`
84+
|
85+
7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int]
86+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
87+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
88+
| ^^^^^ PYI051
89+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
90+
|
91+
92+
PYI051.pyi:10:69: PYI051 `Literal["foo"]` is redundant in a union with `str`
93+
|
94+
8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]]
95+
9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
96+
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]
97+
| ^^^^^ PYI051
98+
11 |
99+
12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ...
100+
|
101+
73102
PYI051.pyi:12:31: PYI051 `Literal[1J]` is redundant in a union with `complex`
74103
|
75104
10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]]

0 commit comments

Comments
 (0)