[`pyupgrade`]: Removes quotes from annotations (#2431)

This commit is contained in:
Colin Delahunty 2023-02-05 09:43:09 -05:00 committed by GitHub
parent 84be1df9d5
commit 1e1dc3a7ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 782 additions and 12 deletions

View File

@ -857,6 +857,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/) on PyPI.
| UP034 | extraneous-parentheses | Avoid extraneous parentheses | 🛠 |
| UP035 | import-replacements | Import from `{module}` instead: {names} | 🛠 |
| UP036 | outdated-version-block | Version block is outdated for minimum Python version | 🛠 |
| UP037 | quoted-annotation | Remove quotes from type annotation | 🛠 |
### flake8-2020 (YTT)

View File

@ -0,0 +1,108 @@
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 = TypeVar("x", "str", "int")
x = cast("str", x)
X = List["MyClass"]
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] = ...

View File

@ -1950,6 +1950,7 @@
"UP034",
"UP035",
"UP036",
"UP037",
"W",
"W2",
"W29",

View File

@ -3349,20 +3349,37 @@ where
Some(Callable::MypyExtension) => {
self.visit_expr(func);
// Ex) DefaultNamedArg(bool | None, name="some_prop_name")
let mut arguments = args.iter().chain(keywords.iter().map(|keyword| {
let KeywordData { value, .. } = &keyword.node;
value
}));
if let Some(expr) = arguments.next() {
if let Some(arg) = args.first() {
// Ex) DefaultNamedArg(bool | None, name="some_prop_name")
self.in_type_definition = true;
self.visit_expr(expr);
self.in_type_definition = prev_in_type_definition;
}
for expr in arguments {
self.in_type_definition = false;
self.visit_expr(expr);
self.visit_expr(arg);
self.in_type_definition = prev_in_type_definition;
for arg in args.iter().skip(1) {
self.in_type_definition = false;
self.visit_expr(arg);
self.in_type_definition = prev_in_type_definition;
}
for keyword in keywords {
let KeywordData { value, .. } = &keyword.node;
self.in_type_definition = false;
self.visit_expr(value);
self.in_type_definition = prev_in_type_definition;
}
} else {
// Ex) DefaultNamedArg(type="bool", name="some_prop_name")
for keyword in keywords {
let KeywordData { value, arg, .. } = &keyword.node;
if arg.as_ref().map_or(false, |arg| arg == "type") {
self.in_type_definition = true;
self.visit_expr(value);
self.in_type_definition = prev_in_type_definition;
} else {
self.in_type_definition = false;
self.visit_expr(value);
self.in_type_definition = prev_in_type_definition;
}
}
}
}
None => {
@ -4366,6 +4383,11 @@ impl<'a> Checker<'a> {
self.deferred_string_type_definitions.pop()
{
if let Ok(mut expr) = parser::parse_expression(expression, "<filename>") {
if self.annotations_future_enabled {
if self.settings.rules.enabled(&Rule::QuotedAnnotation) {
pyupgrade::rules::quoted_annotation(self, expression, range);
}
}
relocate_expr(&mut expr, range);
allocator.push(expr);
stacks.push((in_annotation, context));

View File

@ -260,6 +260,7 @@ ruff_macros::define_rule_mapping!(
UP034 => rules::pyupgrade::rules::ExtraneousParentheses,
UP035 => rules::pyupgrade::rules::ImportReplacements,
UP036 => rules::pyupgrade::rules::OutdatedVersionBlock,
UP037 => rules::pyupgrade::rules::QuotedAnnotation,
// pydocstyle
D100 => rules::pydocstyle::rules::PublicModule,
D101 => rules::pydocstyle::rules::PublicClass,

View File

@ -64,6 +64,7 @@ mod tests {
#[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_2.py"); "UP036_2")]
#[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_3.py"); "UP036_3")]
#[test_case(Rule::OutdatedVersionBlock, Path::new("UP036_4.py"); "UP036_4")]
#[test_case(Rule::QuotedAnnotation, Path::new("UP037.py"); "UP037")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
let diagnostics = test_path(

View File

@ -19,6 +19,7 @@ pub(crate) use open_alias::{open_alias, OpenAlias};
pub(crate) use os_error_alias::{os_error_alias, OSErrorAlias};
pub(crate) use outdated_version_block::{outdated_version_block, OutdatedVersionBlock};
pub(crate) use printf_string_formatting::{printf_string_formatting, PrintfStringFormatting};
pub(crate) use quoted_annotation::{quoted_annotation, QuotedAnnotation};
pub(crate) use redundant_open_modes::{redundant_open_modes, RedundantOpenModes};
pub(crate) use replace_stdout_stderr::{replace_stdout_stderr, ReplaceStdoutStderr};
pub(crate) use replace_universal_newlines::{replace_universal_newlines, ReplaceUniversalNewlines};
@ -59,6 +60,7 @@ mod open_alias;
mod os_error_alias;
mod outdated_version_block;
mod printf_string_formatting;
mod quoted_annotation;
mod redundant_open_modes;
mod replace_stdout_stderr;
mod replace_universal_newlines;

View File

@ -0,0 +1,35 @@
use ruff_macros::derive_message_formats;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::define_violation;
use crate::fix::Fix;
use crate::registry::{Diagnostic, Rule};
use crate::violation::AlwaysAutofixableViolation;
define_violation!(
pub struct QuotedAnnotation;
);
impl AlwaysAutofixableViolation for QuotedAnnotation {
#[derive_message_formats]
fn message(&self) -> String {
format!("Remove quotes from type annotation")
}
fn autofix_title(&self) -> String {
"Remove quotes".to_string()
}
}
/// UP037
pub fn quoted_annotation(checker: &mut Checker, annotation: &str, range: Range) {
let mut diagnostic = Diagnostic::new(QuotedAnnotation, range);
if checker.patch(&Rule::QuotedAnnotation) {
diagnostic.amend(Fix::replacement(
annotation.to_string(),
range.location,
range.end_location,
));
}
checker.diagnostics.push(diagnostic);
}

View File

@ -0,0 +1,599 @@
---
source: src/rules/pyupgrade/mod.rs
expression: diagnostics
---
- kind:
QuotedAnnotation: ~
location:
row: 18
column: 13
end_location:
row: 18
column: 22
fix:
content:
- MyClass
location:
row: 18
column: 13
end_location:
row: 18
column: 22
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 18
column: 27
end_location:
row: 18
column: 36
fix:
content:
- MyClass
location:
row: 18
column: 27
end_location:
row: 18
column: 36
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 19
column: 7
end_location:
row: 19
column: 16
fix:
content:
- MyClass
location:
row: 19
column: 7
end_location:
row: 19
column: 16
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 22
column: 20
end_location:
row: 22
column: 26
fix:
content:
- bool
location:
row: 22
column: 20
end_location:
row: 22
column: 26
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 26
column: 15
end_location:
row: 26
column: 20
fix:
content:
- str
location:
row: 26
column: 15
end_location:
row: 26
column: 20
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 26
column: 32
end_location:
row: 26
column: 37
fix:
content:
- int
location:
row: 26
column: 32
end_location:
row: 26
column: 37
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 30
column: 9
end_location:
row: 30
column: 18
fix:
content:
- MyClass
location:
row: 30
column: 9
end_location:
row: 30
column: 18
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 32
column: 13
end_location:
row: 32
column: 22
fix:
content:
- MyClass
location:
row: 32
column: 13
end_location:
row: 32
column: 22
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 36
column: 7
end_location:
row: 36
column: 16
fix:
content:
- MyClass
location:
row: 36
column: 7
end_location:
row: 36
column: 16
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 40
column: 26
end_location:
row: 40
column: 31
fix:
content:
- int
location:
row: 40
column: 26
end_location:
row: 40
column: 31
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 44
column: 30
end_location:
row: 44
column: 35
fix:
content:
- int
location:
row: 44
column: 30
end_location:
row: 44
column: 35
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 47
column: 13
end_location:
row: 47
column: 18
fix:
content:
- str
location:
row: 47
column: 13
end_location:
row: 47
column: 18
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 49
column: 7
end_location:
row: 49
column: 12
fix:
content:
- str
location:
row: 49
column: 7
end_location:
row: 49
column: 12
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 51
column: 14
end_location:
row: 51
column: 19
fix:
content:
- str
location:
row: 51
column: 14
end_location:
row: 51
column: 19
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 53
column: 12
end_location:
row: 53
column: 17
fix:
content:
- str
location:
row: 53
column: 12
end_location:
row: 53
column: 17
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 55
column: 19
end_location:
row: 55
column: 24
fix:
content:
- str
location:
row: 55
column: 19
end_location:
row: 55
column: 24
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 57
column: 19
end_location:
row: 57
column: 24
fix:
content:
- str
location:
row: 57
column: 19
end_location:
row: 57
column: 24
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 59
column: 10
end_location:
row: 59
column: 15
fix:
content:
- str
location:
row: 59
column: 10
end_location:
row: 59
column: 15
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 61
column: 18
end_location:
row: 61
column: 27
fix:
content:
- MyClass
location:
row: 61
column: 18
end_location:
row: 61
column: 27
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 63
column: 28
end_location:
row: 63
column: 33
fix:
content:
- int
location:
row: 63
column: 28
end_location:
row: 63
column: 33
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 63
column: 44
end_location:
row: 63
column: 49
fix:
content:
- str
location:
row: 63
column: 44
end_location:
row: 63
column: 49
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 65
column: 28
end_location:
row: 65
column: 33
fix:
content:
- foo
location:
row: 65
column: 28
end_location:
row: 65
column: 33
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 65
column: 35
end_location:
row: 65
column: 40
fix:
content:
- int
location:
row: 65
column: 35
end_location:
row: 65
column: 40
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 65
column: 44
end_location:
row: 65
column: 49
fix:
content:
- bar
location:
row: 65
column: 44
end_location:
row: 65
column: 49
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 65
column: 51
end_location:
row: 65
column: 56
fix:
content:
- str
location:
row: 65
column: 51
end_location:
row: 65
column: 56
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 67
column: 23
end_location:
row: 67
column: 26
fix:
content:
- X
location:
row: 67
column: 23
end_location:
row: 67
column: 26
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 67
column: 37
end_location:
row: 67
column: 42
fix:
content:
- foo
location:
row: 67
column: 37
end_location:
row: 67
column: 42
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 67
column: 44
end_location:
row: 67
column: 49
fix:
content:
- int
location:
row: 67
column: 44
end_location:
row: 67
column: 49
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 69
column: 17
end_location:
row: 69
column: 22
fix:
content:
- str
location:
row: 69
column: 17
end_location:
row: 69
column: 22
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 69
column: 24
end_location:
row: 69
column: 29
fix:
content:
- int
location:
row: 69
column: 24
end_location:
row: 69
column: 29
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 71
column: 9
end_location:
row: 71
column: 14
fix:
content:
- str
location:
row: 71
column: 9
end_location:
row: 71
column: 14
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 73
column: 9
end_location:
row: 73
column: 18
fix:
content:
- MyClass
location:
row: 73
column: 9
end_location:
row: 73
column: 18
parent: ~
- kind:
QuotedAnnotation: ~
location:
row: 75
column: 14
end_location:
row: 75
column: 17
fix:
content:
- X
location:
row: 75
column: 14
end_location:
row: 75
column: 17
parent: ~