From 8ccd697020b543e606d559d8a7c58d6dc3ae372f Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 15 Jul 2023 15:37:34 -0400 Subject: [PATCH] Expand scope of `quoted-annotation` rule (#5766) ## Summary Previously, the `quoted-annotation` rule only removed quotes when `from __future__ import annotations` was present. However, there are some other cases in which this is also safe -- for example: ```python def foo(): x: "MyClass" ``` We already model these in the semantic model, so this PR just expands the scope of the rule to handle those. --- .../pyupgrade/{UP037.py => UP037_0.py} | 2 + .../test/fixtures/pyupgrade/UP037_1.py | 108 ++++ crates/ruff/src/checkers/ast/mod.rs | 2 +- crates/ruff/src/rules/pyupgrade/mod.rs | 3 +- .../pyupgrade/rules/quoted_annotation.rs | 5 + ...ff__rules__pyupgrade__tests__UP037.py.snap | 559 ------------------ ...__rules__pyupgrade__tests__UP037_0.py.snap | 559 ++++++++++++++++++ ...__rules__pyupgrade__tests__UP037_1.py.snap | 22 + 8 files changed, 699 insertions(+), 561 deletions(-) rename crates/ruff/resources/test/fixtures/pyupgrade/{UP037.py => UP037_0.py} (95%) create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP037_1.py delete mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_0.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_1.py.snap diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP037.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP037_0.py similarity index 95% rename from crates/ruff/resources/test/fixtures/pyupgrade/UP037.py rename to crates/ruff/resources/test/fixtures/pyupgrade/UP037_0.py index f970c605a8..2536dbc043 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP037.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP037_0.py @@ -1,3 +1,5 @@ +"""A mirror of UP037_1.py, with `from __future__ import annotations`.""" + from __future__ import annotations from typing import ( diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP037_1.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP037_1.py new file mode 100644 index 0000000000..f40257f85a --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP037_1.py @@ -0,0 +1,108 @@ +"""A mirror of UP037_0.py, without `from __future__ import annotations`.""" + +from typing import ( + Annotated, + Callable, + List, + Literal, + NamedTuple, + Tuple, + TypeVar, + TypedDict, + cast, +) + +from mypy_extensions import Arg, DefaultArg, DefaultNamedArg, NamedArg, VarArg + + +def foo(var: "MyClass") -> "MyClass": + x: "MyClass" + + +def foo(*, inplace: "bool"): + pass + + +def foo(*args: "str", **kwargs: "int"): + pass + + +x: Tuple["MyClass"] + +x: Callable[["MyClass"], None] + + +class Foo(NamedTuple): + x: "MyClass" + + +class D(TypedDict): + E: TypedDict("E", foo="int", total=False) + + +class D(TypedDict): + E: TypedDict("E", {"foo": "int"}) + + +x: Annotated["str", "metadata"] + +x: Arg("str", "name") + +x: DefaultArg("str", "name") + +x: NamedArg("str", "name") + +x: DefaultNamedArg("str", "name") + +x: DefaultNamedArg("str", name="name") + +x: VarArg("str") + +x: List[List[List["MyClass"]]] + +x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + +x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + +x: NamedTuple(typename="X", fields=[("foo", "int")]) + +X: MyCallable("X") + + +# OK +class D(TypedDict): + E: TypedDict("E") + + +x: Annotated[()] + +x: DefaultNamedArg(name="name", quox="str") + +x: DefaultNamedArg(name="name") + +x: NamedTuple("X", [("foo",), ("bar",)]) + +x: NamedTuple("X", ["foo", "bar"]) + +x: NamedTuple() + +x: Literal["foo", "bar"] + +x = cast(x, "str") + + +def foo(x, *args, **kwargs): + ... + + +def foo(*, inplace): + ... + + +x: Annotated[1:2] = ... + +x = TypeVar("x", "str", "int") + +x = cast("str", x) + +X = List["MyClass"] diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index e6fe846ec2..e6b64dc1cf 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -4581,7 +4581,7 @@ impl<'a> Checker<'a> { self.semantic.restore(snapshot); - if self.semantic.in_annotation() && self.semantic.future_annotations() { + if self.semantic.in_typing_only_annotation() { if self.enabled(Rule::QuotedAnnotation) { pyupgrade::rules::quoted_annotation(self, value, range); } diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index f65042ebc9..db02317a37 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -55,7 +55,8 @@ mod tests { #[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_5.py"))] #[test_case(Rule::PrintfStringFormatting, Path::new("UP031_0.py"))] #[test_case(Rule::PrintfStringFormatting, Path::new("UP031_1.py"))] - #[test_case(Rule::QuotedAnnotation, Path::new("UP037.py"))] + #[test_case(Rule::QuotedAnnotation, Path::new("UP037_0.py"))] + #[test_case(Rule::QuotedAnnotation, Path::new("UP037_1.py"))] #[test_case(Rule::RedundantOpenModes, Path::new("UP015.py"))] #[test_case(Rule::ReplaceStdoutStderr, Path::new("UP022.py"))] #[test_case(Rule::ReplaceUniversalNewlines, Path::new("UP021.py"))] diff --git a/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs b/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs index 749e3011f5..ac137b97e2 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs @@ -15,6 +15,11 @@ use crate::registry::Rule; /// will always evaluate type annotations in a deferred manner, making /// the quotes unnecessary. /// +/// Type annotations can also be unquoted in some other contexts, even +/// without `from __future__ import annotations`. For example, annotated +/// assignments within function bodies are not evaluated at runtime, and so can +/// be unquoted. +/// /// ## Example /// ```python /// from __future__ import annotations diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037.py.snap deleted file mode 100644 index 8d3af3b967..0000000000 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037.py.snap +++ /dev/null @@ -1,559 +0,0 @@ ---- -source: crates/ruff/src/rules/pyupgrade/mod.rs ---- -UP037.py:18:14: UP037 [*] Remove quotes from type annotation - | -18 | def foo(var: "MyClass") -> "MyClass": - | ^^^^^^^^^ UP037 -19 | x: "MyClass" - | - = help: Remove quotes - -ℹ Fix -15 15 | from mypy_extensions import Arg, DefaultArg, DefaultNamedArg, NamedArg, VarArg -16 16 | -17 17 | -18 |-def foo(var: "MyClass") -> "MyClass": - 18 |+def foo(var: MyClass) -> "MyClass": -19 19 | x: "MyClass" -20 20 | -21 21 | - -UP037.py:18:28: UP037 [*] Remove quotes from type annotation - | -18 | def foo(var: "MyClass") -> "MyClass": - | ^^^^^^^^^ UP037 -19 | x: "MyClass" - | - = help: Remove quotes - -ℹ Fix -15 15 | from mypy_extensions import Arg, DefaultArg, DefaultNamedArg, NamedArg, VarArg -16 16 | -17 17 | -18 |-def foo(var: "MyClass") -> "MyClass": - 18 |+def foo(var: "MyClass") -> MyClass: -19 19 | x: "MyClass" -20 20 | -21 21 | - -UP037.py:19:8: UP037 [*] Remove quotes from type annotation - | -18 | def foo(var: "MyClass") -> "MyClass": -19 | x: "MyClass" - | ^^^^^^^^^ UP037 - | - = help: Remove quotes - -ℹ Fix -16 16 | -17 17 | -18 18 | def foo(var: "MyClass") -> "MyClass": -19 |- x: "MyClass" - 19 |+ x: MyClass -20 20 | -21 21 | -22 22 | def foo(*, inplace: "bool"): - -UP037.py:22:21: UP037 [*] Remove quotes from type annotation - | -22 | def foo(*, inplace: "bool"): - | ^^^^^^ UP037 -23 | pass - | - = help: Remove quotes - -ℹ Fix -19 19 | x: "MyClass" -20 20 | -21 21 | -22 |-def foo(*, inplace: "bool"): - 22 |+def foo(*, inplace: bool): -23 23 | pass -24 24 | -25 25 | - -UP037.py:26:16: UP037 [*] Remove quotes from type annotation - | -26 | def foo(*args: "str", **kwargs: "int"): - | ^^^^^ UP037 -27 | pass - | - = help: Remove quotes - -ℹ Fix -23 23 | pass -24 24 | -25 25 | -26 |-def foo(*args: "str", **kwargs: "int"): - 26 |+def foo(*args: str, **kwargs: "int"): -27 27 | pass -28 28 | -29 29 | - -UP037.py:26:33: UP037 [*] Remove quotes from type annotation - | -26 | def foo(*args: "str", **kwargs: "int"): - | ^^^^^ UP037 -27 | pass - | - = help: Remove quotes - -ℹ Fix -23 23 | pass -24 24 | -25 25 | -26 |-def foo(*args: "str", **kwargs: "int"): - 26 |+def foo(*args: "str", **kwargs: int): -27 27 | pass -28 28 | -29 29 | - -UP037.py:30:10: UP037 [*] Remove quotes from type annotation - | -30 | x: Tuple["MyClass"] - | ^^^^^^^^^ UP037 -31 | -32 | x: Callable[["MyClass"], None] - | - = help: Remove quotes - -ℹ Fix -27 27 | pass -28 28 | -29 29 | -30 |-x: Tuple["MyClass"] - 30 |+x: Tuple[MyClass] -31 31 | -32 32 | x: Callable[["MyClass"], None] -33 33 | - -UP037.py:32:14: UP037 [*] Remove quotes from type annotation - | -30 | x: Tuple["MyClass"] -31 | -32 | x: Callable[["MyClass"], None] - | ^^^^^^^^^ UP037 - | - = help: Remove quotes - -ℹ Fix -29 29 | -30 30 | x: Tuple["MyClass"] -31 31 | -32 |-x: Callable[["MyClass"], None] - 32 |+x: Callable[[MyClass], None] -33 33 | -34 34 | -35 35 | class Foo(NamedTuple): - -UP037.py:36:8: UP037 [*] Remove quotes from type annotation - | -35 | class Foo(NamedTuple): -36 | x: "MyClass" - | ^^^^^^^^^ UP037 - | - = help: Remove quotes - -ℹ Fix -33 33 | -34 34 | -35 35 | class Foo(NamedTuple): -36 |- x: "MyClass" - 36 |+ x: MyClass -37 37 | -38 38 | -39 39 | class D(TypedDict): - -UP037.py:40:27: UP037 [*] Remove quotes from type annotation - | -39 | class D(TypedDict): -40 | E: TypedDict("E", foo="int", total=False) - | ^^^^^ UP037 - | - = help: Remove quotes - -ℹ Fix -37 37 | -38 38 | -39 39 | class D(TypedDict): -40 |- E: TypedDict("E", foo="int", total=False) - 40 |+ E: TypedDict("E", foo=int, total=False) -41 41 | -42 42 | -43 43 | class D(TypedDict): - -UP037.py:44:31: UP037 [*] Remove quotes from type annotation - | -43 | class D(TypedDict): -44 | E: TypedDict("E", {"foo": "int"}) - | ^^^^^ UP037 - | - = help: Remove quotes - -ℹ Fix -41 41 | -42 42 | -43 43 | class D(TypedDict): -44 |- E: TypedDict("E", {"foo": "int"}) - 44 |+ E: TypedDict("E", {"foo": int}) -45 45 | -46 46 | -47 47 | x: Annotated["str", "metadata"] - -UP037.py:47:14: UP037 [*] Remove quotes from type annotation - | -47 | x: Annotated["str", "metadata"] - | ^^^^^ UP037 -48 | -49 | x: Arg("str", "name") - | - = help: Remove quotes - -ℹ Fix -44 44 | E: TypedDict("E", {"foo": "int"}) -45 45 | -46 46 | -47 |-x: Annotated["str", "metadata"] - 47 |+x: Annotated[str, "metadata"] -48 48 | -49 49 | x: Arg("str", "name") -50 50 | - -UP037.py:49:8: UP037 [*] Remove quotes from type annotation - | -47 | x: Annotated["str", "metadata"] -48 | -49 | x: Arg("str", "name") - | ^^^^^ UP037 -50 | -51 | x: DefaultArg("str", "name") - | - = help: Remove quotes - -ℹ Fix -46 46 | -47 47 | x: Annotated["str", "metadata"] -48 48 | -49 |-x: Arg("str", "name") - 49 |+x: Arg(str, "name") -50 50 | -51 51 | x: DefaultArg("str", "name") -52 52 | - -UP037.py:51:15: UP037 [*] Remove quotes from type annotation - | -49 | x: Arg("str", "name") -50 | -51 | x: DefaultArg("str", "name") - | ^^^^^ UP037 -52 | -53 | x: NamedArg("str", "name") - | - = help: Remove quotes - -ℹ Fix -48 48 | -49 49 | x: Arg("str", "name") -50 50 | -51 |-x: DefaultArg("str", "name") - 51 |+x: DefaultArg(str, "name") -52 52 | -53 53 | x: NamedArg("str", "name") -54 54 | - -UP037.py:53:13: UP037 [*] Remove quotes from type annotation - | -51 | x: DefaultArg("str", "name") -52 | -53 | x: NamedArg("str", "name") - | ^^^^^ UP037 -54 | -55 | x: DefaultNamedArg("str", "name") - | - = help: Remove quotes - -ℹ Fix -50 50 | -51 51 | x: DefaultArg("str", "name") -52 52 | -53 |-x: NamedArg("str", "name") - 53 |+x: NamedArg(str, "name") -54 54 | -55 55 | x: DefaultNamedArg("str", "name") -56 56 | - -UP037.py:55:20: UP037 [*] Remove quotes from type annotation - | -53 | x: NamedArg("str", "name") -54 | -55 | x: DefaultNamedArg("str", "name") - | ^^^^^ UP037 -56 | -57 | x: DefaultNamedArg("str", name="name") - | - = help: Remove quotes - -ℹ Fix -52 52 | -53 53 | x: NamedArg("str", "name") -54 54 | -55 |-x: DefaultNamedArg("str", "name") - 55 |+x: DefaultNamedArg(str, "name") -56 56 | -57 57 | x: DefaultNamedArg("str", name="name") -58 58 | - -UP037.py:57:20: UP037 [*] Remove quotes from type annotation - | -55 | x: DefaultNamedArg("str", "name") -56 | -57 | x: DefaultNamedArg("str", name="name") - | ^^^^^ UP037 -58 | -59 | x: VarArg("str") - | - = help: Remove quotes - -ℹ Fix -54 54 | -55 55 | x: DefaultNamedArg("str", "name") -56 56 | -57 |-x: DefaultNamedArg("str", name="name") - 57 |+x: DefaultNamedArg(str, name="name") -58 58 | -59 59 | x: VarArg("str") -60 60 | - -UP037.py:59:11: UP037 [*] Remove quotes from type annotation - | -57 | x: DefaultNamedArg("str", name="name") -58 | -59 | x: VarArg("str") - | ^^^^^ UP037 -60 | -61 | x: List[List[List["MyClass"]]] - | - = help: Remove quotes - -ℹ Fix -56 56 | -57 57 | x: DefaultNamedArg("str", name="name") -58 58 | -59 |-x: VarArg("str") - 59 |+x: VarArg(str) -60 60 | -61 61 | x: List[List[List["MyClass"]]] -62 62 | - -UP037.py:61:19: UP037 [*] Remove quotes from type annotation - | -59 | x: VarArg("str") -60 | -61 | x: List[List[List["MyClass"]]] - | ^^^^^^^^^ UP037 -62 | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) - | - = help: Remove quotes - -ℹ Fix -58 58 | -59 59 | x: VarArg("str") -60 60 | -61 |-x: List[List[List["MyClass"]]] - 61 |+x: List[List[List[MyClass]]] -62 62 | -63 63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 64 | - -UP037.py:63:29: UP037 [*] Remove quotes from type annotation - | -61 | x: List[List[List["MyClass"]]] -62 | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | - = help: Remove quotes - -ℹ Fix -60 60 | -61 61 | x: List[List[List["MyClass"]]] -62 62 | -63 |-x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) - 63 |+x: NamedTuple("X", [("foo", int), ("bar", "str")]) -64 64 | -65 65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 66 | - -UP037.py:63:45: UP037 [*] Remove quotes from type annotation - | -61 | x: List[List[List["MyClass"]]] -62 | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | - = help: Remove quotes - -ℹ Fix -60 60 | -61 61 | x: List[List[List["MyClass"]]] -62 62 | -63 |-x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) - 63 |+x: NamedTuple("X", [("foo", "int"), ("bar", str)]) -64 64 | -65 65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 66 | - -UP037.py:65:29: UP037 [*] Remove quotes from type annotation - | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | - = help: Remove quotes - -ℹ Fix -62 62 | -63 63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 64 | -65 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - 65 |+x: NamedTuple("X", fields=[(foo, "int"), ("bar", "str")]) -66 66 | -67 67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) -68 68 | - -UP037.py:65:36: UP037 [*] Remove quotes from type annotation - | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | - = help: Remove quotes - -ℹ Fix -62 62 | -63 63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 64 | -65 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - 65 |+x: NamedTuple("X", fields=[("foo", int), ("bar", "str")]) -66 66 | -67 67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) -68 68 | - -UP037.py:65:45: UP037 [*] Remove quotes from type annotation - | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | - = help: Remove quotes - -ℹ Fix -62 62 | -63 63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 64 | -65 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - 65 |+x: NamedTuple("X", fields=[("foo", "int"), (bar, "str")]) -66 66 | -67 67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) -68 68 | - -UP037.py:65:52: UP037 [*] Remove quotes from type annotation - | -63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - | ^^^^^ UP037 -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | - = help: Remove quotes - -ℹ Fix -62 62 | -63 63 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) -64 64 | -65 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) - 65 |+x: NamedTuple("X", fields=[("foo", "int"), ("bar", str)]) -66 66 | -67 67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) -68 68 | - -UP037.py:67:24: UP037 [*] Remove quotes from type annotation - | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | ^^^ UP037 -68 | -69 | X: MyCallable("X") - | - = help: Remove quotes - -ℹ Fix -64 64 | -65 65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 66 | -67 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) - 67 |+x: NamedTuple(typename=X, fields=[("foo", "int")]) -68 68 | -69 69 | X: MyCallable("X") -70 70 | - -UP037.py:67:38: UP037 [*] Remove quotes from type annotation - | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | ^^^^^ UP037 -68 | -69 | X: MyCallable("X") - | - = help: Remove quotes - -ℹ Fix -64 64 | -65 65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 66 | -67 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) - 67 |+x: NamedTuple(typename="X", fields=[(foo, "int")]) -68 68 | -69 69 | X: MyCallable("X") -70 70 | - -UP037.py:67:45: UP037 [*] Remove quotes from type annotation - | -65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 | -67 | x: NamedTuple(typename="X", fields=[("foo", "int")]) - | ^^^^^ UP037 -68 | -69 | X: MyCallable("X") - | - = help: Remove quotes - -ℹ Fix -64 64 | -65 65 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) -66 66 | -67 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) - 67 |+x: NamedTuple(typename="X", fields=[("foo", int)]) -68 68 | -69 69 | X: MyCallable("X") -70 70 | - - diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_0.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_0.py.snap new file mode 100644 index 0000000000..f9b3084db5 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_0.py.snap @@ -0,0 +1,559 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +UP037_0.py:20:14: UP037 [*] Remove quotes from type annotation + | +20 | def foo(var: "MyClass") -> "MyClass": + | ^^^^^^^^^ UP037 +21 | x: "MyClass" + | + = help: Remove quotes + +ℹ Fix +17 17 | from mypy_extensions import Arg, DefaultArg, DefaultNamedArg, NamedArg, VarArg +18 18 | +19 19 | +20 |-def foo(var: "MyClass") -> "MyClass": + 20 |+def foo(var: MyClass) -> "MyClass": +21 21 | x: "MyClass" +22 22 | +23 23 | + +UP037_0.py:20:28: UP037 [*] Remove quotes from type annotation + | +20 | def foo(var: "MyClass") -> "MyClass": + | ^^^^^^^^^ UP037 +21 | x: "MyClass" + | + = help: Remove quotes + +ℹ Fix +17 17 | from mypy_extensions import Arg, DefaultArg, DefaultNamedArg, NamedArg, VarArg +18 18 | +19 19 | +20 |-def foo(var: "MyClass") -> "MyClass": + 20 |+def foo(var: "MyClass") -> MyClass: +21 21 | x: "MyClass" +22 22 | +23 23 | + +UP037_0.py:21:8: UP037 [*] Remove quotes from type annotation + | +20 | def foo(var: "MyClass") -> "MyClass": +21 | x: "MyClass" + | ^^^^^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +18 18 | +19 19 | +20 20 | def foo(var: "MyClass") -> "MyClass": +21 |- x: "MyClass" + 21 |+ x: MyClass +22 22 | +23 23 | +24 24 | def foo(*, inplace: "bool"): + +UP037_0.py:24:21: UP037 [*] Remove quotes from type annotation + | +24 | def foo(*, inplace: "bool"): + | ^^^^^^ UP037 +25 | pass + | + = help: Remove quotes + +ℹ Fix +21 21 | x: "MyClass" +22 22 | +23 23 | +24 |-def foo(*, inplace: "bool"): + 24 |+def foo(*, inplace: bool): +25 25 | pass +26 26 | +27 27 | + +UP037_0.py:28:16: UP037 [*] Remove quotes from type annotation + | +28 | def foo(*args: "str", **kwargs: "int"): + | ^^^^^ UP037 +29 | pass + | + = help: Remove quotes + +ℹ Fix +25 25 | pass +26 26 | +27 27 | +28 |-def foo(*args: "str", **kwargs: "int"): + 28 |+def foo(*args: str, **kwargs: "int"): +29 29 | pass +30 30 | +31 31 | + +UP037_0.py:28:33: UP037 [*] Remove quotes from type annotation + | +28 | def foo(*args: "str", **kwargs: "int"): + | ^^^^^ UP037 +29 | pass + | + = help: Remove quotes + +ℹ Fix +25 25 | pass +26 26 | +27 27 | +28 |-def foo(*args: "str", **kwargs: "int"): + 28 |+def foo(*args: "str", **kwargs: int): +29 29 | pass +30 30 | +31 31 | + +UP037_0.py:32:10: UP037 [*] Remove quotes from type annotation + | +32 | x: Tuple["MyClass"] + | ^^^^^^^^^ UP037 +33 | +34 | x: Callable[["MyClass"], None] + | + = help: Remove quotes + +ℹ Fix +29 29 | pass +30 30 | +31 31 | +32 |-x: Tuple["MyClass"] + 32 |+x: Tuple[MyClass] +33 33 | +34 34 | x: Callable[["MyClass"], None] +35 35 | + +UP037_0.py:34:14: UP037 [*] Remove quotes from type annotation + | +32 | x: Tuple["MyClass"] +33 | +34 | x: Callable[["MyClass"], None] + | ^^^^^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +31 31 | +32 32 | x: Tuple["MyClass"] +33 33 | +34 |-x: Callable[["MyClass"], None] + 34 |+x: Callable[[MyClass], None] +35 35 | +36 36 | +37 37 | class Foo(NamedTuple): + +UP037_0.py:38:8: UP037 [*] Remove quotes from type annotation + | +37 | class Foo(NamedTuple): +38 | x: "MyClass" + | ^^^^^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +35 35 | +36 36 | +37 37 | class Foo(NamedTuple): +38 |- x: "MyClass" + 38 |+ x: MyClass +39 39 | +40 40 | +41 41 | class D(TypedDict): + +UP037_0.py:42:27: UP037 [*] Remove quotes from type annotation + | +41 | class D(TypedDict): +42 | E: TypedDict("E", foo="int", total=False) + | ^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +39 39 | +40 40 | +41 41 | class D(TypedDict): +42 |- E: TypedDict("E", foo="int", total=False) + 42 |+ E: TypedDict("E", foo=int, total=False) +43 43 | +44 44 | +45 45 | class D(TypedDict): + +UP037_0.py:46:31: UP037 [*] Remove quotes from type annotation + | +45 | class D(TypedDict): +46 | E: TypedDict("E", {"foo": "int"}) + | ^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +43 43 | +44 44 | +45 45 | class D(TypedDict): +46 |- E: TypedDict("E", {"foo": "int"}) + 46 |+ E: TypedDict("E", {"foo": int}) +47 47 | +48 48 | +49 49 | x: Annotated["str", "metadata"] + +UP037_0.py:49:14: UP037 [*] Remove quotes from type annotation + | +49 | x: Annotated["str", "metadata"] + | ^^^^^ UP037 +50 | +51 | x: Arg("str", "name") + | + = help: Remove quotes + +ℹ Fix +46 46 | E: TypedDict("E", {"foo": "int"}) +47 47 | +48 48 | +49 |-x: Annotated["str", "metadata"] + 49 |+x: Annotated[str, "metadata"] +50 50 | +51 51 | x: Arg("str", "name") +52 52 | + +UP037_0.py:51:8: UP037 [*] Remove quotes from type annotation + | +49 | x: Annotated["str", "metadata"] +50 | +51 | x: Arg("str", "name") + | ^^^^^ UP037 +52 | +53 | x: DefaultArg("str", "name") + | + = help: Remove quotes + +ℹ Fix +48 48 | +49 49 | x: Annotated["str", "metadata"] +50 50 | +51 |-x: Arg("str", "name") + 51 |+x: Arg(str, "name") +52 52 | +53 53 | x: DefaultArg("str", "name") +54 54 | + +UP037_0.py:53:15: UP037 [*] Remove quotes from type annotation + | +51 | x: Arg("str", "name") +52 | +53 | x: DefaultArg("str", "name") + | ^^^^^ UP037 +54 | +55 | x: NamedArg("str", "name") + | + = help: Remove quotes + +ℹ Fix +50 50 | +51 51 | x: Arg("str", "name") +52 52 | +53 |-x: DefaultArg("str", "name") + 53 |+x: DefaultArg(str, "name") +54 54 | +55 55 | x: NamedArg("str", "name") +56 56 | + +UP037_0.py:55:13: UP037 [*] Remove quotes from type annotation + | +53 | x: DefaultArg("str", "name") +54 | +55 | x: NamedArg("str", "name") + | ^^^^^ UP037 +56 | +57 | x: DefaultNamedArg("str", "name") + | + = help: Remove quotes + +ℹ Fix +52 52 | +53 53 | x: DefaultArg("str", "name") +54 54 | +55 |-x: NamedArg("str", "name") + 55 |+x: NamedArg(str, "name") +56 56 | +57 57 | x: DefaultNamedArg("str", "name") +58 58 | + +UP037_0.py:57:20: UP037 [*] Remove quotes from type annotation + | +55 | x: NamedArg("str", "name") +56 | +57 | x: DefaultNamedArg("str", "name") + | ^^^^^ UP037 +58 | +59 | x: DefaultNamedArg("str", name="name") + | + = help: Remove quotes + +ℹ Fix +54 54 | +55 55 | x: NamedArg("str", "name") +56 56 | +57 |-x: DefaultNamedArg("str", "name") + 57 |+x: DefaultNamedArg(str, "name") +58 58 | +59 59 | x: DefaultNamedArg("str", name="name") +60 60 | + +UP037_0.py:59:20: UP037 [*] Remove quotes from type annotation + | +57 | x: DefaultNamedArg("str", "name") +58 | +59 | x: DefaultNamedArg("str", name="name") + | ^^^^^ UP037 +60 | +61 | x: VarArg("str") + | + = help: Remove quotes + +ℹ Fix +56 56 | +57 57 | x: DefaultNamedArg("str", "name") +58 58 | +59 |-x: DefaultNamedArg("str", name="name") + 59 |+x: DefaultNamedArg(str, name="name") +60 60 | +61 61 | x: VarArg("str") +62 62 | + +UP037_0.py:61:11: UP037 [*] Remove quotes from type annotation + | +59 | x: DefaultNamedArg("str", name="name") +60 | +61 | x: VarArg("str") + | ^^^^^ UP037 +62 | +63 | x: List[List[List["MyClass"]]] + | + = help: Remove quotes + +ℹ Fix +58 58 | +59 59 | x: DefaultNamedArg("str", name="name") +60 60 | +61 |-x: VarArg("str") + 61 |+x: VarArg(str) +62 62 | +63 63 | x: List[List[List["MyClass"]]] +64 64 | + +UP037_0.py:63:19: UP037 [*] Remove quotes from type annotation + | +61 | x: VarArg("str") +62 | +63 | x: List[List[List["MyClass"]]] + | ^^^^^^^^^ UP037 +64 | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + | + = help: Remove quotes + +ℹ Fix +60 60 | +61 61 | x: VarArg("str") +62 62 | +63 |-x: List[List[List["MyClass"]]] + 63 |+x: List[List[List[MyClass]]] +64 64 | +65 65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 66 | + +UP037_0.py:65:29: UP037 [*] Remove quotes from type annotation + | +63 | x: List[List[List["MyClass"]]] +64 | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | + = help: Remove quotes + +ℹ Fix +62 62 | +63 63 | x: List[List[List["MyClass"]]] +64 64 | +65 |-x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + 65 |+x: NamedTuple("X", [("foo", int), ("bar", "str")]) +66 66 | +67 67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 68 | + +UP037_0.py:65:45: UP037 [*] Remove quotes from type annotation + | +63 | x: List[List[List["MyClass"]]] +64 | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | + = help: Remove quotes + +ℹ Fix +62 62 | +63 63 | x: List[List[List["MyClass"]]] +64 64 | +65 |-x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) + 65 |+x: NamedTuple("X", [("foo", "int"), ("bar", str)]) +66 66 | +67 67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 68 | + +UP037_0.py:67:29: UP037 [*] Remove quotes from type annotation + | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | + = help: Remove quotes + +ℹ Fix +64 64 | +65 65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 66 | +67 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + 67 |+x: NamedTuple("X", fields=[(foo, "int"), ("bar", "str")]) +68 68 | +69 69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) +70 70 | + +UP037_0.py:67:36: UP037 [*] Remove quotes from type annotation + | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | + = help: Remove quotes + +ℹ Fix +64 64 | +65 65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 66 | +67 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + 67 |+x: NamedTuple("X", fields=[("foo", int), ("bar", "str")]) +68 68 | +69 69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) +70 70 | + +UP037_0.py:67:45: UP037 [*] Remove quotes from type annotation + | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | + = help: Remove quotes + +ℹ Fix +64 64 | +65 65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 66 | +67 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + 67 |+x: NamedTuple("X", fields=[("foo", "int"), (bar, "str")]) +68 68 | +69 69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) +70 70 | + +UP037_0.py:67:52: UP037 [*] Remove quotes from type annotation + | +65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + | ^^^^^ UP037 +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | + = help: Remove quotes + +ℹ Fix +64 64 | +65 65 | x: NamedTuple("X", [("foo", "int"), ("bar", "str")]) +66 66 | +67 |-x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) + 67 |+x: NamedTuple("X", fields=[("foo", "int"), ("bar", str)]) +68 68 | +69 69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) +70 70 | + +UP037_0.py:69:24: UP037 [*] Remove quotes from type annotation + | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | ^^^ UP037 +70 | +71 | X: MyCallable("X") + | + = help: Remove quotes + +ℹ Fix +66 66 | +67 67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 68 | +69 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) + 69 |+x: NamedTuple(typename=X, fields=[("foo", "int")]) +70 70 | +71 71 | X: MyCallable("X") +72 72 | + +UP037_0.py:69:38: UP037 [*] Remove quotes from type annotation + | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | ^^^^^ UP037 +70 | +71 | X: MyCallable("X") + | + = help: Remove quotes + +ℹ Fix +66 66 | +67 67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 68 | +69 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) + 69 |+x: NamedTuple(typename="X", fields=[(foo, "int")]) +70 70 | +71 71 | X: MyCallable("X") +72 72 | + +UP037_0.py:69:45: UP037 [*] Remove quotes from type annotation + | +67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 | +69 | x: NamedTuple(typename="X", fields=[("foo", "int")]) + | ^^^^^ UP037 +70 | +71 | X: MyCallable("X") + | + = help: Remove quotes + +ℹ Fix +66 66 | +67 67 | x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")]) +68 68 | +69 |-x: NamedTuple(typename="X", fields=[("foo", "int")]) + 69 |+x: NamedTuple(typename="X", fields=[("foo", int)]) +70 70 | +71 71 | X: MyCallable("X") +72 72 | + + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_1.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_1.py.snap new file mode 100644 index 0000000000..22d8da416d --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP037_1.py.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +UP037_1.py:19:8: UP037 [*] Remove quotes from type annotation + | +18 | def foo(var: "MyClass") -> "MyClass": +19 | x: "MyClass" + | ^^^^^^^^^ UP037 + | + = help: Remove quotes + +ℹ Fix +16 16 | +17 17 | +18 18 | def foo(var: "MyClass") -> "MyClass": +19 |- x: "MyClass" + 19 |+ x: MyClass +20 20 | +21 21 | +22 22 | def foo(*, inplace: "bool"): + +