diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.py index 6b11efb181e2d..967f056a92345 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.py @@ -84,3 +84,27 @@ def func2() -> str | str: # PYI016: Duplicate union member `str` # duplicates of the outer `int`), but not three times (which would indicate that # we incorrectly re-checked the nested union). field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` + +# Should emit in cases with nested `typing.Union` +field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` + +# Should emit in cases with nested `typing.Union` +field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int` + +# Should emit in cases with mixed `typing.Union` and `|` +field28: typing.Union[int | int] # Error + +# Should emit twice in cases with multiple nested `typing.Union` +field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + +# Should emit once in cases with multiple nested `typing.Union` +field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error + +# Should emit once, and fix to `typing.Union[float, int]` +field31: typing.Union[float, typing.Union[int | int]] # Error + +# Should emit once, and fix to `typing.Union[float, int]` +field32: typing.Union[float, typing.Union[int | int | int]] # Error + +# Test case for mixed union type fix +field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.pyi index 6b11efb181e2d..7fc398be26408 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI016.pyi @@ -84,3 +84,27 @@ field24: typing.Union[int, typing.Union[int, int]] # PYI016: Duplicate union me # duplicates of the outer `int`), but not three times (which would indicate that # we incorrectly re-checked the nested union). field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` + +# Should emit in cases with nested `typing.Union` +field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` + +# Should emit in cases with nested `typing.Union` +field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int` + +# Should emit in cases with mixed `typing.Union` and `|` +field28: typing.Union[int | int] # Error + +# Should emit twice in cases with multiple nested `typing.Union` +field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + +# Should emit once in cases with multiple nested `typing.Union` +field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error + +# Should emit once, and fix to `typing.Union[float, int]` +field31: typing.Union[float, typing.Union[int | int]] # Error + +# Should emit once, and fix to `typing.Union[float, int]` +field32: typing.Union[float, typing.Union[int | int | int]] # Error + +# Test case for mixed union type fix +field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error \ No newline at end of file diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.py index d1349b3ee3a0f..ba0b1f0c1bee9 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.py @@ -39,6 +39,22 @@ async def f4(**kwargs: int | int | float) -> None: ... +def f5(arg1: int, *args: Union[int, int, float]) -> None: + ... + + +def f6(arg1: int, *args: Union[Union[int, int, float]]) -> None: + ... + + +def f7(arg1: int, *args: Union[Union[Union[int, int, float]]]) -> None: + ... + + +def f8(arg1: int, *args: Union[Union[Union[int | int | float]]]) -> None: + ... + + class Foo: def good(self, arg: int) -> None: ... diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.pyi index 07c2bd3fd67a3..8d95a56a58b12 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI041.pyi @@ -33,6 +33,18 @@ def f3(arg1: int, *args: Union[int | int | float]) -> None: ... # PYI041 async def f4(**kwargs: int | int | float) -> None: ... # PYI041 +def f5(arg1: int, *args: Union[int, int, float]) -> None: ... # PYI041 + + +def f6(arg1: int, *args: Union[Union[int, int, float]]) -> None: ... # PYI041 + + +def f7(arg1: int, *args: Union[Union[Union[int, int, float]]]) -> None: ... # PYI041 + + +def f8(arg1: int, *args: Union[Union[Union[int | int | float]]]) -> None: ... # PYI041 + + class Foo: def good(self, arg: int) -> None: ... diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.py index 543c12974c36e..85e867f84e489 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.py @@ -5,6 +5,9 @@ B: TypeAlias = typing.Union[Literal[b"bar", b"foo"], bytes, str] C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.pyi index 543c12974c36e..85e867f84e489 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI051.pyi @@ -5,6 +5,9 @@ A: str | Literal["foo"] B: TypeAlias = typing.Union[Literal[b"bar", b"foo"], bytes, str] C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py index 2a9c2d77871cc..f039340e4a4cf 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.py @@ -1,11 +1,14 @@ import builtins from typing import Union -w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -x: type[int] | type[str] | type[float] -y: builtins.type[int] | type[str] | builtins.type[complex] -z: Union[type[float], type[complex]] -z: Union[type[float, int], type[complex]] +s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +t: type[int] | type[str] | type[float] +u: builtins.type[int] | type[str] | builtins.type[complex] +v: Union[type[float], type[complex]] +w: Union[type[float, int], type[complex]] +x: Union[Union[type[float, int], type[complex]]] +y: Union[Union[Union[type[float, int], type[complex]]]] +z: Union[type[complex], Union[Union[type[float, int]]]] def func(arg: type[int] | str | type[float]) -> None: diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi index 530f395dfa359..403fc40459580 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI055.pyi @@ -1,11 +1,14 @@ import builtins from typing import Union -w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -x: type[int] | type[str] | type[float] -y: builtins.type[int] | type[str] | builtins.type[complex] -z: Union[type[float], type[complex]] -z: Union[type[float, int], type[complex]] +s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +t: type[int] | type[str] | type[float] +u: builtins.type[int] | type[str] | builtins.type[complex] +v: Union[type[float], type[complex]] +w: Union[type[float, int], type[complex]] +x: Union[Union[type[float, int], type[complex]]] +y: Union[Union[Union[type[float, int], type[complex]]]] +z: Union[type[complex], Union[Union[type[float, int]]]] def func(arg: type[int] | str | type[float]) -> None: ... diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.py index 9e3b46c1f80c0..7fbb70ce6a71f 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.py @@ -14,8 +14,20 @@ Literal[1, Literal[2], Literal[2]] # once t.Literal[1, t.Literal[2, t.Literal[1]]] # once typing_extensions.Literal[1, 1, 1] # twice +Literal[ + 1, # comment + Literal[ # another comment + 1 + ] +] # once # Ensure issue is only raised once, even on nested literals MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 n: Literal["No", "duplicates", "here", 1, "1"] + + +# nested literals, all equivalent to `Literal[1]` +Literal[Literal[1]] # no duplicate +Literal[Literal[Literal[1], Literal[1]]] # once +Literal[Literal[1], Literal[Literal[Literal[1]]]] # once diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.pyi index 38d04bcd9df68..7fbb70ce6a71f 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI062.pyi @@ -2,11 +2,11 @@ from typing import Literal import typing as t import typing_extensions -x: Literal[True, False, True, False] # PY062 twice here +x: Literal[True, False, True, False] # PYI062 twice here -y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 -z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal Literal[1, Literal[1]] # once Literal[1, 2, Literal[1, 2]] # twice @@ -14,8 +14,20 @@ Literal[1, Literal[1], Literal[1]] # twice Literal[1, Literal[2], Literal[2]] # once t.Literal[1, t.Literal[2, t.Literal[1]]] # once typing_extensions.Literal[1, 1, 1] # twice +Literal[ + 1, # comment + Literal[ # another comment + 1 + ] +] # once # Ensure issue is only raised once, even on nested literals MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 n: Literal["No", "duplicates", "here", 1, "1"] + + +# nested literals, all equivalent to `Literal[1]` +Literal[Literal[1]] # no duplicate +Literal[Literal[Literal[1], Literal[1]]] # once +Literal[Literal[1], Literal[Literal[Literal[1]]]] # once diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.py.snap index d3ba1b4f1334b..4ffb35d5fd343 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.py.snap @@ -514,6 +514,8 @@ PYI016.py:86:28: PYI016 [*] Duplicate union member `int` 85 | # we incorrectly re-checked the nested union). 86 | field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` | ^^^ PYI016 +87 | +88 | # Should emit in cases with nested `typing.Union` | = help: Remove duplicate union member `int` @@ -523,6 +525,9 @@ PYI016.py:86:28: PYI016 [*] Duplicate union member `int` 85 85 | # we incorrectly re-checked the nested union). 86 |-field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` 86 |+field25: typing.Union[int, int] # PYI016: Duplicate union member `int` +87 87 | +88 88 | # Should emit in cases with nested `typing.Union` +89 89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` PYI016.py:86:34: PYI016 [*] Duplicate union member `int` | @@ -530,6 +535,8 @@ PYI016.py:86:34: PYI016 [*] Duplicate union member `int` 85 | # we incorrectly re-checked the nested union). 86 | field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` | ^^^ PYI016 +87 | +88 | # Should emit in cases with nested `typing.Union` | = help: Remove duplicate union member `int` @@ -539,5 +546,151 @@ PYI016.py:86:34: PYI016 [*] Duplicate union member `int` 85 85 | # we incorrectly re-checked the nested union). 86 |-field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` 86 |+field25: typing.Union[int, int] # PYI016: Duplicate union member `int` +87 87 | +88 88 | # Should emit in cases with nested `typing.Union` +89 89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` +PYI016.py:89:41: PYI016 Duplicate union member `int` + | +88 | # Should emit in cases with nested `typing.Union` +89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` + | ^^^ PYI016 +90 | +91 | # Should emit in cases with nested `typing.Union` + | + = help: Remove duplicate union member `int` +PYI016.py:95:29: PYI016 [*] Duplicate union member `int` + | +94 | # Should emit in cases with mixed `typing.Union` and `|` +95 | field28: typing.Union[int | int] # Error + | ^^^ PYI016 +96 | +97 | # Should emit twice in cases with multiple nested `typing.Union` + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +92 92 | field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int` +93 93 | +94 94 | # Should emit in cases with mixed `typing.Union` and `|` +95 |-field28: typing.Union[int | int] # Error + 95 |+field28: typing.Union[int] # Error +96 96 | +97 97 | # Should emit twice in cases with multiple nested `typing.Union` +98 98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + +PYI016.py:98:59: PYI016 Duplicate union member `int` + | + 97 | # Should emit twice in cases with multiple nested `typing.Union` + 98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + | ^^^ PYI016 + 99 | +100 | # Should emit once in cases with multiple nested `typing.Union` + | + = help: Remove duplicate union member `int` + +PYI016.py:104:49: PYI016 [*] Duplicate union member `int` + | +103 | # Should emit once, and fix to `typing.Union[float, int]` +104 | field31: typing.Union[float, typing.Union[int | int]] # Error + | ^^^ PYI016 +105 | +106 | # Should emit once, and fix to `typing.Union[float, int]` + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +101 101 | field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error +102 102 | +103 103 | # Should emit once, and fix to `typing.Union[float, int]` +104 |-field31: typing.Union[float, typing.Union[int | int]] # Error + 104 |+field31: typing.Union[float, typing.Union[int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + +PYI016.py:107:49: PYI016 [*] Duplicate union member `int` + | +106 | # Should emit once, and fix to `typing.Union[float, int]` +107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + | ^^^ PYI016 +108 | +109 | # Test case for mixed union type fix + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +104 104 | field31: typing.Union[float, typing.Union[int | int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 |-field32: typing.Union[float, typing.Union[int | int | int]] # Error + 107 |+field32: typing.Union[float, typing.Union[int | int]] # Error +108 108 | +109 109 | # Test case for mixed union type fix +110 110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + +PYI016.py:107:55: PYI016 [*] Duplicate union member `int` + | +106 | # Should emit once, and fix to `typing.Union[float, int]` +107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + | ^^^ PYI016 +108 | +109 | # Test case for mixed union type fix + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +104 104 | field31: typing.Union[float, typing.Union[int | int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 |-field32: typing.Union[float, typing.Union[int | int | int]] # Error + 107 |+field32: typing.Union[float, typing.Union[int | int]] # Error +108 108 | +109 109 | # Test case for mixed union type fix +110 110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + +PYI016.py:110:42: PYI016 [*] Duplicate union member `int` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^ PYI016 + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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] | typing.Union[int | int]] # Error + +PYI016.py:110:49: PYI016 [*] Duplicate union member `typing.Union[int | int]` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI016 + | + = help: Remove duplicate union member `typing.Union[int | int]` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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]] # Error + +PYI016.py:110:68: PYI016 [*] Duplicate union member `int` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^ PYI016 + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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]] # Error diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.pyi.snap index 647791e92b21e..59159d245cfea 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI016_PYI016.pyi.snap @@ -514,6 +514,8 @@ PYI016.pyi:86:28: PYI016 [*] Duplicate union member `int` 85 | # we incorrectly re-checked the nested union). 86 | field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` | ^^^ PYI016 +87 | +88 | # Should emit in cases with nested `typing.Union` | = help: Remove duplicate union member `int` @@ -523,6 +525,9 @@ PYI016.pyi:86:28: PYI016 [*] Duplicate union member `int` 85 85 | # we incorrectly re-checked the nested union). 86 |-field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` 86 |+field25: typing.Union[int, int] # PYI016: Duplicate union member `int` +87 87 | +88 88 | # Should emit in cases with nested `typing.Union` +89 89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` PYI016.pyi:86:34: PYI016 [*] Duplicate union member `int` | @@ -530,6 +535,8 @@ PYI016.pyi:86:34: PYI016 [*] Duplicate union member `int` 85 | # we incorrectly re-checked the nested union). 86 | field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` | ^^^ PYI016 +87 | +88 | # Should emit in cases with nested `typing.Union` | = help: Remove duplicate union member `int` @@ -539,5 +546,151 @@ PYI016.pyi:86:34: PYI016 [*] Duplicate union member `int` 85 85 | # we incorrectly re-checked the nested union). 86 |-field25: typing.Union[int, int | int] # PYI016: Duplicate union member `int` 86 |+field25: typing.Union[int, int] # PYI016: Duplicate union member `int` +87 87 | +88 88 | # Should emit in cases with nested `typing.Union` +89 89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` +PYI016.pyi:89:41: PYI016 Duplicate union member `int` + | +88 | # Should emit in cases with nested `typing.Union` +89 | field26: typing.Union[typing.Union[int, int]] # PYI016: Duplicate union member `int` + | ^^^ PYI016 +90 | +91 | # Should emit in cases with nested `typing.Union` + | + = help: Remove duplicate union member `int` +PYI016.pyi:95:29: PYI016 [*] Duplicate union member `int` + | +94 | # Should emit in cases with mixed `typing.Union` and `|` +95 | field28: typing.Union[int | int] # Error + | ^^^ PYI016 +96 | +97 | # Should emit twice in cases with multiple nested `typing.Union` + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +92 92 | field27: typing.Union[typing.Union[typing.Union[int, int]]] # PYI016: Duplicate union member `int` +93 93 | +94 94 | # Should emit in cases with mixed `typing.Union` and `|` +95 |-field28: typing.Union[int | int] # Error + 95 |+field28: typing.Union[int] # Error +96 96 | +97 97 | # Should emit twice in cases with multiple nested `typing.Union` +98 98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + +PYI016.pyi:98:59: PYI016 Duplicate union member `int` + | + 97 | # Should emit twice in cases with multiple nested `typing.Union` + 98 | field29: typing.Union[int, typing.Union[typing.Union[int, int]]] # Error + | ^^^ PYI016 + 99 | +100 | # Should emit once in cases with multiple nested `typing.Union` + | + = help: Remove duplicate union member `int` + +PYI016.pyi:104:49: PYI016 [*] Duplicate union member `int` + | +103 | # Should emit once, and fix to `typing.Union[float, int]` +104 | field31: typing.Union[float, typing.Union[int | int]] # Error + | ^^^ PYI016 +105 | +106 | # Should emit once, and fix to `typing.Union[float, int]` + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +101 101 | field30: typing.Union[int, typing.Union[typing.Union[int, str]]] # Error +102 102 | +103 103 | # Should emit once, and fix to `typing.Union[float, int]` +104 |-field31: typing.Union[float, typing.Union[int | int]] # Error + 104 |+field31: typing.Union[float, typing.Union[int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + +PYI016.pyi:107:49: PYI016 [*] Duplicate union member `int` + | +106 | # Should emit once, and fix to `typing.Union[float, int]` +107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + | ^^^ PYI016 +108 | +109 | # Test case for mixed union type fix + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +104 104 | field31: typing.Union[float, typing.Union[int | int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 |-field32: typing.Union[float, typing.Union[int | int | int]] # Error + 107 |+field32: typing.Union[float, typing.Union[int | int]] # Error +108 108 | +109 109 | # Test case for mixed union type fix +110 110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + +PYI016.pyi:107:55: PYI016 [*] Duplicate union member `int` + | +106 | # Should emit once, and fix to `typing.Union[float, int]` +107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error + | ^^^ PYI016 +108 | +109 | # Test case for mixed union type fix + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +104 104 | field31: typing.Union[float, typing.Union[int | int]] # Error +105 105 | +106 106 | # Should emit once, and fix to `typing.Union[float, int]` +107 |-field32: typing.Union[float, typing.Union[int | int | int]] # Error + 107 |+field32: typing.Union[float, typing.Union[int | int]] # Error +108 108 | +109 109 | # Test case for mixed union type fix +110 110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + +PYI016.pyi:110:42: PYI016 [*] Duplicate union member `int` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^ PYI016 + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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] | typing.Union[int | int]] # Error + +PYI016.pyi:110:49: PYI016 [*] Duplicate union member `typing.Union[int | int]` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^^^^^^^^^^^^^^^^^^^^^ PYI016 + | + = help: Remove duplicate union member `typing.Union[int | int]` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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]] # Error + +PYI016.pyi:110:68: PYI016 [*] Duplicate union member `int` + | +109 | # Test case for mixed union type fix +110 | field33: typing.Union[typing.Union[int | int] | typing.Union[int | int]] # Error + | ^^^ PYI016 + | + = help: Remove duplicate union member `int` + +ℹ Safe fix +107 107 | field32: typing.Union[float, typing.Union[int | int | int]] # Error +108 108 | +109 109 | # 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]] # Error diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.py.snap index e1721adde5913..d477fa4e5481d 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.py.snap @@ -29,22 +29,27 @@ PYI041.py:38:24: PYI041 Use `float` instead of `int | float` 39 | ... | -PYI041.py:46:24: PYI041 Use `complex` instead of `float | complex` +PYI041.py:42:26: PYI041 Use `float` instead of `int | float` | -44 | ... -45 | -46 | def bad(self, arg: int | float | complex) -> None: - | ^^^^^^^^^^^^^^^^^^^^^ PYI041 -47 | ... +42 | def f5(arg1: int, *args: Union[int, int, float]) -> None: + | ^^^^^^^^^^^^^^^^^^^^^^ PYI041 +43 | ... | -PYI041.py:46:24: PYI041 Use `complex` instead of `int | complex` +PYI041.py:62:24: PYI041 Use `complex` instead of `float | complex` | -44 | ... -45 | -46 | def bad(self, arg: int | float | complex) -> None: +60 | ... +61 | +62 | def bad(self, arg: int | float | complex) -> None: | ^^^^^^^^^^^^^^^^^^^^^ PYI041 -47 | ... +63 | ... | - +PYI041.py:62:24: PYI041 Use `complex` instead of `int | complex` + | +60 | ... +61 | +62 | def bad(self, arg: int | float | complex) -> None: + | ^^^^^^^^^^^^^^^^^^^^^ PYI041 +63 | ... + | diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.pyi.snap index 914faa51566ad..1eb0532519ffe 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI041_PYI041.pyi.snap @@ -25,20 +25,24 @@ PYI041.pyi:33:24: PYI041 Use `float` instead of `int | float` | ^^^^^^^^^^^^^^^^^ PYI041 | -PYI041.pyi:39:24: PYI041 Use `complex` instead of `float | complex` +PYI041.pyi:36:26: PYI041 Use `float` instead of `int | float` | -37 | def good(self, arg: int) -> None: ... -38 | -39 | def bad(self, arg: int | float | complex) -> None: ... # PYI041 - | ^^^^^^^^^^^^^^^^^^^^^ PYI041 +36 | def f5(arg1: int, *args: Union[int, int, float]) -> None: ... # PYI041 + | ^^^^^^^^^^^^^^^^^^^^^^ PYI041 | -PYI041.pyi:39:24: PYI041 Use `complex` instead of `int | complex` +PYI041.pyi:51:24: PYI041 Use `complex` instead of `float | complex` | -37 | def good(self, arg: int) -> None: ... -38 | -39 | def bad(self, arg: int | float | complex) -> None: ... # PYI041 +49 | def good(self, arg: int) -> None: ... +50 | +51 | def bad(self, arg: int | float | complex) -> None: ... # PYI041 | ^^^^^^^^^^^^^^^^^^^^^ PYI041 | - +PYI041.pyi:51:24: PYI041 Use `complex` instead of `int | complex` + | +49 | def good(self, arg: int) -> None: ... +50 | +51 | def bad(self, arg: int | float | complex) -> None: ... # PYI041 + | ^^^^^^^^^^^^^^^^^^^^^ PYI041 + | diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.py.snap index 1e67d47c63e82..5bbbb9809aadc 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.py.snap @@ -36,6 +36,7 @@ PYI051.py:6:37: PYI051 `Literal[5]` is redundant in a union with `int` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] | ^ PYI051 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] | PYI051.py:6:67: PYI051 `Literal["foo"]` is redundant in a union with `str` @@ -45,6 +46,7 @@ PYI051.py:6:67: PYI051 `Literal["foo"]` is redundant in a union with `str` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] | ^^^^^ PYI051 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] | PYI051.py:7:37: PYI051 `Literal[b"str_bytes"]` is redundant in a union with `bytes` @@ -53,8 +55,8 @@ PYI051.py:7:37: PYI051 `Literal[b"str_bytes"]` is redundant in a union with `byt 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] | ^^^^^^^^^^^^ PYI051 -8 | -9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] | PYI051.py:7:51: PYI051 `Literal[42]` is redundant in a union with `int` @@ -63,28 +65,26 @@ PYI051.py:7:51: PYI051 `Literal[42]` is redundant in a union with `int` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] | ^^ PYI051 -8 | -9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] | -PYI051.py:9:31: PYI051 `Literal[1J]` is redundant in a union with `complex` +PYI051.py:12:31: PYI051 `Literal[1J]` is redundant in a union with `complex` | - 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] - 8 | - 9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +11 | +12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... | ^^ PYI051 -10 | -11 | # OK +13 | +14 | # OK | -PYI051.py:9:53: PYI051 `Literal[3.14]` is redundant in a union with `float` +PYI051.py:12:53: PYI051 `Literal[3.14]` is redundant in a union with `float` | - 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] - 8 | - 9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +11 | +12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... | ^^^^ PYI051 -10 | -11 | # OK +13 | +14 | # OK | - - diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.pyi.snap index b5da422a00a7f..bdf063c455cea 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI051_PYI051.pyi.snap @@ -36,6 +36,7 @@ PYI051.pyi:6:37: PYI051 `Literal[5]` is redundant in a union with `int` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] | ^ PYI051 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] | PYI051.pyi:6:67: PYI051 `Literal["foo"]` is redundant in a union with `str` @@ -45,6 +46,7 @@ PYI051.pyi:6:67: PYI051 `Literal["foo"]` is redundant in a union with `str` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] | ^^^^^ PYI051 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] | PYI051.pyi:7:37: PYI051 `Literal[b"str_bytes"]` is redundant in a union with `bytes` @@ -53,8 +55,8 @@ PYI051.pyi:7:37: PYI051 `Literal[b"str_bytes"]` is redundant in a union with `by 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] | ^^^^^^^^^^^^ PYI051 -8 | -9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] | PYI051.pyi:7:51: PYI051 `Literal[42]` is redundant in a union with `int` @@ -63,28 +65,26 @@ PYI051.pyi:7:51: PYI051 `Literal[42]` is redundant in a union with `int` 6 | C: TypeAlias = typing.Union[Literal[5], int, typing.Union[Literal["foo"], str]] 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] | ^^ PYI051 -8 | -9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +8 | E: TypeAlias = typing.Union[typing.Union[typing.Union[typing.Union[Literal["foo"], str]]]] +9 | F: TypeAlias = typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] | -PYI051.pyi:9:31: PYI051 `Literal[1J]` is redundant in a union with `complex` +PYI051.pyi:12:31: PYI051 `Literal[1J]` is redundant in a union with `complex` | - 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] - 8 | - 9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +11 | +12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... | ^^ PYI051 -10 | -11 | # OK +13 | +14 | # OK | -PYI051.pyi:9:53: PYI051 `Literal[3.14]` is redundant in a union with `float` +PYI051.pyi:12:53: PYI051 `Literal[3.14]` is redundant in a union with `float` | - 7 | D: TypeAlias = typing.Union[Literal[b"str_bytes", 42], bytes, int] - 8 | - 9 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... +10 | G: typing.Union[str, typing.Union[typing.Union[typing.Union[Literal["foo"], int]]]] +11 | +12 | def func(x: complex | Literal[1J], y: Union[Literal[3.14], float]): ... | ^^^^ PYI051 -10 | -11 | # OK +13 | +14 | # OK | - - diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap index e93e79a12d48a..2b03a0e9dc3ae 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.py.snap @@ -1,144 +1,142 @@ --- source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs --- -PYI055.py:31:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. +PYI055.py:34:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. | -29 | def func(): -30 | # PYI055 -31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +32 | def func(): +33 | # PYI055 +34 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +35 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | = help: Combine multiple `type` members ℹ Safe fix -28 28 | -29 29 | def func(): -30 30 | # PYI055 -31 |- x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker - 31 |+ x: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker -32 32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker -33 33 | -34 34 | +31 31 | +32 32 | def func(): +33 33 | # PYI055 +34 |- x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + 34 |+ x: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker +35 35 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +36 36 | +37 37 | -PYI055.py:32:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. +PYI055.py:35:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | -30 | # PYI055 -31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -32 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +33 | # PYI055 +34 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +35 | y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members ℹ Safe fix -29 29 | def func(): -30 30 | # PYI055 -31 31 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -32 |- y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - 32 |+ y: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker -33 33 | -34 34 | -35 35 | def func(): +32 32 | def func(): +33 33 | # PYI055 +34 34 | x: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +35 |- y: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 35 |+ y: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker +36 36 | +37 37 | +38 38 | def func(): -PYI055.py:39:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. +PYI055.py:42:8: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | -38 | # PYI055 -39 | x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +41 | # PYI055 +42 | x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members ℹ Safe fix -36 36 | from typing import Union as U -37 37 | -38 38 | # PYI055 -39 |- x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - 39 |+ x: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker +39 39 | from typing import Union as U 40 40 | -41 41 | -42 42 | def convert_union(union: UnionType) -> _T | None: +41 41 | # PYI055 +42 |- x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 42 |+ x: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker +43 43 | +44 44 | +45 45 | def convert_union(union: UnionType) -> _T | None: -PYI055.py:44:9: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. +PYI055.py:47:9: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. | -42 | def convert_union(union: UnionType) -> _T | None: -43 | converters: tuple[ -44 | type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 +45 | def convert_union(union: UnionType) -> _T | None: +46 | converters: tuple[ +47 | type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -45 | ] = union.__args__ -46 | ... +48 | ] = union.__args__ +49 | ... | = help: Combine multiple `type` members ℹ Safe fix -41 41 | -42 42 | def convert_union(union: UnionType) -> _T | None: -43 43 | converters: tuple[ -44 |- type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 - 44 |+ type[_T | Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 -45 45 | ] = union.__args__ -46 46 | ... -47 47 | +44 44 | +45 45 | def convert_union(union: UnionType) -> _T | None: +46 46 | converters: tuple[ +47 |- type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 + 47 |+ type[_T | Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055 +48 48 | ] = union.__args__ +49 49 | ... +50 50 | -PYI055.py:50:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. +PYI055.py:53:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. | -48 | def convert_union(union: UnionType) -> _T | None: -49 | converters: tuple[ -50 | Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 +51 | def convert_union(union: UnionType) -> _T | None: +52 | converters: tuple[ +53 | Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -51 | ] = union.__args__ -52 | ... +54 | ] = union.__args__ +55 | ... | = help: Combine multiple `type` members ℹ Safe fix -47 47 | -48 48 | def convert_union(union: UnionType) -> _T | None: -49 49 | converters: tuple[ -50 |- Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 - 50 |+ Union[type[_T | Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 -51 51 | ] = union.__args__ -52 52 | ... -53 53 | +50 50 | +51 51 | def convert_union(union: UnionType) -> _T | None: +52 52 | converters: tuple[ +53 |- Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 + 53 |+ Union[type[_T | Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055 +54 54 | ] = union.__args__ +55 55 | ... +56 56 | -PYI055.py:56:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. +PYI055.py:59:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. | -54 | def convert_union(union: UnionType) -> _T | None: -55 | converters: tuple[ -56 | Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 +57 | def convert_union(union: UnionType) -> _T | None: +58 | converters: tuple[ +59 | Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -57 | ] = union.__args__ -58 | ... +60 | ] = union.__args__ +61 | ... | = help: Combine multiple `type` members ℹ Safe fix -53 53 | -54 54 | def convert_union(union: UnionType) -> _T | None: -55 55 | converters: tuple[ -56 |- Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 - 56 |+ Union[type[_T | Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 -57 57 | ] = union.__args__ -58 58 | ... -59 59 | +56 56 | +57 57 | def convert_union(union: UnionType) -> _T | None: +58 58 | converters: tuple[ +59 |- Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 + 59 |+ Union[type[_T | Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055 +60 60 | ] = union.__args__ +61 61 | ... +62 62 | -PYI055.py:62:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. +PYI055.py:65:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[_T | Converter[_T]]`. | -60 | def convert_union(union: UnionType) -> _T | None: -61 | converters: tuple[ -62 | Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 +63 | def convert_union(union: UnionType) -> _T | None: +64 | converters: tuple[ +65 | Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -63 | ] = union.__args__ -64 | ... +66 | ] = union.__args__ +67 | ... | = help: Combine multiple `type` members ℹ Safe fix -59 59 | -60 60 | def convert_union(union: UnionType) -> _T | None: -61 61 | converters: tuple[ -62 |- Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 - 62 |+ Union[type[_T | Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 -63 63 | ] = union.__args__ -64 64 | ... - - +62 62 | +63 63 | def convert_union(union: UnionType) -> _T | None: +64 64 | converters: tuple[ +65 |- Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 + 65 |+ Union[type[_T | Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055 +66 66 | ] = union.__args__ +67 67 | ... diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap index 0e41288be5073..764d5c519dc2a 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI055_PYI055.pyi.snap @@ -5,10 +5,10 @@ PYI055.pyi:4:4: PYI055 [*] Multiple `type` members in a union. Combine them into | 2 | from typing import Union 3 | -4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] +4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -5 | x: type[int] | type[str] | type[float] -6 | y: builtins.type[int] | type[str] | builtins.type[complex] +5 | t: type[int] | type[str] | type[float] +6 | u: builtins.type[int] | type[str] | builtins.type[complex] | = help: Combine multiple `type` members @@ -16,167 +16,187 @@ PYI055.pyi:4:4: PYI055 [*] Multiple `type` members in a union. Combine them into 1 1 | import builtins 2 2 | from typing import Union 3 3 | -4 |-w: builtins.type[int] | builtins.type[str] | builtins.type[complex] - 4 |+w: type[int | str | complex] -5 5 | x: type[int] | type[str] | type[float] -6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 7 | z: Union[type[float], type[complex]] +4 |-s: builtins.type[int] | builtins.type[str] | builtins.type[complex] + 4 |+s: type[int | str | complex] +5 5 | t: type[int] | type[str] | type[float] +6 6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | v: Union[type[float], type[complex]] PYI055.pyi:5:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | float]`. | -4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -5 | x: type[int] | type[str] | type[float] +4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 | t: type[int] | type[str] | type[float] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 | z: Union[type[float], type[complex]] +6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 | v: Union[type[float], type[complex]] | = help: Combine multiple `type` members ℹ Safe fix 2 2 | from typing import Union 3 3 | -4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -5 |-x: type[int] | type[str] | type[float] - 5 |+x: type[int | str | float] -6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 7 | z: Union[type[float], type[complex]] -8 8 | z: Union[type[float, int], type[complex]] +4 4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 |-t: type[int] | type[str] | type[float] + 5 |+t: type[int | str | float] +6 6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | v: Union[type[float], type[complex]] +8 8 | w: Union[type[float, int], type[complex]] PYI055.pyi:6:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | str | complex]`. | -4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -5 | x: type[int] | type[str] | type[float] -6 | y: builtins.type[int] | type[str] | builtins.type[complex] +4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 | t: type[int] | type[str] | type[float] +6 | u: builtins.type[int] | type[str] | builtins.type[complex] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -7 | z: Union[type[float], type[complex]] -8 | z: Union[type[float, int], type[complex]] +7 | v: Union[type[float], type[complex]] +8 | w: Union[type[float, int], type[complex]] | = help: Combine multiple `type` members ℹ Safe fix 3 3 | -4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -5 5 | x: type[int] | type[str] | type[float] -6 |-y: builtins.type[int] | type[str] | builtins.type[complex] - 6 |+y: type[int | str | complex] -7 7 | z: Union[type[float], type[complex]] -8 8 | z: Union[type[float, int], type[complex]] -9 9 | +4 4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 5 | t: type[int] | type[str] | type[float] +6 |-u: builtins.type[int] | type[str] | builtins.type[complex] + 6 |+u: type[int | str | complex] +7 7 | v: Union[type[float], type[complex]] +8 8 | w: Union[type[float, int], type[complex]] +9 9 | x: Union[Union[type[float, int], type[complex]]] PYI055.pyi:7:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, complex]]`. | -5 | x: type[int] | type[str] | type[float] -6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 | z: Union[type[float], type[complex]] +5 | t: type[int] | type[str] | type[float] +6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 | v: Union[type[float], type[complex]] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -8 | z: Union[type[float, int], type[complex]] +8 | w: Union[type[float, int], type[complex]] +9 | x: Union[Union[type[float, int], type[complex]]] | = help: Combine multiple `type` members ℹ Safe fix -4 4 | w: builtins.type[int] | builtins.type[str] | builtins.type[complex] -5 5 | x: type[int] | type[str] | type[float] -6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 |-z: Union[type[float], type[complex]] - 7 |+z: type[Union[float, complex]] -8 8 | z: Union[type[float, int], type[complex]] -9 9 | -10 10 | def func(arg: type[int] | str | type[float]) -> None: ... +4 4 | s: builtins.type[int] | builtins.type[str] | builtins.type[complex] +5 5 | t: type[int] | type[str] | type[float] +6 6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 |-v: Union[type[float], type[complex]] + 7 |+v: type[Union[float, complex]] +8 8 | w: Union[type[float, int], type[complex]] +9 9 | x: Union[Union[type[float, int], type[complex]]] +10 10 | y: Union[Union[Union[type[float, int], type[complex]]]] PYI055.pyi:8:4: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`. | - 6 | y: builtins.type[int] | type[str] | builtins.type[complex] - 7 | z: Union[type[float], type[complex]] - 8 | z: Union[type[float, int], type[complex]] + 6 | u: builtins.type[int] | type[str] | builtins.type[complex] + 7 | v: Union[type[float], type[complex]] + 8 | w: Union[type[float, int], type[complex]] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 - 9 | -10 | def func(arg: type[int] | str | type[float]) -> None: ... + 9 | x: Union[Union[type[float, int], type[complex]]] +10 | y: Union[Union[Union[type[float, int], type[complex]]]] | = help: Combine multiple `type` members ℹ Safe fix -5 5 | x: type[int] | type[str] | type[float] -6 6 | y: builtins.type[int] | type[str] | builtins.type[complex] -7 7 | z: Union[type[float], type[complex]] -8 |-z: Union[type[float, int], type[complex]] - 8 |+z: type[Union[float, int, complex]] -9 9 | -10 10 | def func(arg: type[int] | str | type[float]) -> None: ... -11 11 | - -PYI055.pyi:10:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | float]`. +5 5 | t: type[int] | type[str] | type[float] +6 6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | v: Union[type[float], type[complex]] +8 |-w: Union[type[float, int], type[complex]] + 8 |+w: type[Union[float, int, complex]] +9 9 | x: Union[Union[type[float, int], type[complex]]] +10 10 | y: Union[Union[Union[type[float, int], type[complex]]]] +11 11 | z: Union[type[complex], Union[Union[type[float, int]]]] + +PYI055.pyi:9:10: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[float, int, complex]]`. | - 8 | z: Union[type[float, int], type[complex]] - 9 | -10 | def func(arg: type[int] | str | type[float]) -> None: ... + 7 | v: Union[type[float], type[complex]] + 8 | w: Union[type[float, int], type[complex]] + 9 | x: Union[Union[type[float, int], type[complex]]] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 +10 | y: Union[Union[Union[type[float, int], type[complex]]]] +11 | z: Union[type[complex], Union[Union[type[float, int]]]] + | + = help: Combine multiple `type` members + +ℹ Safe fix +6 6 | u: builtins.type[int] | type[str] | builtins.type[complex] +7 7 | v: Union[type[float], type[complex]] +8 8 | w: Union[type[float, int], type[complex]] +9 |-x: Union[Union[type[float, int], type[complex]]] + 9 |+x: Union[type[Union[float, int, complex]]] +10 10 | y: Union[Union[Union[type[float, int], type[complex]]]] +11 11 | z: Union[type[complex], Union[Union[type[float, int]]]] +12 12 | + +PYI055.pyi:13:15: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[int | float]`. + | +11 | z: Union[type[complex], Union[Union[type[float, int]]]] +12 | +13 | def func(arg: type[int] | str | type[float]) -> None: ... | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -11 | -12 | # OK +14 | +15 | # OK | = help: Combine multiple `type` members ℹ Safe fix -7 7 | z: Union[type[float], type[complex]] -8 8 | z: Union[type[float, int], type[complex]] -9 9 | -10 |-def func(arg: type[int] | str | type[float]) -> None: ... - 10 |+def func(arg: type[int | float] | str) -> None: ... -11 11 | -12 12 | # OK -13 13 | x: type[int, str, float] - -PYI055.pyi:20:7: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. +10 10 | y: Union[Union[Union[type[float, int], type[complex]]]] +11 11 | z: Union[type[complex], Union[Union[type[float, int]]]] +12 12 | +13 |-def func(arg: type[int] | str | type[float]) -> None: ... + 13 |+def func(arg: type[int | float] | str) -> None: ... +14 14 | +15 15 | # OK +16 16 | x: type[int, str, float] + +PYI055.pyi:23:7: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty]`. | -19 | # OK -20 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker +22 | # OK +23 | item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -21 | -22 | def func(): +24 | +25 | def func(): | = help: Combine multiple `type` members ℹ Safe fix -17 17 | def func(arg: type[int, float] | str) -> None: ... -18 18 | -19 19 | # OK -20 |-item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker - 20 |+item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker +20 20 | def func(arg: type[int, float] | str) -> None: ... 21 21 | -22 22 | def func(): -23 23 | # PYI055 - -PYI055.pyi:24:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. +22 22 | # OK +23 |-item: type[requests_mock.Mocker] | type[httpretty] = requests_mock.Mocker + 23 |+item: type[requests_mock.Mocker | httpretty] = requests_mock.Mocker +24 24 | +25 25 | def func(): +26 26 | # PYI055 + +PYI055.pyi:27:11: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[requests_mock.Mocker | httpretty | str]`. | -22 | def func(): -23 | # PYI055 -24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +25 | def func(): +26 | # PYI055 +27 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 -25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +28 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | = help: Combine multiple `type` members ℹ Safe fix -21 21 | -22 22 | def func(): -23 23 | # PYI055 -24 |- item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker - 24 |+ item: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker -25 25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - -PYI055.pyi:25:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. +24 24 | +25 25 | def func(): +26 26 | # PYI055 +27 |- item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker + 27 |+ item: type[requests_mock.Mocker | httpretty | str] = requests_mock.Mocker +28 28 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + +PYI055.pyi:28:12: PYI055 [*] Multiple `type` members in a union. Combine them into one, e.g., `type[Union[requests_mock.Mocker, httpretty, str]]`. | -23 | # PYI055 -24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -25 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker +26 | # PYI055 +27 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +28 | item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI055 | = help: Combine multiple `type` members ℹ Safe fix -22 22 | def func(): -23 23 | # PYI055 -24 24 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker -25 |- item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker - 25 |+ item2: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker - - +25 25 | def func(): +26 26 | # PYI055 +27 27 | item: type[requests_mock.Mocker] | type[httpretty] | type[str] = requests_mock.Mocker +28 |- item2: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker + 28 |+ item2: type[Union[requests_mock.Mocker, httpretty, str]] = requests_mock.Mocker diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap index c73ae4f46e55b..224e48cbc7ab8 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.py.snap @@ -207,7 +207,7 @@ PYI062.py:14:32: PYI062 [*] Duplicate literal member `2` 14 |+Literal[1, 2] # once 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | +17 17 | Literal[ PYI062.py:15:37: PYI062 [*] Duplicate literal member `1` | @@ -216,6 +216,7 @@ PYI062.py:15:37: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | ^ PYI062 16 | typing_extensions.Literal[1, 1, 1] # twice +17 | Literal[ | = help: Remove duplicates @@ -226,8 +227,8 @@ PYI062.py:15:37: PYI062 [*] Duplicate literal member `1` 15 |-t.Literal[1, t.Literal[2, t.Literal[1]]] # once 15 |+t.Literal[1, 2] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals +17 17 | Literal[ +18 18 | 1, # comment PYI062.py:16:30: PYI062 [*] Duplicate literal member `1` | @@ -235,8 +236,8 @@ PYI062.py:16:30: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | ^ PYI062 -17 | -18 | # Ensure issue is only raised once, even on nested literals +17 | Literal[ +18 | 1, # comment | = help: Remove duplicates @@ -246,9 +247,9 @@ PYI062.py:16:30: PYI062 [*] Duplicate literal member `1` 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 |-typing_extensions.Literal[1, 1, 1] # twice 16 |+typing_extensions.Literal[1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 +17 17 | Literal[ +18 18 | 1, # comment +19 19 | Literal[ # another comment PYI062.py:16:33: PYI062 [*] Duplicate literal member `1` | @@ -256,8 +257,8 @@ PYI062.py:16:33: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | ^ PYI062 -17 | -18 | # Ensure issue is only raised once, even on nested literals +17 | Literal[ +18 | 1, # comment | = help: Remove duplicates @@ -267,25 +268,104 @@ PYI062.py:16:33: PYI062 [*] Duplicate literal member `1` 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 |-typing_extensions.Literal[1, 1, 1] # twice 16 |+typing_extensions.Literal[1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 +17 17 | Literal[ +18 18 | 1, # comment +19 19 | Literal[ # another comment -PYI062.py:19:46: PYI062 [*] Duplicate literal member `True` +PYI062.py:20:9: PYI062 [*] Duplicate literal member `1` | -18 | # Ensure issue is only raised once, even on nested literals -19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 - | ^^^^ PYI062 -20 | -21 | n: Literal["No", "duplicates", "here", 1, "1"] +18 | 1, # comment +19 | Literal[ # another comment +20 | 1 + | ^ PYI062 +21 | ] +22 | ] # once | = help: Remove duplicates ℹ Safe fix +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 - 19 |+MyType = Literal["foo", True, False, "bar"] # PYI062 -20 20 | -21 21 | n: Literal["No", "duplicates", "here", 1, "1"] +17 |-Literal[ +18 |- 1, # comment +19 |- Literal[ # another comment +20 |- 1 +21 |- ] +22 |-] # once + 17 |+Literal[1] # once +23 18 | +24 19 | # Ensure issue is only raised once, even on nested literals +25 20 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.py:25:46: PYI062 [*] Duplicate literal member `True` + | +24 | # Ensure issue is only raised once, even on nested literals +25 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + | ^^^^ PYI062 +26 | +27 | n: Literal["No", "duplicates", "here", 1, "1"] + | + = help: Remove duplicates + +ℹ Safe fix +22 22 | ] # once +23 23 | +24 24 | # Ensure issue is only raised once, even on nested literals +25 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + 25 |+MyType = Literal["foo", True, False, "bar"] # PYI062 +26 26 | +27 27 | n: Literal["No", "duplicates", "here", 1, "1"] +28 28 | + +PYI062.py:32:37: PYI062 [*] Duplicate literal member `1` + | +30 | # nested literals, all equivalent to `Literal[1]` +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once + | ^ PYI062 +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | + = help: Remove duplicates + +ℹ Safe fix +29 29 | +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 |-Literal[Literal[Literal[1], Literal[1]]] # once + 32 |+Literal[Literal[1]] # once +33 33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + +PYI062.py:32:37: PYI062 [*] Duplicate literal member `1` + | +30 | # nested literals, all equivalent to `Literal[1]` +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once + | ^ PYI062 +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | + = help: Remove duplicates + +ℹ Safe fix +29 29 | +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 |-Literal[Literal[Literal[1], Literal[1]]] # once + 32 |+Literal[1] # once +33 33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + +PYI062.py:33:45: PYI062 [*] Duplicate literal member `1` + | +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | ^ PYI062 + | + = help: Remove duplicates + +ℹ Safe fix +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 32 | Literal[Literal[Literal[1], Literal[1]]] # once +33 |-Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + 33 |+Literal[1] # once diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap index 0a96dea0cec1e..c5ab4f3f20370 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI062_PYI062.pyi.snap @@ -5,10 +5,10 @@ PYI062.pyi:5:25: PYI062 [*] Duplicate literal member `True` | 3 | import typing_extensions 4 | -5 | x: Literal[True, False, True, False] # PY062 twice here +5 | x: Literal[True, False, True, False] # PYI062 twice here | ^^^^ PYI062 6 | -7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 | = help: Remove duplicates @@ -16,20 +16,20 @@ PYI062.pyi:5:25: PYI062 [*] Duplicate literal member `True` 2 2 | import typing as t 3 3 | import typing_extensions 4 4 | -5 |-x: Literal[True, False, True, False] # PY062 twice here - 5 |+x: Literal[True, False] # PY062 twice here +5 |-x: Literal[True, False, True, False] # PYI062 twice here + 5 |+x: Literal[True, False] # PYI062 twice here 6 6 | -7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 8 8 | PYI062.pyi:5:31: PYI062 [*] Duplicate literal member `False` | 3 | import typing_extensions 4 | -5 | x: Literal[True, False, True, False] # PY062 twice here +5 | x: Literal[True, False, True, False] # PYI062 twice here | ^^^^^ PYI062 6 | -7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 | = help: Remove duplicates @@ -37,38 +37,38 @@ PYI062.pyi:5:31: PYI062 [*] Duplicate literal member `False` 2 2 | import typing as t 3 3 | import typing_extensions 4 4 | -5 |-x: Literal[True, False, True, False] # PY062 twice here - 5 |+x: Literal[True, False] # PY062 twice here +5 |-x: Literal[True, False, True, False] # PYI062 twice here + 5 |+x: Literal[True, False] # PYI062 twice here 6 6 | -7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 8 8 | PYI062.pyi:7:45: PYI062 [*] Duplicate literal member `1` | -5 | x: Literal[True, False, True, False] # PY062 twice here +5 | x: Literal[True, False, True, False] # PYI062 twice here 6 | -7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 | ^ PYI062 8 | -9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal | = help: Remove duplicates ℹ Safe fix 4 4 | -5 5 | x: Literal[True, False, True, False] # PY062 twice here +5 5 | x: Literal[True, False, True, False] # PYI062 twice here 6 6 | -7 |-y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 - 7 |+y: Literal[1, print("hello"), 3, 4] # PY062 on the last 1 +7 |-y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 + 7 |+y: Literal[1, print("hello"), 3, 4] # PYI062 on the last 1 8 8 | -9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 10 | PYI062.pyi:9:33: PYI062 [*] Duplicate literal member `{1, 3, 5}` | - 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 + 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 8 | - 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal + 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal | ^^^^^^^ PYI062 10 | 11 | Literal[1, Literal[1]] # once @@ -77,17 +77,17 @@ PYI062.pyi:9:33: PYI062 [*] Duplicate literal member `{1, 3, 5}` ℹ Safe fix 6 6 | -7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PY062 on the last 1 +7 7 | y: Literal[1, print("hello"), 3, Literal[4, 1]] # PYI062 on the last 1 8 8 | -9 |-z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal - 9 |+z: Literal[{1, 3, 5}, "foobar"] # PY062 on the set literal +9 |-z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal + 9 |+z: Literal[{1, 3, 5}, "foobar"] # PYI062 on the set literal 10 10 | 11 11 | Literal[1, Literal[1]] # once 12 12 | Literal[1, 2, Literal[1, 2]] # twice PYI062.pyi:11:20: PYI062 [*] Duplicate literal member `1` | - 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal + 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 | 11 | Literal[1, Literal[1]] # once | ^ PYI062 @@ -98,7 +98,7 @@ PYI062.pyi:11:20: PYI062 [*] Duplicate literal member `1` ℹ Safe fix 8 8 | -9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 10 | 11 |-Literal[1, Literal[1]] # once 11 |+Literal[1] # once @@ -117,7 +117,7 @@ PYI062.pyi:12:23: PYI062 [*] Duplicate literal member `1` = help: Remove duplicates ℹ Safe fix -9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 10 | 11 11 | Literal[1, Literal[1]] # once 12 |-Literal[1, 2, Literal[1, 2]] # twice @@ -137,7 +137,7 @@ PYI062.pyi:12:26: PYI062 [*] Duplicate literal member `2` = help: Remove duplicates ℹ Safe fix -9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PY062 on the set literal +9 9 | z: Literal[{1, 3, 5}, "foobar", {1,3,5}] # PYI062 on the set literal 10 10 | 11 11 | Literal[1, Literal[1]] # once 12 |-Literal[1, 2, Literal[1, 2]] # twice @@ -207,7 +207,7 @@ PYI062.pyi:14:32: PYI062 [*] Duplicate literal member `2` 14 |+Literal[1, 2] # once 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | +17 17 | Literal[ PYI062.pyi:15:37: PYI062 [*] Duplicate literal member `1` | @@ -216,6 +216,7 @@ PYI062.pyi:15:37: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once | ^ PYI062 16 | typing_extensions.Literal[1, 1, 1] # twice +17 | Literal[ | = help: Remove duplicates @@ -226,8 +227,8 @@ PYI062.pyi:15:37: PYI062 [*] Duplicate literal member `1` 15 |-t.Literal[1, t.Literal[2, t.Literal[1]]] # once 15 |+t.Literal[1, 2] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals +17 17 | Literal[ +18 18 | 1, # comment PYI062.pyi:16:30: PYI062 [*] Duplicate literal member `1` | @@ -235,8 +236,8 @@ PYI062.pyi:16:30: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | ^ PYI062 -17 | -18 | # Ensure issue is only raised once, even on nested literals +17 | Literal[ +18 | 1, # comment | = help: Remove duplicates @@ -246,9 +247,9 @@ PYI062.pyi:16:30: PYI062 [*] Duplicate literal member `1` 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 |-typing_extensions.Literal[1, 1, 1] # twice 16 |+typing_extensions.Literal[1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 +17 17 | Literal[ +18 18 | 1, # comment +19 19 | Literal[ # another comment PYI062.pyi:16:33: PYI062 [*] Duplicate literal member `1` | @@ -256,8 +257,8 @@ PYI062.pyi:16:33: PYI062 [*] Duplicate literal member `1` 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 | typing_extensions.Literal[1, 1, 1] # twice | ^ PYI062 -17 | -18 | # Ensure issue is only raised once, even on nested literals +17 | Literal[ +18 | 1, # comment | = help: Remove duplicates @@ -267,25 +268,104 @@ PYI062.pyi:16:33: PYI062 [*] Duplicate literal member `1` 15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 |-typing_extensions.Literal[1, 1, 1] # twice 16 |+typing_extensions.Literal[1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 +17 17 | Literal[ +18 18 | 1, # comment +19 19 | Literal[ # another comment -PYI062.pyi:19:46: PYI062 [*] Duplicate literal member `True` +PYI062.pyi:20:9: PYI062 [*] Duplicate literal member `1` | -18 | # Ensure issue is only raised once, even on nested literals -19 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 - | ^^^^ PYI062 -20 | -21 | n: Literal["No", "duplicates", "here", 1, "1"] +18 | 1, # comment +19 | Literal[ # another comment +20 | 1 + | ^ PYI062 +21 | ] +22 | ] # once | = help: Remove duplicates ℹ Safe fix +14 14 | Literal[1, Literal[2], Literal[2]] # once +15 15 | t.Literal[1, t.Literal[2, t.Literal[1]]] # once 16 16 | typing_extensions.Literal[1, 1, 1] # twice -17 17 | -18 18 | # Ensure issue is only raised once, even on nested literals -19 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 - 19 |+MyType = Literal["foo", True, False, "bar"] # PYI062 -20 20 | -21 21 | n: Literal["No", "duplicates", "here", 1, "1"] +17 |-Literal[ +18 |- 1, # comment +19 |- Literal[ # another comment +20 |- 1 +21 |- ] +22 |-] # once + 17 |+Literal[1] # once +23 18 | +24 19 | # Ensure issue is only raised once, even on nested literals +25 20 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + +PYI062.pyi:25:46: PYI062 [*] Duplicate literal member `True` + | +24 | # Ensure issue is only raised once, even on nested literals +25 | MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + | ^^^^ PYI062 +26 | +27 | n: Literal["No", "duplicates", "here", 1, "1"] + | + = help: Remove duplicates + +ℹ Safe fix +22 22 | ] # once +23 23 | +24 24 | # Ensure issue is only raised once, even on nested literals +25 |-MyType = Literal["foo", Literal[True, False, True], "bar"] # PYI062 + 25 |+MyType = Literal["foo", True, False, "bar"] # PYI062 +26 26 | +27 27 | n: Literal["No", "duplicates", "here", 1, "1"] +28 28 | + +PYI062.pyi:32:37: PYI062 [*] Duplicate literal member `1` + | +30 | # nested literals, all equivalent to `Literal[1]` +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once + | ^ PYI062 +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | + = help: Remove duplicates + +ℹ Safe fix +29 29 | +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 |-Literal[Literal[Literal[1], Literal[1]]] # once + 32 |+Literal[Literal[1]] # once +33 33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + +PYI062.pyi:32:37: PYI062 [*] Duplicate literal member `1` + | +30 | # nested literals, all equivalent to `Literal[1]` +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once + | ^ PYI062 +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | + = help: Remove duplicates + +ℹ Safe fix +29 29 | +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 |-Literal[Literal[Literal[1], Literal[1]]] # once + 32 |+Literal[1] # once +33 33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + +PYI062.pyi:33:45: PYI062 [*] Duplicate literal member `1` + | +31 | Literal[Literal[1]] # no duplicate +32 | Literal[Literal[Literal[1], Literal[1]]] # once +33 | Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + | ^ PYI062 + | + = help: Remove duplicates + +ℹ Safe fix +30 30 | # nested literals, all equivalent to `Literal[1]` +31 31 | Literal[Literal[1]] # no duplicate +32 32 | Literal[Literal[Literal[1], Literal[1]]] # once +33 |-Literal[Literal[1], Literal[Literal[Literal[1]]]] # once + 33 |+Literal[1] # once