Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve quote style in generated code #15726

Merged
merged 54 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d78dfe4
prototype removing `Default` implementation for `StringLiteralFlags`
AlexWaygood Jan 24, 2025
efb3e45
preserve quotes for raw strings
ntBre Jan 23, 2025
d880234
test quotes on ruf055
ntBre Jan 23, 2025
52e45f7
preserve quotes for other string literals
ntBre Jan 23, 2025
c1f0bc5
update a round trip test
ntBre Jan 23, 2025
72f8c67
delete set_quote test, add note to round_trip_with
ntBre Jan 23, 2025
7b17b34
add StringLiteralValue::flags
ntBre Jan 24, 2025
514a3eb
propagate flags through pt006
ntBre Jan 24, 2025
418fcc6
propagate flags through sim905
ntBre Jan 24, 2025
18cfc02
accept preserved quotes for SIM905
ntBre Jan 24, 2025
5c28bb5
fix 8 tc006 tests by passing along stylist.quote
ntBre Jan 24, 2025
7031a91
accept preserved quotes for tc006
ntBre Jan 24, 2025
7a638f9
accept new flake8 quotes
ntBre Jan 24, 2025
8f70e58
pass along flags for fly002
ntBre Jan 24, 2025
0509f80
update more generator tests
ntBre Jan 24, 2025
6c86e1a
use checker.stylist().quote() for encoding
ntBre Jan 24, 2025
6c0322d
add DYNAMIC string flag
ntBre Jan 24, 2025
fbbb150
check for dynamic quotes in unparse_string_literal
ntBre Jan 24, 2025
bf430d7
use dynamic quotes in up018
ntBre Jan 24, 2025
64662a7
use dynamic quotes in ruf030
ntBre Jan 24, 2025
4c07cda
Merge remote-tracking branch 'alex/alex/stringflags-prototype' into b…
ntBre Jan 24, 2025
a14cbf0
still need dynamic behavior for UP018
ntBre Jan 24, 2025
66542e2
we do need the whole flag for prefixes, not just quotes
ntBre Jan 24, 2025
2c5bdad
fix docs
ntBre Jan 24, 2025
50ee561
delete leftover flags code
ntBre Jan 24, 2025
8594b6f
add a regression test for #14132 that fails on main
ntBre Jan 24, 2025
25ef7fc
factor out Checker::preferred_quote and default_string_flags
ntBre Jan 25, 2025
e3dbe8e
delete StringLiteralFlags::from(stylist), replace with default_flags
ntBre Jan 25, 2025
3720e0b
delete DYNAMIC flag
ntBre Jan 25, 2025
3b5ca11
get flags in loop
ntBre Jan 25, 2025
18a998e
add QuoteRewriter
ntBre Jan 26, 2025
50aed8e
Revert "accept new flake8 quotes"
ntBre Jan 26, 2025
9b6c393
Revert "accept preserved quotes for tc006"
ntBre Jan 26, 2025
3e89384
make StringLiteralFlags::empty pub(crate)
ntBre Jan 26, 2025
37dd162
use preferred_quote
ntBre Jan 26, 2025
1fd1846
pass down StringLiteralFlags instead of Quote
ntBre Jan 26, 2025
d39ffe7
update docstring
ntBre Jan 26, 2025
74f8aaa
make preferred_quote private
ntBre Jan 26, 2025
fc1fd19
document StringLiteralFlags::new with manual links
ntBre Jan 26, 2025
bfd5c0d
update Generator::quote docs
ntBre Jan 26, 2025
28070d9
resurrect set_quote test
ntBre Jan 26, 2025
78f4642
switch to bytestrings
ntBre Jan 26, 2025
648ad8a
test all string types
ntBre Jan 26, 2025
37c583e
document QuoteRewriter
ntBre Jan 27, 2025
67bb04d
local -> locale
ntBre Jan 27, 2025
4ac9851
simplify generate_keyword_fix
ntBre Jan 27, 2025
3e26565
update docs
ntBre Jan 27, 2025
e4019f6
update expected result comments for sim905
ntBre Jan 27, 2025
8205cbf
remove StringLiteralFlags::new, update docs
ntBre Jan 27, 2025
2d80567
update docstring
ntBre Jan 27, 2025
d61122e
fix docs error
ntBre Jan 27, 2025
4b6ef41
class -> struct
ntBre Jan 27, 2025
afe0df7
use StringLiteralFlags::empty in Normalizer test
ntBre Jan 27, 2025
06da812
just use empty
ntBre Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/ruff/RUF055_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,8 @@ def dashrepl(matchobj):

re.sub(r"a", "\?", "a")
re.sub(r"a", r"\?", "a")

# these double as tests for preserving raw string quoting style
re.sub(r'abc', "", s)
re.sub(r"""abc""", "", s)
re.sub(r'''abc''', "", s)
2 changes: 1 addition & 1 deletion crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
checker,
attr,
call,
string_value.to_str(),
string_value,
);
}
} else if attr == "format" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext};
use ruff_python_codegen::Generator;
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext, StringLiteralFlags};
use ruff_python_codegen::{Generator, Stylist};
use ruff_python_trivia::CommentRanges;
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange, TextSize};
Expand Down Expand Up @@ -280,7 +280,7 @@ impl Violation for PytestDuplicateParametrizeTestCases {
}
}

fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
fn elts_to_csv(elts: &[Expr], generator: Generator, stylist: &Stylist) -> Option<String> {
if !elts.iter().all(Expr::is_string_literal_expr) {
return None;
}
Expand All @@ -298,7 +298,8 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
acc
})
.into_boxed_str(),
..ast::StringLiteral::default()
range: TextRange::default(),
flags: StringLiteralFlags::from(stylist),
});
Some(generator.expr(&node))
}
Expand Down Expand Up @@ -358,8 +359,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
.iter()
.map(|name| {
Expr::from(ast::StringLiteral {
value: (*name).to_string().into_boxed_str(),
..ast::StringLiteral::default()
value: Box::from(*name),
range: TextRange::default(),
flags: StringLiteralFlags::from(checker.stylist()),
})
})
.collect(),
Expand Down Expand Up @@ -393,8 +395,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
.iter()
.map(|name| {
Expr::from(ast::StringLiteral {
value: (*name).to_string().into_boxed_str(),
..ast::StringLiteral::default()
value: Box::from(*name),
range: TextRange::default(),
flags: StringLiteralFlags::from(checker.stylist()),
})
})
.collect(),
Expand Down Expand Up @@ -444,7 +447,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
},
expr.range(),
);
if let Some(content) = elts_to_csv(elts, checker.generator()) {
if let Some(content) =
elts_to_csv(elts, checker.generator(), checker.stylist())
{
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
content,
expr.range(),
Expand Down Expand Up @@ -489,7 +494,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
},
expr.range(),
);
if let Some(content) = elts_to_csv(elts, checker.generator()) {
if let Some(content) =
elts_to_csv(elts, checker.generator(), checker.stylist())
{
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
content,
expr.range(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use ruff_python_ast::{
self as ast, str_prefix::StringLiteralPrefix, Arguments, Expr, StringLiteralFlags,
};
use ruff_text_size::Ranged;
use ruff_text_size::{Ranged, TextRange};

use crate::fix::snippet::SourceCodeSnippet;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation};
Expand Down Expand Up @@ -220,14 +220,14 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
);
let node = ast::StringLiteral {
value: capital_env_var.into_boxed_str(),
flags: StringLiteralFlags::default().with_prefix({
flags: StringLiteralFlags::from(checker.stylist()).with_prefix({
if env_var.is_unicode() {
StringLiteralPrefix::Unicode
} else {
StringLiteralPrefix::Empty
}
}),
..ast::StringLiteral::default()
range: TextRange::default(),
};
let new_env_var = node.into();
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub(crate) fn split_static_string(
checker: &mut Checker,
attr: &str,
call: &ExprCall,
str_value: &str,
str_value: &StringLiteralValue,
) {
let ExprCall { arguments, .. } = call;

Expand Down Expand Up @@ -115,16 +115,16 @@ pub(crate) fn split_static_string(
checker.diagnostics.push(diagnostic);
}

fn construct_replacement(elts: &[&str]) -> Expr {
fn construct_replacement(elts: &[&str], flags: StringLiteralFlags) -> Expr {
Expr::List(ExprList {
elts: elts
.iter()
.map(|elt| {
Expr::StringLiteral(ExprStringLiteral {
value: StringLiteralValue::single(StringLiteral {
value: (*elt).to_string().into_boxed_str(),
value: Box::from(*elt),
range: TextRange::default(),
flags: StringLiteralFlags::default(),
flags,
}),
range: TextRange::default(),
})
Expand All @@ -135,7 +135,7 @@ fn construct_replacement(elts: &[&str]) -> Expr {
})
}

fn split_default(str_value: &str, max_split: i32) -> Option<Expr> {
fn split_default(str_value: &StringLiteralValue, max_split: i32) -> Option<Expr> {
// From the Python documentation:
// > If sep is not specified or is None, a different splitting algorithm is applied: runs of
// > consecutive whitespace are regarded as a single separator, and the result will contain
Expand All @@ -151,30 +151,36 @@ fn split_default(str_value: &str, max_split: i32) -> Option<Expr> {
None
}
Ordering::Equal => {
let list_items: Vec<&str> = vec![str_value];
Some(construct_replacement(&list_items))
let list_items: Vec<&str> = vec![str_value.to_str()];
Some(construct_replacement(&list_items, str_value.flags()))
}
Ordering::Less => {
let list_items: Vec<&str> = str_value.split_whitespace().collect();
Some(construct_replacement(&list_items))
let list_items: Vec<&str> = str_value.to_str().split_whitespace().collect();
Some(construct_replacement(&list_items, str_value.flags()))
}
}
}

fn split_sep(str_value: &str, sep_value: &str, max_split: i32, direction: Direction) -> Expr {
fn split_sep(
str_value: &StringLiteralValue,
sep_value: &str,
max_split: i32,
direction: Direction,
) -> Expr {
let value = str_value.to_str();
let list_items: Vec<&str> = if let Ok(split_n) = usize::try_from(max_split) {
match direction {
Direction::Left => str_value.splitn(split_n + 1, sep_value).collect(),
Direction::Right => str_value.rsplitn(split_n + 1, sep_value).collect(),
Direction::Left => value.splitn(split_n + 1, sep_value).collect(),
Direction::Right => value.rsplitn(split_n + 1, sep_value).collect(),
}
} else {
match direction {
Direction::Left => str_value.split(sep_value).collect(),
Direction::Right => str_value.rsplit(sep_value).collect(),
Direction::Left => value.split(sep_value).collect(),
Direction::Right => value.rsplit(sep_value).collect(),
}
};

construct_replacement(&list_items)
construct_replacement(&list_items, str_value.flags())
}

/// Returns the value of the `maxsplit` argument as an `i32`, if it is a numeric value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ SIM905.py:29:1: SIM905 [*] Consider using a list literal instead of `str.split`
27 27 | "a,b,c,d".split(maxsplit=0)
28 28 | "VERB AUX PRON ADP DET".split(" ")
29 |-' 1 2 3 '.split()
29 |+["1", "2", "3"]
29 |+['1', '2', '3']
30 30 | '1<>2<>3<4'.split('<>')
31 31 |
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
Expand All @@ -340,7 +340,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
28 28 | "VERB AUX PRON ADP DET".split(" ")
29 29 | ' 1 2 3 '.split()
30 |-'1<>2<>3<4'.split('<>')
30 |+["1", "2", "3<4"]
30 |+['1', '2', '3<4']
31 31 |
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
33 33 | "".split() # []
Expand Down Expand Up @@ -569,7 +569,7 @@ SIM905.py:58:1: SIM905 [*] Consider using a list literal instead of `str.split`
56 56 |
57 57 | # prefixes and isc
58 |-u"a b".split() # ['a', 'b']
58 |+["a", "b"] # ['a', 'b']
58 |+[u"a", u"b"] # ['a', 'b']
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
60 60 | ("a " "b").split() # ['a', 'b']
61 61 | "a " "b".split() # ['a', 'b']
Expand All @@ -590,7 +590,7 @@ SIM905.py:59:1: SIM905 [*] Consider using a list literal instead of `str.split`
57 57 | # prefixes and isc
58 58 | u"a b".split() # ['a', 'b']
59 |-r"a \n b".split() # ['a', '\\n', 'b']
59 |+["a", "\\n", "b"] # ['a', '\\n', 'b']
59 |+[r"a", r"\n", r"b"] # ['a', '\\n', 'b']
60 60 | ("a " "b").split() # ['a', 'b']
61 61 | "a " "b".split() # ['a', 'b']
62 62 | u"a " "b".split() # ['a', 'b']
Expand Down Expand Up @@ -653,7 +653,7 @@ SIM905.py:62:1: SIM905 [*] Consider using a list literal instead of `str.split`
60 60 | ("a " "b").split() # ['a', 'b']
61 61 | "a " "b".split() # ['a', 'b']
62 |-u"a " "b".split() # ['a', 'b']
62 |+["a", "b"] # ['a', 'b']
62 |+[u"a", u"b"] # ['a', 'b']
63 63 | "a " u"b".split() # ['a', 'b']
64 64 | u"a " r"\n".split() # ['a', '\\n']
65 65 | r"\n " u"\n".split() # ['\\n']
Expand Down Expand Up @@ -695,7 +695,7 @@ SIM905.py:64:1: SIM905 [*] Consider using a list literal instead of `str.split`
62 62 | u"a " "b".split() # ['a', 'b']
63 63 | "a " u"b".split() # ['a', 'b']
64 |-u"a " r"\n".split() # ['a', '\\n']
64 |+["a", "\\n"] # ['a', '\\n']
64 |+[u"a", u"\\n"] # ['a', '\\n']
65 65 | r"\n " u"\n".split() # ['\\n']
66 66 | r"\n " "\n".split() # ['\\n']
67 67 | "a " r"\n".split() # ['a', '\\n']
Expand All @@ -716,7 +716,7 @@ SIM905.py:65:1: SIM905 [*] Consider using a list literal instead of `str.split`
63 63 | "a " u"b".split() # ['a', 'b']
64 64 | u"a " r"\n".split() # ['a', '\\n']
65 |-r"\n " u"\n".split() # ['\\n']
65 |+["\\n"] # ['\\n']
65 |+[r"\n"] # ['\\n']
66 66 | r"\n " "\n".split() # ['\\n']
67 67 | "a " r"\n".split() # ['a', '\\n']
68 68 |
Expand All @@ -736,7 +736,7 @@ SIM905.py:66:1: SIM905 [*] Consider using a list literal instead of `str.split`
64 64 | u"a " r"\n".split() # ['a', '\\n']
65 65 | r"\n " u"\n".split() # ['\\n']
66 |-r"\n " "\n".split() # ['\\n']
66 |+["\\n"] # ['\\n']
66 |+[r"\n"] # ['\\n']
67 67 | "a " r"\n".split() # ['a', '\\n']
68 68 |
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ impl<'a> QuoteAnnotator<'a> {
generator.expr(&Expr::from(ast::StringLiteral {
range: TextRange::default(),
value: annotation.into_boxed_str(),
flags: ast::StringLiteralFlags::default(),
flags: ast::StringLiteralFlags::from(self.stylist),
}))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ quote.py:47:24: TC002 [*] Move third-party import `pandas.DataFrame` into a type
47 |- from pandas import DataFrame
48 51 |
49 |- def baz() -> DataFrame[Literal["int"]]:
52 |+ def baz() -> "DataFrame[Literal['int']]":
52 |+ def baz() -> 'DataFrame[Literal["int"]]':
50 53 | ...
51 54 |
52 55 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ quote2.py:25:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
25 |- from django.contrib.auth.models import AbstractBaseUser
26 29 |
27 |- def test_literal_annotation_args_contain_quotes(self, type1: AbstractBaseUser[Literal["user", "admin"], Annotated["int", "1", 2]]):
30 |+ def test_literal_annotation_args_contain_quotes(self, type1: "AbstractBaseUser[Literal['user', 'admin'], Annotated[int, '1', 2]]"):
30 |+ def test_literal_annotation_args_contain_quotes(self, type1: 'AbstractBaseUser[Literal["user", "admin"], Annotated[int, "1", 2]]'):
28 31 | pass
29 32 |
30 33 |
Expand Down Expand Up @@ -142,7 +142,7 @@ quote2.py:34:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
34 |- from django.contrib.auth.models import AbstractBaseUser
35 38 |
36 |- def test_union_contain_inner_quotes(self, type1: AbstractBaseUser["int" | Literal["int"]]):
39 |+ def test_union_contain_inner_quotes(self, type1: "AbstractBaseUser[int | Literal['int']]"):
39 |+ def test_union_contain_inner_quotes(self, type1: 'AbstractBaseUser[int | Literal["int"]]'):
37 40 | pass
38 41 |
39 42 |
Expand Down Expand Up @@ -173,7 +173,7 @@ quote2.py:43:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
43 |- from django.contrib.auth.models import AbstractBaseUser
44 47 |
45 |- def test_inner_literal_mixed_quotes(user: AbstractBaseUser[Literal['user', "admin"]]):
48 |+ def test_inner_literal_mixed_quotes(user: "AbstractBaseUser[Literal['user', 'admin']]"):
48 |+ def test_inner_literal_mixed_quotes(user: "AbstractBaseUser[Literal['user', \"admin\"]]"):
46 49 | pass
47 50 |
48 51 |
Expand Down Expand Up @@ -266,7 +266,7 @@ quote2.py:70:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
70 |- from django.contrib.auth.models import AbstractBaseUser
71 74 |
72 |- def test_annotated_literal_mixed_quotes(user: AbstractBaseUser[Annotated[str, "max_length=20", Literal['user', "admin"]]]):
75 |+ def test_annotated_literal_mixed_quotes(user: "AbstractBaseUser[Annotated[str, 'max_length=20', Literal['user', 'admin']]]"):
75 |+ def test_annotated_literal_mixed_quotes(user: "AbstractBaseUser[Annotated[str, \"max_length=20\", Literal['user', \"admin\"]]]"):
73 76 | pass
74 77 |
75 78 |
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ quote3.py:4:44: TC002 [*] Move third-party import `django.contrib.auth.models.Ab
4 |- from django.contrib.auth.models import AbstractBaseUser
5 8 |
6 |- def test_union_literal_mixed_quotes(user: AbstractBaseUser[Union[Literal['active', "inactive"], str]]):
9 |+ def test_union_literal_mixed_quotes(user: 'AbstractBaseUser[Union[Literal["active", "inactive"], str]]'):
9 |+ def test_union_literal_mixed_quotes(user: 'AbstractBaseUser[Union[Literal[\'active\', "inactive"], str]]'):
7 10 | pass
8 11 |
9 12 |
Expand Down Expand Up @@ -54,7 +54,7 @@ quote3.py:13:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
13 |- from django.contrib.auth.models import AbstractBaseUser
14 17 |
15 |- def test_callable_literal_mixed_quotes(callable_fn: AbstractBaseUser[Callable[["int", Literal['admin', "user"]], 'bool']]):
18 |+ def test_callable_literal_mixed_quotes(callable_fn: 'AbstractBaseUser[Callable[[int, Literal["admin", "user"]], bool]]'):
18 |+ def test_callable_literal_mixed_quotes(callable_fn: 'AbstractBaseUser[Callable[[int, Literal[\'admin\', "user"]], bool]]'):
16 19 | pass
17 20 |
18 21 |
Expand Down Expand Up @@ -85,7 +85,7 @@ quote3.py:22:44: TC002 [*] Move third-party import `django.contrib.auth.models.A
22 |- from django.contrib.auth.models import AbstractBaseUser
23 26 |
24 |- def test_callable_annotated_literal(callable_fn: AbstractBaseUser[Callable[[int, Annotated[str, Literal['active', "inactive"]]], bool]]):
27 |+ def test_callable_annotated_literal(callable_fn: 'AbstractBaseUser[Callable[[int, Annotated[str, Literal["active", "inactive"]]], bool]]'):
27 |+ def test_callable_annotated_literal(callable_fn: 'AbstractBaseUser[Callable[[int, Annotated[str, Literal[\'active\', "inactive"]]], bool]]'):
25 28 | pass
26 29 |
27 30 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ TC006.py:52:12: TC006 [*] Add quotes to type expression in `typing.cast()`
50 50 | import typing as t
51 51 |
52 |- t.cast(t.Literal["3.0", '3'], 3.0) # TC006
52 |+ t.cast("t.Literal['3.0', '3']", 3.0) # TC006
52 |+ t.cast("t.Literal[\"3.0\", '3']", 3.0) # TC006
53 53 |
54 54 |
55 55 | def f():
Expand Down Expand Up @@ -170,7 +170,7 @@ TC006.py:75:10: TC006 [*] Add quotes to type expression in `typing.cast()`
73 73 | from typing import cast, Literal
74 74 |
75 |- cast(Literal["A"], 'A')
75 |+ cast("Literal['A']", 'A')
75 |+ cast('Literal["A"]', 'A')
76 76 |
77 77 |
78 78 | def f():
Expand All @@ -189,7 +189,7 @@ TC006.py:82:10: TC006 [*] Add quotes to type expression in `typing.cast()`
80 80 | from typing import cast, Annotated, Literal
81 81 |
82 |- cast(list[Annotated["list['Literal[\"A\"]']", "Foo"]], ['A'])
82 |+ cast("list[Annotated[list[Literal['A']], 'Foo']]", ['A'])
82 |+ cast('list[Annotated[list[Literal["A"]], "Foo"]]', ['A'])
83 83 |
84 84 |
85 85 | def f():
Expand Down
Loading
Loading