Skip to content

Commit

Permalink
Expand scope of quoted-annotation rule
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jul 14, 2023
1 parent 81b88dc commit 402b3c7
Show file tree
Hide file tree
Showing 7 changed files with 699 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""A mirror of UP037_1.py, with `from __future__ import annotations`."""

from __future__ import annotations

from typing import (
Expand Down
108 changes: 108 additions & 0 deletions crates/ruff/resources/test/fixtures/pyupgrade/UP037_1.py
Original file line number Diff line number Diff line change
@@ -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"]
2 changes: 1 addition & 1 deletion crates/ruff/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4586,7 +4586,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);
}
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/pyupgrade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
5 changes: 5 additions & 0 deletions crates/ruff/src/rules/pyupgrade/rules/quoted_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 402b3c7

Please sign in to comment.