mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 05:25:17 +00:00
Preserve quote style in generated code (#15726)
## Summary This is a first step toward fixing #7799 by using the quoting style stored in the `flags` field on `ast::StringLiteral`s to select a quoting style. This PR does not include support for f-strings or byte strings. Several rules also needed small updates to pass along existing quoting styles instead of using `StringLiteralFlags::default()`. The remaining snapshot changes are intentional and should preserve the quotes from the input strings. ## Test Plan Existing tests with some accepted updates, plus a few new RUF055 tests for raw strings. --------- Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
e994970538
commit
9bf138c45a
24 changed files with 550 additions and 343 deletions
|
@ -29,47 +29,47 @@ no_sep = None
|
||||||
' 1 2 3 '.split()
|
' 1 2 3 '.split()
|
||||||
'1<>2<>3<4'.split('<>')
|
'1<>2<>3<4'.split('<>')
|
||||||
|
|
||||||
" a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
" a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
"".split() # []
|
"".split() # []
|
||||||
"""
|
"""
|
||||||
""".split() # []
|
""".split() # []
|
||||||
" ".split() # []
|
" ".split() # []
|
||||||
"/abc/".split() # ['/abc/']
|
"/abc/".split() # ["/abc/"]
|
||||||
("a,b,c"
|
("a,b,c"
|
||||||
# comment
|
# comment
|
||||||
.split()
|
.split()
|
||||||
) # ['a,b,c']
|
) # ["a,b,c"]
|
||||||
("a,b,c"
|
("a,b,c"
|
||||||
# comment1
|
# comment1
|
||||||
.split(",")
|
.split(",")
|
||||||
) # ['a', 'b', 'c']
|
) # ["a", "b", "c"]
|
||||||
("a,"
|
("a,"
|
||||||
# comment
|
# comment
|
||||||
"b,"
|
"b,"
|
||||||
"c"
|
"c"
|
||||||
.split(",")
|
.split(",")
|
||||||
) # ['a', 'b', 'c']
|
) # ["a", "b", "c"]
|
||||||
|
|
||||||
"hello "\
|
"hello "\
|
||||||
"world".split()
|
"world".split()
|
||||||
# ['hello', 'world']
|
# ["hello", "world"]
|
||||||
|
|
||||||
# prefixes and isc
|
# prefixes and isc
|
||||||
u"a b".split() # ['a', 'b']
|
u"a b".split() # [u"a", u"b"]
|
||||||
r"a \n b".split() # ['a', '\\n', 'b']
|
r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
("a " "b").split() # ['a', 'b']
|
("a " "b").split() # ["a", "b"]
|
||||||
"a " "b".split() # ['a', 'b']
|
"a " "b".split() # ["a", "b"]
|
||||||
u"a " "b".split() # ['a', 'b']
|
u"a " "b".split() # [u"a", u"b"]
|
||||||
"a " u"b".split() # ['a', 'b']
|
"a " u"b".split() # ["a", "b"]
|
||||||
u"a " r"\n".split() # ['a', '\\n']
|
u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
r"\n " u"\n".split() # ['\\n']
|
r"\n " u"\n".split() # [r"\n"]
|
||||||
r"\n " "\n".split() # ['\\n']
|
r"\n " "\n".split() # [r"\n"]
|
||||||
"a " r"\n".split() # ['a', '\\n']
|
"a " r"\n".split() # ["a", "\\n"]
|
||||||
|
|
||||||
"a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
"a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
"a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
"a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
"a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
"a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
"a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
"a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
|
|
||||||
# negatives
|
# negatives
|
||||||
|
|
||||||
|
|
|
@ -82,3 +82,11 @@ class Collection(Protocol[*_B0]):
|
||||||
# Regression test for: https://github.com/astral-sh/ruff/issues/8609
|
# Regression test for: https://github.com/astral-sh/ruff/issues/8609
|
||||||
def f(x: Union[int, str, bytes]) -> None:
|
def f(x: Union[int, str, bytes]) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Regression test for https://github.com/astral-sh/ruff/issues/14132
|
||||||
|
class AClass:
|
||||||
|
...
|
||||||
|
|
||||||
|
def myfunc(param: "tuple[Union[int, 'AClass', None], str]"):
|
||||||
|
print(param)
|
||||||
|
|
|
@ -93,3 +93,8 @@ re.sub(r"a", r"\a", "a")
|
||||||
|
|
||||||
re.sub(r"a", "\?", "a")
|
re.sub(r"a", "\?", "a")
|
||||||
re.sub(r"a", r"\?", "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)
|
||||||
|
|
|
@ -506,7 +506,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||||
checker,
|
checker,
|
||||||
attr,
|
attr,
|
||||||
call,
|
call,
|
||||||
string_value.to_str(),
|
string_value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if attr == "format" {
|
} else if attr == "format" {
|
||||||
|
|
|
@ -296,11 +296,23 @@ impl<'a> Checker<'a> {
|
||||||
pub(crate) fn generator(&self) -> Generator {
|
pub(crate) fn generator(&self) -> Generator {
|
||||||
Generator::new(
|
Generator::new(
|
||||||
self.stylist.indentation(),
|
self.stylist.indentation(),
|
||||||
self.f_string_quote_style().unwrap_or(self.stylist.quote()),
|
self.preferred_quote(),
|
||||||
self.stylist.line_ending(),
|
self.stylist.line_ending(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the preferred quote for a generated `StringLiteral` node, given where we are in the
|
||||||
|
/// AST.
|
||||||
|
fn preferred_quote(&self) -> Quote {
|
||||||
|
self.f_string_quote_style().unwrap_or(self.stylist.quote())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the default string flags a generated `StringLiteral` node should use, given where we
|
||||||
|
/// are in the AST.
|
||||||
|
pub(crate) fn default_string_flags(&self) -> ast::StringLiteralFlags {
|
||||||
|
ast::StringLiteralFlags::empty().with_quote_style(self.preferred_quote())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the appropriate quoting for f-string by reversing the one used outside of
|
/// Returns the appropriate quoting for f-string by reversing the one used outside of
|
||||||
/// the f-string.
|
/// the f-string.
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::comparable::ComparableExpr;
|
use ruff_python_ast::comparable::ComparableExpr;
|
||||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext};
|
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext, StringLiteralFlags};
|
||||||
use ruff_python_codegen::Generator;
|
use ruff_python_codegen::Generator;
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
||||||
|
@ -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, flags: StringLiteralFlags) -> Option<String> {
|
||||||
if !elts.iter().all(Expr::is_string_literal_expr) {
|
if !elts.iter().all(Expr::is_string_literal_expr) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,8 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
|
||||||
acc
|
acc
|
||||||
})
|
})
|
||||||
.into_boxed_str(),
|
.into_boxed_str(),
|
||||||
..ast::StringLiteral::default()
|
range: TextRange::default(),
|
||||||
|
flags,
|
||||||
});
|
});
|
||||||
Some(generator.expr(&node))
|
Some(generator.expr(&node))
|
||||||
}
|
}
|
||||||
|
@ -358,8 +359,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| {
|
.map(|name| {
|
||||||
Expr::from(ast::StringLiteral {
|
Expr::from(ast::StringLiteral {
|
||||||
value: (*name).to_string().into_boxed_str(),
|
value: Box::from(*name),
|
||||||
..ast::StringLiteral::default()
|
range: TextRange::default(),
|
||||||
|
flags: checker.default_string_flags(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -393,8 +395,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| {
|
.map(|name| {
|
||||||
Expr::from(ast::StringLiteral {
|
Expr::from(ast::StringLiteral {
|
||||||
value: (*name).to_string().into_boxed_str(),
|
value: Box::from(*name),
|
||||||
..ast::StringLiteral::default()
|
range: TextRange::default(),
|
||||||
|
flags: checker.default_string_flags(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -444,7 +447,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
if let Some(content) =
|
||||||
|
elts_to_csv(elts, checker.generator(), checker.default_string_flags())
|
||||||
|
{
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
content,
|
content,
|
||||||
expr.range(),
|
expr.range(),
|
||||||
|
@ -489,7 +494,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
if let Some(content) =
|
||||||
|
elts_to_csv(elts, checker.generator(), checker.default_string_flags())
|
||||||
|
{
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
content,
|
content,
|
||||||
expr.range(),
|
expr.range(),
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{self as ast, str_prefix::StringLiteralPrefix, Arguments, Expr};
|
||||||
self as ast, str_prefix::StringLiteralPrefix, Arguments, Expr, StringLiteralFlags,
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
};
|
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
|
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
|
@ -220,14 +218,14 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
||||||
);
|
);
|
||||||
let node = ast::StringLiteral {
|
let node = ast::StringLiteral {
|
||||||
value: capital_env_var.into_boxed_str(),
|
value: capital_env_var.into_boxed_str(),
|
||||||
flags: StringLiteralFlags::default().with_prefix({
|
flags: checker.default_string_flags().with_prefix({
|
||||||
if env_var.is_unicode() {
|
if env_var.is_unicode() {
|
||||||
StringLiteralPrefix::Unicode
|
StringLiteralPrefix::Unicode
|
||||||
} else {
|
} else {
|
||||||
StringLiteralPrefix::Empty
|
StringLiteralPrefix::Empty
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
..ast::StringLiteral::default()
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
let new_env_var = node.into();
|
let new_env_var = node.into();
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn split_static_string(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
attr: &str,
|
attr: &str,
|
||||||
call: &ExprCall,
|
call: &ExprCall,
|
||||||
str_value: &str,
|
str_value: &StringLiteralValue,
|
||||||
) {
|
) {
|
||||||
let ExprCall { arguments, .. } = call;
|
let ExprCall { arguments, .. } = call;
|
||||||
|
|
||||||
|
@ -115,16 +115,16 @@ pub(crate) fn split_static_string(
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_replacement(elts: &[&str]) -> Expr {
|
fn construct_replacement(elts: &[&str], flags: StringLiteralFlags) -> Expr {
|
||||||
Expr::List(ExprList {
|
Expr::List(ExprList {
|
||||||
elts: elts
|
elts: elts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|elt| {
|
.map(|elt| {
|
||||||
Expr::StringLiteral(ExprStringLiteral {
|
Expr::StringLiteral(ExprStringLiteral {
|
||||||
value: StringLiteralValue::single(StringLiteral {
|
value: StringLiteralValue::single(StringLiteral {
|
||||||
value: (*elt).to_string().into_boxed_str(),
|
value: Box::from(*elt),
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
flags: StringLiteralFlags::default(),
|
flags,
|
||||||
}),
|
}),
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
})
|
})
|
||||||
|
@ -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:
|
// From the Python documentation:
|
||||||
// > If sep is not specified or is None, a different splitting algorithm is applied: runs of
|
// > 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
|
// > consecutive whitespace are regarded as a single separator, and the result will contain
|
||||||
|
@ -151,30 +151,36 @@ fn split_default(str_value: &str, max_split: i32) -> Option<Expr> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
let list_items: Vec<&str> = vec![str_value];
|
let list_items: Vec<&str> = vec![str_value.to_str()];
|
||||||
Some(construct_replacement(&list_items))
|
Some(construct_replacement(&list_items, str_value.flags()))
|
||||||
}
|
}
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
let list_items: Vec<&str> = str_value.split_whitespace().collect();
|
let list_items: Vec<&str> = str_value.to_str().split_whitespace().collect();
|
||||||
Some(construct_replacement(&list_items))
|
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) {
|
let list_items: Vec<&str> = if let Ok(split_n) = usize::try_from(max_split) {
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Left => str_value.splitn(split_n + 1, sep_value).collect(),
|
Direction::Left => value.splitn(split_n + 1, sep_value).collect(),
|
||||||
Direction::Right => str_value.rsplitn(split_n + 1, sep_value).collect(),
|
Direction::Right => value.rsplitn(split_n + 1, sep_value).collect(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Left => str_value.split(sep_value).collect(),
|
Direction::Left => value.split(sep_value).collect(),
|
||||||
Direction::Right => str_value.rsplit(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.
|
/// Returns the value of the `maxsplit` argument as an `i32`, if it is a numeric value.
|
||||||
|
|
|
@ -319,10 +319,10 @@ SIM905.py:29:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
27 27 | "a,b,c,d".split(maxsplit=0)
|
27 27 | "a,b,c,d".split(maxsplit=0)
|
||||||
28 28 | "VERB AUX PRON ADP DET".split(" ")
|
28 28 | "VERB AUX PRON ADP DET".split(" ")
|
||||||
29 |-' 1 2 3 '.split()
|
29 |-' 1 2 3 '.split()
|
||||||
29 |+["1", "2", "3"]
|
29 |+['1', '2', '3']
|
||||||
30 30 | '1<>2<>3<4'.split('<>')
|
30 30 | '1<>2<>3<4'.split('<>')
|
||||||
31 31 |
|
31 31 |
|
||||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
|
|
||||||
SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
|
@ -331,7 +331,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
30 | '1<>2<>3<4'.split('<>')
|
30 | '1<>2<>3<4'.split('<>')
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
31 |
|
31 |
|
||||||
32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
|
@ -340,16 +340,16 @@ SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
28 28 | "VERB AUX PRON ADP DET".split(" ")
|
28 28 | "VERB AUX PRON ADP DET".split(" ")
|
||||||
29 29 | ' 1 2 3 '.split()
|
29 29 | ' 1 2 3 '.split()
|
||||||
30 |-'1<>2<>3<4'.split('<>')
|
30 |-'1<>2<>3<4'.split('<>')
|
||||||
30 |+["1", "2", "3<4"]
|
30 |+['1', '2', '3<4']
|
||||||
31 31 |
|
31 31 |
|
||||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
33 33 | "".split() # []
|
33 33 | "".split() # []
|
||||||
|
|
||||||
SIM905.py:32:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:32:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
30 | '1<>2<>3<4'.split('<>')
|
30 | '1<>2<>3<4'.split('<>')
|
||||||
31 |
|
31 |
|
||||||
32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
33 | "".split() # []
|
33 | "".split() # []
|
||||||
34 | """
|
34 | """
|
||||||
|
@ -360,15 +360,15 @@ SIM905.py:32:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
29 29 | ' 1 2 3 '.split()
|
29 29 | ' 1 2 3 '.split()
|
||||||
30 30 | '1<>2<>3<4'.split('<>')
|
30 30 | '1<>2<>3<4'.split('<>')
|
||||||
31 31 |
|
31 31 |
|
||||||
32 |-" a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 |-" a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
32 |+[" a", "a a", "a a "] # [' a', 'a a', 'a a ']
|
32 |+[" a", "a a", "a a "] # [" a", "a a", "a a "]
|
||||||
33 33 | "".split() # []
|
33 33 | "".split() # []
|
||||||
34 34 | """
|
34 34 | """
|
||||||
35 35 | """.split() # []
|
35 35 | """.split() # []
|
||||||
|
|
||||||
SIM905.py:33:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:33:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
33 | "".split() # []
|
33 | "".split() # []
|
||||||
| ^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^ SIM905
|
||||||
34 | """
|
34 | """
|
||||||
|
@ -379,7 +379,7 @@ SIM905.py:33:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
30 30 | '1<>2<>3<4'.split('<>')
|
30 30 | '1<>2<>3<4'.split('<>')
|
||||||
31 31 |
|
31 31 |
|
||||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
33 |-"".split() # []
|
33 |-"".split() # []
|
||||||
33 |+[] # []
|
33 |+[] # []
|
||||||
34 34 | """
|
34 34 | """
|
||||||
|
@ -388,25 +388,25 @@ SIM905.py:33:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
||||||
SIM905.py:34:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:34:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
33 | "".split() # []
|
33 | "".split() # []
|
||||||
34 | / """
|
34 | / """
|
||||||
35 | | """.split() # []
|
35 | | """.split() # []
|
||||||
| |___________^ SIM905
|
| |___________^ SIM905
|
||||||
36 | " ".split() # []
|
36 | " ".split() # []
|
||||||
37 | "/abc/".split() # ['/abc/']
|
37 | "/abc/".split() # ["/abc/"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
31 31 |
|
31 31 |
|
||||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||||
33 33 | "".split() # []
|
33 33 | "".split() # []
|
||||||
34 |-"""
|
34 |-"""
|
||||||
35 |-""".split() # []
|
35 |-""".split() # []
|
||||||
34 |+[] # []
|
34 |+[] # []
|
||||||
36 35 | " ".split() # []
|
36 35 | " ".split() # []
|
||||||
37 36 | "/abc/".split() # ['/abc/']
|
37 36 | "/abc/".split() # ["/abc/"]
|
||||||
38 37 | ("a,b,c"
|
38 37 | ("a,b,c"
|
||||||
|
|
||||||
SIM905.py:36:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:36:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
@ -415,7 +415,7 @@ SIM905.py:36:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
35 | """.split() # []
|
35 | """.split() # []
|
||||||
36 | " ".split() # []
|
36 | " ".split() # []
|
||||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||||
37 | "/abc/".split() # ['/abc/']
|
37 | "/abc/".split() # ["/abc/"]
|
||||||
38 | ("a,b,c"
|
38 | ("a,b,c"
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
@ -426,7 +426,7 @@ SIM905.py:36:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
35 35 | """.split() # []
|
35 35 | """.split() # []
|
||||||
36 |-" ".split() # []
|
36 |-" ".split() # []
|
||||||
36 |+[] # []
|
36 |+[] # []
|
||||||
37 37 | "/abc/".split() # ['/abc/']
|
37 37 | "/abc/".split() # ["/abc/"]
|
||||||
38 38 | ("a,b,c"
|
38 38 | ("a,b,c"
|
||||||
39 39 | # comment
|
39 39 | # comment
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
35 | """.split() # []
|
35 | """.split() # []
|
||||||
36 | " ".split() # []
|
36 | " ".split() # []
|
||||||
37 | "/abc/".split() # ['/abc/']
|
37 | "/abc/".split() # ["/abc/"]
|
||||||
| ^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^ SIM905
|
||||||
38 | ("a,b,c"
|
38 | ("a,b,c"
|
||||||
39 | # comment
|
39 | # comment
|
||||||
|
@ -445,8 +445,8 @@ SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
34 34 | """
|
34 34 | """
|
||||||
35 35 | """.split() # []
|
35 35 | """.split() # []
|
||||||
36 36 | " ".split() # []
|
36 36 | " ".split() # []
|
||||||
37 |-"/abc/".split() # ['/abc/']
|
37 |-"/abc/".split() # ["/abc/"]
|
||||||
37 |+["/abc/"] # ['/abc/']
|
37 |+["/abc/"] # ["/abc/"]
|
||||||
38 38 | ("a,b,c"
|
38 38 | ("a,b,c"
|
||||||
39 39 | # comment
|
39 39 | # comment
|
||||||
40 40 | .split()
|
40 40 | .split()
|
||||||
|
@ -454,13 +454,13 @@ SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
SIM905.py:38:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:38:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
36 | " ".split() # []
|
36 | " ".split() # []
|
||||||
37 | "/abc/".split() # ['/abc/']
|
37 | "/abc/".split() # ["/abc/"]
|
||||||
38 | ("a,b,c"
|
38 | ("a,b,c"
|
||||||
| __^
|
| __^
|
||||||
39 | | # comment
|
39 | | # comment
|
||||||
40 | | .split()
|
40 | | .split()
|
||||||
| |________^ SIM905
|
| |________^ SIM905
|
||||||
41 | ) # ['a,b,c']
|
41 | ) # ["a,b,c"]
|
||||||
42 | ("a,b,c"
|
42 | ("a,b,c"
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
@ -468,25 +468,25 @@ SIM905.py:38:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
ℹ Unsafe fix
|
ℹ Unsafe fix
|
||||||
35 35 | """.split() # []
|
35 35 | """.split() # []
|
||||||
36 36 | " ".split() # []
|
36 36 | " ".split() # []
|
||||||
37 37 | "/abc/".split() # ['/abc/']
|
37 37 | "/abc/".split() # ["/abc/"]
|
||||||
38 |-("a,b,c"
|
38 |-("a,b,c"
|
||||||
39 |-# comment
|
39 |-# comment
|
||||||
40 |-.split()
|
40 |-.split()
|
||||||
38 |+(["a,b,c"]
|
38 |+(["a,b,c"]
|
||||||
41 39 | ) # ['a,b,c']
|
41 39 | ) # ["a,b,c"]
|
||||||
42 40 | ("a,b,c"
|
42 40 | ("a,b,c"
|
||||||
43 41 | # comment1
|
43 41 | # comment1
|
||||||
|
|
||||||
SIM905.py:42:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:42:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
40 | .split()
|
40 | .split()
|
||||||
41 | ) # ['a,b,c']
|
41 | ) # ["a,b,c"]
|
||||||
42 | ("a,b,c"
|
42 | ("a,b,c"
|
||||||
| __^
|
| __^
|
||||||
43 | | # comment1
|
43 | | # comment1
|
||||||
44 | | .split(",")
|
44 | | .split(",")
|
||||||
| |___________^ SIM905
|
| |___________^ SIM905
|
||||||
45 | ) # ['a', 'b', 'c']
|
45 | ) # ["a", "b", "c"]
|
||||||
46 | ("a,"
|
46 | ("a,"
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
@ -494,19 +494,19 @@ SIM905.py:42:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
ℹ Unsafe fix
|
ℹ Unsafe fix
|
||||||
39 39 | # comment
|
39 39 | # comment
|
||||||
40 40 | .split()
|
40 40 | .split()
|
||||||
41 41 | ) # ['a,b,c']
|
41 41 | ) # ["a,b,c"]
|
||||||
42 |-("a,b,c"
|
42 |-("a,b,c"
|
||||||
43 |-# comment1
|
43 |-# comment1
|
||||||
44 |-.split(",")
|
44 |-.split(",")
|
||||||
42 |+(["a", "b", "c"]
|
42 |+(["a", "b", "c"]
|
||||||
45 43 | ) # ['a', 'b', 'c']
|
45 43 | ) # ["a", "b", "c"]
|
||||||
46 44 | ("a,"
|
46 44 | ("a,"
|
||||||
47 45 | # comment
|
47 45 | # comment
|
||||||
|
|
||||||
SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
44 | .split(",")
|
44 | .split(",")
|
||||||
45 | ) # ['a', 'b', 'c']
|
45 | ) # ["a", "b", "c"]
|
||||||
46 | ("a,"
|
46 | ("a,"
|
||||||
| __^
|
| __^
|
||||||
47 | | # comment
|
47 | | # comment
|
||||||
|
@ -514,320 +514,320 @@ SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
49 | | "c"
|
49 | | "c"
|
||||||
50 | | .split(",")
|
50 | | .split(",")
|
||||||
| |___________^ SIM905
|
| |___________^ SIM905
|
||||||
51 | ) # ['a', 'b', 'c']
|
51 | ) # ["a", "b", "c"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Unsafe fix
|
ℹ Unsafe fix
|
||||||
43 43 | # comment1
|
43 43 | # comment1
|
||||||
44 44 | .split(",")
|
44 44 | .split(",")
|
||||||
45 45 | ) # ['a', 'b', 'c']
|
45 45 | ) # ["a", "b", "c"]
|
||||||
46 |-("a,"
|
46 |-("a,"
|
||||||
47 |-# comment
|
47 |-# comment
|
||||||
48 |-"b,"
|
48 |-"b,"
|
||||||
49 |-"c"
|
49 |-"c"
|
||||||
50 |-.split(",")
|
50 |-.split(",")
|
||||||
46 |+(["a", "b", "c"]
|
46 |+(["a", "b", "c"]
|
||||||
51 47 | ) # ['a', 'b', 'c']
|
51 47 | ) # ["a", "b", "c"]
|
||||||
52 48 |
|
52 48 |
|
||||||
53 49 | "hello "\
|
53 49 | "hello "\
|
||||||
|
|
||||||
SIM905.py:53:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:53:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
51 | ) # ['a', 'b', 'c']
|
51 | ) # ["a", "b", "c"]
|
||||||
52 |
|
52 |
|
||||||
53 | / "hello "\
|
53 | / "hello "\
|
||||||
54 | | "world".split()
|
54 | | "world".split()
|
||||||
| |___________________^ SIM905
|
| |___________________^ SIM905
|
||||||
55 | # ['hello', 'world']
|
55 | # ["hello", "world"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
50 50 | .split(",")
|
50 50 | .split(",")
|
||||||
51 51 | ) # ['a', 'b', 'c']
|
51 51 | ) # ["a", "b", "c"]
|
||||||
52 52 |
|
52 52 |
|
||||||
53 |-"hello "\
|
53 |-"hello "\
|
||||||
54 |- "world".split()
|
54 |- "world".split()
|
||||||
53 |+["hello", "world"]
|
53 |+["hello", "world"]
|
||||||
55 54 | # ['hello', 'world']
|
55 54 | # ["hello", "world"]
|
||||||
56 55 |
|
56 55 |
|
||||||
57 56 | # prefixes and isc
|
57 56 | # prefixes and isc
|
||||||
|
|
||||||
SIM905.py:58:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:58:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
57 | # prefixes and isc
|
57 | # prefixes and isc
|
||||||
58 | u"a b".split() # ['a', 'b']
|
58 | u"a b".split() # [u"a", u"b"]
|
||||||
| ^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^ SIM905
|
||||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 | ("a " "b").split() # ['a', 'b']
|
60 | ("a " "b").split() # ["a", "b"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
55 55 | # ['hello', 'world']
|
55 55 | # ["hello", "world"]
|
||||||
56 56 |
|
56 56 |
|
||||||
57 57 | # prefixes and isc
|
57 57 | # prefixes and isc
|
||||||
58 |-u"a b".split() # ['a', 'b']
|
58 |-u"a b".split() # [u"a", u"b"]
|
||||||
58 |+["a", "b"] # ['a', 'b']
|
58 |+[u"a", u"b"] # [u"a", u"b"]
|
||||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 60 | ("a " "b").split() # ['a', 'b']
|
60 60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
|
|
||||||
SIM905.py:59:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:59:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
57 | # prefixes and isc
|
57 | # prefixes and isc
|
||||||
58 | u"a b".split() # ['a', 'b']
|
58 | u"a b".split() # [u"a", u"b"]
|
||||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||||
60 | ("a " "b").split() # ['a', 'b']
|
60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 | "a " "b".split() # ['a', 'b']
|
61 | "a " "b".split() # ["a", "b"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
56 56 |
|
56 56 |
|
||||||
57 57 | # prefixes and isc
|
57 57 | # prefixes and isc
|
||||||
58 58 | u"a b".split() # ['a', 'b']
|
58 58 | u"a b".split() # [u"a", u"b"]
|
||||||
59 |-r"a \n b".split() # ['a', '\\n', 'b']
|
59 |-r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
59 |+["a", "\\n", "b"] # ['a', '\\n', 'b']
|
59 |+[r"a", r"\n", r"b"] # [r"a", r"\n", r"b"]
|
||||||
60 60 | ("a " "b").split() # ['a', 'b']
|
60 60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
|
|
||||||
SIM905.py:60:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:60:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
58 | u"a b".split() # ['a', 'b']
|
58 | u"a b".split() # [u"a", u"b"]
|
||||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 | ("a " "b").split() # ['a', 'b']
|
60 | ("a " "b").split() # ["a", "b"]
|
||||||
| ^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
61 | "a " "b".split() # ['a', 'b']
|
61 | "a " "b".split() # ["a", "b"]
|
||||||
62 | u"a " "b".split() # ['a', 'b']
|
62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
57 57 | # prefixes and isc
|
57 57 | # prefixes and isc
|
||||||
58 58 | u"a b".split() # ['a', 'b']
|
58 58 | u"a b".split() # [u"a", u"b"]
|
||||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 |-("a " "b").split() # ['a', 'b']
|
60 |-("a " "b").split() # ["a", "b"]
|
||||||
60 |+["a", "b"] # ['a', 'b']
|
60 |+["a", "b"] # ["a", "b"]
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
|
|
||||||
SIM905.py:61:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:61:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 | ("a " "b").split() # ['a', 'b']
|
60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 | "a " "b".split() # ['a', 'b']
|
61 | "a " "b".split() # ["a", "b"]
|
||||||
| ^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^ SIM905
|
||||||
62 | u"a " "b".split() # ['a', 'b']
|
62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 | "a " u"b".split() # ['a', 'b']
|
63 | "a " u"b".split() # ["a", "b"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
58 58 | u"a b".split() # ['a', 'b']
|
58 58 | u"a b".split() # [u"a", u"b"]
|
||||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 60 | ("a " "b").split() # ['a', 'b']
|
60 60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 |-"a " "b".split() # ['a', 'b']
|
61 |-"a " "b".split() # ["a", "b"]
|
||||||
61 |+["a", "b"] # ['a', 'b']
|
61 |+["a", "b"] # ["a", "b"]
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
|
|
||||||
SIM905.py:62:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:62:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
60 | ("a " "b").split() # ['a', 'b']
|
60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 | "a " "b".split() # ['a', 'b']
|
61 | "a " "b".split() # ["a", "b"]
|
||||||
62 | u"a " "b".split() # ['a', 'b']
|
62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||||
63 | "a " u"b".split() # ['a', 'b']
|
63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||||
60 60 | ("a " "b").split() # ['a', 'b']
|
60 60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
62 |-u"a " "b".split() # ['a', 'b']
|
62 |-u"a " "b".split() # [u"a", u"b"]
|
||||||
62 |+["a", "b"] # ['a', 'b']
|
62 |+[u"a", u"b"] # [u"a", u"b"]
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
|
|
||||||
SIM905.py:63:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:63:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
61 | "a " "b".split() # ['a', 'b']
|
61 | "a " "b".split() # ["a", "b"]
|
||||||
62 | u"a " "b".split() # ['a', 'b']
|
62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 | "a " u"b".split() # ['a', 'b']
|
63 | "a " u"b".split() # ["a", "b"]
|
||||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 | r"\n " u"\n".split() # ['\\n']
|
65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
60 60 | ("a " "b").split() # ['a', 'b']
|
60 60 | ("a " "b").split() # ["a", "b"]
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 |-"a " u"b".split() # ['a', 'b']
|
63 |-"a " u"b".split() # ["a", "b"]
|
||||||
63 |+["a", "b"] # ['a', 'b']
|
63 |+["a", "b"] # ["a", "b"]
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 66 | r"\n " "\n".split() # ['\\n']
|
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||||
|
|
||||||
SIM905.py:64:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:64:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
62 | u"a " "b".split() # ['a', 'b']
|
62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 | "a " u"b".split() # ['a', 'b']
|
63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
65 | r"\n " u"\n".split() # ['\\n']
|
65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 | r"\n " "\n".split() # ['\\n']
|
66 | r"\n " "\n".split() # [r"\n"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
61 61 | "a " "b".split() # ['a', 'b']
|
61 61 | "a " "b".split() # ["a", "b"]
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 |-u"a " r"\n".split() # ['a', '\\n']
|
64 |-u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
64 |+["a", "\\n"] # ['a', '\\n']
|
64 |+[u"a", u"\\n"] # [u"a", u"\\n"]
|
||||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 66 | r"\n " "\n".split() # ['\\n']
|
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
|
|
||||||
SIM905.py:65:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:65:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
63 | "a " u"b".split() # ['a', 'b']
|
63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 | r"\n " u"\n".split() # ['\\n']
|
65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
66 | r"\n " "\n".split() # ['\\n']
|
66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 | "a " r"\n".split() # ['a', '\\n']
|
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
62 62 | u"a " "b".split() # ['a', 'b']
|
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 |-r"\n " u"\n".split() # ['\\n']
|
65 |-r"\n " u"\n".split() # [r"\n"]
|
||||||
65 |+["\\n"] # ['\\n']
|
65 |+[r"\n"] # [r"\n"]
|
||||||
66 66 | r"\n " "\n".split() # ['\\n']
|
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
68 68 |
|
68 68 |
|
||||||
|
|
||||||
SIM905.py:66:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:66:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 | r"\n " u"\n".split() # ['\\n']
|
65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 | r"\n " "\n".split() # ['\\n']
|
66 | r"\n " "\n".split() # [r"\n"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
67 | "a " r"\n".split() # ['a', '\\n']
|
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
63 63 | "a " u"b".split() # ['a', 'b']
|
63 63 | "a " u"b".split() # ["a", "b"]
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 |-r"\n " "\n".split() # ['\\n']
|
66 |-r"\n " "\n".split() # [r"\n"]
|
||||||
66 |+["\\n"] # ['\\n']
|
66 |+[r"\n"] # [r"\n"]
|
||||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
68 68 |
|
68 68 |
|
||||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
|
|
||||||
SIM905.py:67:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:67:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
65 | r"\n " u"\n".split() # ['\\n']
|
65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 | r"\n " "\n".split() # ['\\n']
|
66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 | "a " r"\n".split() # ['a', '\\n']
|
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
| ^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
68 |
|
68 |
|
||||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||||
66 66 | r"\n " "\n".split() # ['\\n']
|
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 |-"a " r"\n".split() # ['a', '\\n']
|
67 |-"a " r"\n".split() # ["a", "\\n"]
|
||||||
67 |+["a", "\\n"] # ['a', '\\n']
|
67 |+["a", "\\n"] # ["a", "\\n"]
|
||||||
68 68 |
|
68 68 |
|
||||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
|
|
||||||
SIM905.py:69:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:69:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
67 | "a " r"\n".split() # ['a', '\\n']
|
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
68 |
|
68 |
|
||||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
66 66 | r"\n " "\n".split() # ['\\n']
|
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
68 68 |
|
68 68 |
|
||||||
69 |-"a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 |-"a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
69 |+["a,b,c"] # ['a,b,c']
|
69 |+["a,b,c"] # ["a,b,c"]
|
||||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
72 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
|
|
||||||
SIM905.py:70:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:70:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||||
68 68 |
|
68 68 |
|
||||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 |-"a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 |-"a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
70 |+["a", "b", "c"] # ['a', 'b', 'c']
|
70 |+["a", "b", "c"] # ["a", "b", "c"]
|
||||||
71 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
72 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
73 73 |
|
73 73 |
|
||||||
|
|
||||||
SIM905.py:71:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:71:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
|
|
|
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
68 68 |
|
68 68 |
|
||||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 |-"a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 |-"a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
71 |+["a", "b", "c"] # ['a', 'b', 'c']
|
71 |+["a", "b", "c"] # ["a", "b", "c"]
|
||||||
72 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
73 73 |
|
73 73 |
|
||||||
74 74 | # negatives
|
74 74 | # negatives
|
||||||
|
|
||||||
SIM905.py:72:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
SIM905.py:72:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
|
|
|
|
||||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||||
73 |
|
73 |
|
||||||
74 | # negatives
|
74 | # negatives
|
||||||
|
@ -835,11 +835,11 @@ SIM905.py:72:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||||
= help: Replace with list literal
|
= help: Replace with list literal
|
||||||
|
|
||||||
ℹ Safe fix
|
ℹ Safe fix
|
||||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
69 69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
70 70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||||
71 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
71 71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||||
72 |-"a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
72 |-"a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||||
72 |+["a,b,c"] # ['a,b,c']
|
72 |+["a,b,c"] # ["a,b,c"]
|
||||||
73 73 |
|
73 73 |
|
||||||
74 74 | # negatives
|
74 74 | # negatives
|
||||||
75 75 |
|
75 75 |
|
||||||
|
|
|
@ -3,8 +3,9 @@ use std::cmp::Reverse;
|
||||||
use ruff_diagnostics::Edit;
|
use ruff_diagnostics::Edit;
|
||||||
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
|
use ruff_python_ast::str::Quote;
|
||||||
use ruff_python_ast::visitor::transformer::{walk_expr, Transformer};
|
use ruff_python_ast::visitor::transformer::{walk_expr, Transformer};
|
||||||
use ruff_python_ast::{self as ast, Decorator, Expr};
|
use ruff_python_ast::{self as ast, Decorator, Expr, StringLiteralFlags};
|
||||||
use ruff_python_codegen::{Generator, Stylist};
|
use ruff_python_codegen::{Generator, Stylist};
|
||||||
use ruff_python_parser::typing::parse_type_annotation;
|
use ruff_python_parser::typing::parse_type_annotation;
|
||||||
use ruff_python_semantic::{
|
use ruff_python_semantic::{
|
||||||
|
@ -249,6 +250,7 @@ pub(crate) fn quote_annotation(
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
) -> Edit {
|
) -> Edit {
|
||||||
let expr = semantic.expression(node_id).expect("Expression not found");
|
let expr = semantic.expression(node_id).expect("Expression not found");
|
||||||
if let Some(parent_id) = semantic.parent_expression_id(node_id) {
|
if let Some(parent_id) = semantic.parent_expression_id(node_id) {
|
||||||
|
@ -258,7 +260,7 @@ pub(crate) fn quote_annotation(
|
||||||
// If we're quoting the value of a subscript, we need to quote the entire
|
// If we're quoting the value of a subscript, we need to quote the entire
|
||||||
// expression. For example, when quoting `DataFrame` in `DataFrame[int]`, we
|
// expression. For example, when quoting `DataFrame` in `DataFrame[int]`, we
|
||||||
// should generate `"DataFrame[int]"`.
|
// should generate `"DataFrame[int]"`.
|
||||||
return quote_annotation(parent_id, semantic, stylist, locator);
|
return quote_annotation(parent_id, semantic, stylist, locator, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Expr::Attribute(parent)) => {
|
Some(Expr::Attribute(parent)) => {
|
||||||
|
@ -266,7 +268,7 @@ pub(crate) fn quote_annotation(
|
||||||
// If we're quoting the value of an attribute, we need to quote the entire
|
// If we're quoting the value of an attribute, we need to quote the entire
|
||||||
// expression. For example, when quoting `DataFrame` in `pd.DataFrame`, we
|
// expression. For example, when quoting `DataFrame` in `pd.DataFrame`, we
|
||||||
// should generate `"pd.DataFrame"`.
|
// should generate `"pd.DataFrame"`.
|
||||||
return quote_annotation(parent_id, semantic, stylist, locator);
|
return quote_annotation(parent_id, semantic, stylist, locator, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Expr::Call(parent)) => {
|
Some(Expr::Call(parent)) => {
|
||||||
|
@ -274,7 +276,7 @@ pub(crate) fn quote_annotation(
|
||||||
// If we're quoting the function of a call, we need to quote the entire
|
// If we're quoting the function of a call, we need to quote the entire
|
||||||
// expression. For example, when quoting `DataFrame` in `DataFrame()`, we
|
// expression. For example, when quoting `DataFrame` in `DataFrame()`, we
|
||||||
// should generate `"DataFrame()"`.
|
// should generate `"DataFrame()"`.
|
||||||
return quote_annotation(parent_id, semantic, stylist, locator);
|
return quote_annotation(parent_id, semantic, stylist, locator, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Expr::BinOp(parent)) => {
|
Some(Expr::BinOp(parent)) => {
|
||||||
|
@ -282,14 +284,14 @@ pub(crate) fn quote_annotation(
|
||||||
// If we're quoting the left or right side of a binary operation, we need to
|
// If we're quoting the left or right side of a binary operation, we need to
|
||||||
// quote the entire expression. For example, when quoting `DataFrame` in
|
// quote the entire expression. For example, when quoting `DataFrame` in
|
||||||
// `DataFrame | Series`, we should generate `"DataFrame | Series"`.
|
// `DataFrame | Series`, we should generate `"DataFrame | Series"`.
|
||||||
return quote_annotation(parent_id, semantic, stylist, locator);
|
return quote_annotation(parent_id, semantic, stylist, locator, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quote_type_expression(expr, semantic, stylist, locator)
|
quote_type_expression(expr, semantic, stylist, locator, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrap a type expression in quotes.
|
/// Wrap a type expression in quotes.
|
||||||
|
@ -305,9 +307,10 @@ pub(crate) fn quote_type_expression(
|
||||||
semantic: &SemanticModel,
|
semantic: &SemanticModel,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
) -> Edit {
|
) -> Edit {
|
||||||
// Quote the entire expression.
|
// Quote the entire expression.
|
||||||
let quote_annotator = QuoteAnnotator::new(semantic, stylist, locator);
|
let quote_annotator = QuoteAnnotator::new(semantic, stylist, locator, flags);
|
||||||
|
|
||||||
Edit::range_replacement(quote_annotator.into_annotation(expr), expr.range())
|
Edit::range_replacement(quote_annotator.into_annotation(expr), expr.range())
|
||||||
}
|
}
|
||||||
|
@ -336,6 +339,7 @@ pub(crate) struct QuoteAnnotator<'a> {
|
||||||
semantic: &'a SemanticModel<'a>,
|
semantic: &'a SemanticModel<'a>,
|
||||||
stylist: &'a Stylist<'a>,
|
stylist: &'a Stylist<'a>,
|
||||||
locator: &'a Locator<'a>,
|
locator: &'a Locator<'a>,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> QuoteAnnotator<'a> {
|
impl<'a> QuoteAnnotator<'a> {
|
||||||
|
@ -343,11 +347,13 @@ impl<'a> QuoteAnnotator<'a> {
|
||||||
semantic: &'a SemanticModel<'a>,
|
semantic: &'a SemanticModel<'a>,
|
||||||
stylist: &'a Stylist<'a>,
|
stylist: &'a Stylist<'a>,
|
||||||
locator: &'a Locator<'a>,
|
locator: &'a Locator<'a>,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
semantic,
|
semantic,
|
||||||
stylist,
|
stylist,
|
||||||
locator,
|
locator,
|
||||||
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +372,7 @@ impl<'a> QuoteAnnotator<'a> {
|
||||||
generator.expr(&Expr::from(ast::StringLiteral {
|
generator.expr(&Expr::from(ast::StringLiteral {
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
value: annotation.into_boxed_str(),
|
value: annotation.into_boxed_str(),
|
||||||
flags: ast::StringLiteralFlags::default(),
|
flags: self.flags,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +382,12 @@ impl<'a> QuoteAnnotator<'a> {
|
||||||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice {
|
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = slice {
|
||||||
if !elts.is_empty() {
|
if !elts.is_empty() {
|
||||||
self.visit_expr(&mut elts[0]);
|
self.visit_expr(&mut elts[0]);
|
||||||
|
// The outer annotation will use the preferred quote.
|
||||||
|
// As such, any quotes found in metadata elements inside an `Annotated` slice
|
||||||
|
// should use the opposite quote to the preferred quote.
|
||||||
|
for elt in elts.iter_mut().skip(1) {
|
||||||
|
QuoteRewriter::new(self.stylist).visit_expr(elt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,8 +402,10 @@ impl Transformer for QuoteAnnotator<'_> {
|
||||||
.semantic
|
.semantic
|
||||||
.match_typing_qualified_name(&qualified_name, "Literal")
|
.match_typing_qualified_name(&qualified_name, "Literal")
|
||||||
{
|
{
|
||||||
// we don't want to modify anything inside `Literal`
|
// The outer annotation will use the preferred quote.
|
||||||
// so skip visiting this subscripts' slice
|
// As such, any quotes found inside a `Literal` slice
|
||||||
|
// should use the opposite quote to the preferred quote.
|
||||||
|
QuoteRewriter::new(self.stylist).visit_expr(slice);
|
||||||
} else if self
|
} else if self
|
||||||
.semantic
|
.semantic
|
||||||
.match_typing_qualified_name(&qualified_name, "Annotated")
|
.match_typing_qualified_name(&qualified_name, "Annotated")
|
||||||
|
@ -420,3 +434,24 @@ impl Transformer for QuoteAnnotator<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`Transformer`] struct that rewrites all strings in an expression
|
||||||
|
/// to use a specified quotation style
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QuoteRewriter {
|
||||||
|
preferred_inner_quote: Quote,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuoteRewriter {
|
||||||
|
fn new(stylist: &Stylist) -> Self {
|
||||||
|
Self {
|
||||||
|
preferred_inner_quote: stylist.quote().opposite(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transformer for QuoteRewriter {
|
||||||
|
fn visit_string_literal(&self, literal: &mut ast::StringLiteral) {
|
||||||
|
literal.flags = literal.flags.with_quote_style(self.preferred_inner_quote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub(crate) fn runtime_cast_value(checker: &mut Checker, type_expr: &Expr) {
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
checker.stylist(),
|
checker.stylist(),
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
|
checker.default_string_flags(),
|
||||||
);
|
);
|
||||||
if checker.comment_ranges().intersects(type_expr.range()) {
|
if checker.comment_ranges().intersects(type_expr.range()) {
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||||
|
|
|
@ -278,6 +278,7 @@ fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding])
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
checker.stylist(),
|
checker.stylist(),
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
|
checker.default_string_flags(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -175,6 +175,7 @@ pub(crate) fn unquoted_type_alias(checker: &Checker, binding: &Binding) -> Optio
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
checker.stylist(),
|
checker.stylist(),
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
|
checker.default_string_flags(),
|
||||||
);
|
);
|
||||||
let mut diagnostics = Vec::with_capacity(names.len());
|
let mut diagnostics = Vec::with_capacity(names.len());
|
||||||
for name in names {
|
for name in names {
|
||||||
|
|
|
@ -510,6 +510,7 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) ->
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
checker.stylist(),
|
checker.stylist(),
|
||||||
checker.locator(),
|
checker.locator(),
|
||||||
|
checker.default_string_flags(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -63,11 +63,16 @@ fn is_static_length(elts: &[Expr]) -> bool {
|
||||||
fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
||||||
// If all elements are string constants, join them into a single string.
|
// If all elements are string constants, join them into a single string.
|
||||||
if joinees.iter().all(Expr::is_string_literal_expr) {
|
if joinees.iter().all(Expr::is_string_literal_expr) {
|
||||||
|
let mut flags = None;
|
||||||
let node = ast::StringLiteral {
|
let node = ast::StringLiteral {
|
||||||
value: joinees
|
value: joinees
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|expr| {
|
.filter_map(|expr| {
|
||||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
||||||
|
if flags.is_none() {
|
||||||
|
// take the flags from the first Expr
|
||||||
|
flags = Some(value.flags());
|
||||||
|
}
|
||||||
Some(value.to_str())
|
Some(value.to_str())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -75,7 +80,8 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
||||||
})
|
})
|
||||||
.join(joiner)
|
.join(joiner)
|
||||||
.into_boxed_str(),
|
.into_boxed_str(),
|
||||||
..ast::StringLiteral::default()
|
flags: flags?,
|
||||||
|
range: TextRange::default(),
|
||||||
};
|
};
|
||||||
return Some(node.into());
|
return Some(node.into());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::{self as ast, Expr, StringLiteralFlags};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ use crate::fix::edits::add_argument;
|
||||||
/// encoding. [PEP 597] recommends the use of `encoding="utf-8"` as a default,
|
/// encoding. [PEP 597] recommends the use of `encoding="utf-8"` as a default,
|
||||||
/// and suggests that it may become the default in future versions of Python.
|
/// and suggests that it may become the default in future versions of Python.
|
||||||
///
|
///
|
||||||
/// If a local-specific encoding is intended, use `encoding="local"` on
|
/// If a locale-specific encoding is intended, use `encoding="locale"` on
|
||||||
/// Python 3.10 and later, or `locale.getpreferredencoding()` on earlier versions,
|
/// Python 3.10 and later, or `locale.getpreferredencoding()` on earlier versions,
|
||||||
/// to make the encoding explicit.
|
/// to make the encoding explicit.
|
||||||
///
|
///
|
||||||
|
@ -158,16 +158,11 @@ fn generate_keyword_fix(checker: &Checker, call: &ast::ExprCall) -> Fix {
|
||||||
Fix::unsafe_edit(add_argument(
|
Fix::unsafe_edit(add_argument(
|
||||||
&format!(
|
&format!(
|
||||||
"encoding={}",
|
"encoding={}",
|
||||||
checker
|
checker.generator().expr(&Expr::from(ast::StringLiteral {
|
||||||
.generator()
|
value: Box::from("utf-8"),
|
||||||
.expr(&Expr::StringLiteral(ast::ExprStringLiteral {
|
flags: checker.default_string_flags(),
|
||||||
value: ast::StringLiteralValue::single(ast::StringLiteral {
|
range: TextRange::default(),
|
||||||
value: "utf-8".to_string().into_boxed_str(),
|
}))
|
||||||
flags: StringLiteralFlags::default(),
|
|
||||||
range: TextRange::default(),
|
|
||||||
}),
|
|
||||||
range: TextRange::default(),
|
|
||||||
}))
|
|
||||||
),
|
),
|
||||||
&call.arguments,
|
&call.arguments,
|
||||||
checker.comment_ranges(),
|
checker.comment_ranges(),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
use ruff_python_ast::{self as ast, Expr, Int, LiteralExpressionRef, UnaryOp};
|
use ruff_python_ast::{self as ast, Expr, Int, LiteralExpressionRef, StringLiteralFlags, UnaryOp};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
@ -33,9 +33,14 @@ impl FromStr for LiteralType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LiteralType {
|
impl LiteralType {
|
||||||
fn as_zero_value_expr(self) -> Expr {
|
fn as_zero_value_expr(self, flags: StringLiteralFlags) -> Expr {
|
||||||
match self {
|
match self {
|
||||||
LiteralType::Str => ast::ExprStringLiteral::default().into(),
|
LiteralType::Str => ast::StringLiteral {
|
||||||
|
value: Box::default(),
|
||||||
|
range: TextRange::default(),
|
||||||
|
flags,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
LiteralType::Bytes => ast::ExprBytesLiteral::default().into(),
|
LiteralType::Bytes => ast::ExprBytesLiteral::default().into(),
|
||||||
LiteralType::Int => ast::ExprNumberLiteral {
|
LiteralType::Int => ast::ExprNumberLiteral {
|
||||||
value: ast::Number::Int(Int::from(0u8)),
|
value: ast::Number::Int(Int::from(0u8)),
|
||||||
|
@ -186,7 +191,7 @@ pub(crate) fn native_literals(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr = literal_type.as_zero_value_expr();
|
let expr = literal_type.as_zero_value_expr(checker.default_string_flags());
|
||||||
let content = checker.generator().expr(&expr);
|
let content = checker.generator().expr(&expr);
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
content,
|
content,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
|
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
UP007.py:5:10: UP007 [*] Use `X | Y` for type annotations
|
UP007.py:5:10: UP007 [*] Use `X | Y` for type annotations
|
||||||
|
|
|
|
||||||
|
@ -295,3 +294,23 @@ UP007.py:83:10: UP007 [*] Use `X | Y` for type annotations
|
||||||
83 |-def f(x: Union[int, str, bytes]) -> None:
|
83 |-def f(x: Union[int, str, bytes]) -> None:
|
||||||
83 |+def f(x: int | str | bytes) -> None:
|
83 |+def f(x: int | str | bytes) -> None:
|
||||||
84 84 | ...
|
84 84 | ...
|
||||||
|
85 85 |
|
||||||
|
86 86 |
|
||||||
|
|
||||||
|
UP007.py:91:26: UP007 [*] Use `X | Y` for type annotations
|
||||||
|
|
|
||||||
|
89 | ...
|
||||||
|
90 |
|
||||||
|
91 | def myfunc(param: "tuple[Union[int, 'AClass', None], str]"):
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP007
|
||||||
|
92 | print(param)
|
||||||
|
|
|
||||||
|
= help: Convert to `X | Y`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
88 88 | class AClass:
|
||||||
|
89 89 | ...
|
||||||
|
90 90 |
|
||||||
|
91 |-def myfunc(param: "tuple[Union[int, 'AClass', None], str]"):
|
||||||
|
91 |+def myfunc(param: "tuple[int | 'AClass' | None, str]"):
|
||||||
|
92 92 | print(param)
|
||||||
|
|
|
@ -66,7 +66,8 @@ pub(crate) fn assert_with_print_message(checker: &mut Checker, stmt: &ast::StmtA
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
checker.generator().stmt(&Stmt::Assert(ast::StmtAssert {
|
checker.generator().stmt(&Stmt::Assert(ast::StmtAssert {
|
||||||
test: stmt.test.clone(),
|
test: stmt.test.clone(),
|
||||||
msg: print_arguments::to_expr(&call.arguments).map(Box::new),
|
msg: print_arguments::to_expr(&call.arguments, checker.default_string_flags())
|
||||||
|
.map(Box::new),
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
})),
|
})),
|
||||||
// We have to replace the entire statement,
|
// We have to replace the entire statement,
|
||||||
|
@ -140,12 +141,13 @@ mod print_arguments {
|
||||||
/// literals.
|
/// literals.
|
||||||
fn fstring_elements_to_string_literals<'a>(
|
fn fstring_elements_to_string_literals<'a>(
|
||||||
mut elements: impl ExactSizeIterator<Item = &'a FStringElement>,
|
mut elements: impl ExactSizeIterator<Item = &'a FStringElement>,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
) -> Option<Vec<StringLiteral>> {
|
) -> Option<Vec<StringLiteral>> {
|
||||||
elements.try_fold(Vec::with_capacity(elements.len()), |mut acc, element| {
|
elements.try_fold(Vec::with_capacity(elements.len()), |mut acc, element| {
|
||||||
if let FStringElement::Literal(literal) = element {
|
if let FStringElement::Literal(literal) = element {
|
||||||
acc.push(StringLiteral {
|
acc.push(StringLiteral {
|
||||||
value: literal.value.clone(),
|
value: literal.value.clone(),
|
||||||
flags: StringLiteralFlags::default(),
|
flags,
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
});
|
});
|
||||||
Some(acc)
|
Some(acc)
|
||||||
|
@ -162,6 +164,7 @@ mod print_arguments {
|
||||||
fn args_to_string_literal_expr<'a>(
|
fn args_to_string_literal_expr<'a>(
|
||||||
args: impl ExactSizeIterator<Item = &'a Vec<FStringElement>>,
|
args: impl ExactSizeIterator<Item = &'a Vec<FStringElement>>,
|
||||||
sep: impl ExactSizeIterator<Item = &'a FStringElement>,
|
sep: impl ExactSizeIterator<Item = &'a FStringElement>,
|
||||||
|
flags: StringLiteralFlags,
|
||||||
) -> Option<Expr> {
|
) -> Option<Expr> {
|
||||||
// If there are no arguments, short-circuit and return `None`
|
// If there are no arguments, short-circuit and return `None`
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
|
@ -174,8 +177,8 @@ mod print_arguments {
|
||||||
// of a concatenated string literal. (e.g. "text", "text" "text") The `sep` will
|
// of a concatenated string literal. (e.g. "text", "text" "text") The `sep` will
|
||||||
// be inserted only between the outer Vecs.
|
// be inserted only between the outer Vecs.
|
||||||
let (Some(sep), Some(args)) = (
|
let (Some(sep), Some(args)) = (
|
||||||
fstring_elements_to_string_literals(sep),
|
fstring_elements_to_string_literals(sep, flags),
|
||||||
args.map(|arg| fstring_elements_to_string_literals(arg.iter()))
|
args.map(|arg| fstring_elements_to_string_literals(arg.iter(), flags))
|
||||||
.collect::<Option<Vec<_>>>(),
|
.collect::<Option<Vec<_>>>(),
|
||||||
) else {
|
) else {
|
||||||
// If any of the arguments are not string literals, return None
|
// If any of the arguments are not string literals, return None
|
||||||
|
@ -203,7 +206,7 @@ mod print_arguments {
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
value: StringLiteralValue::single(StringLiteral {
|
value: StringLiteralValue::single(StringLiteral {
|
||||||
value: combined_string.into(),
|
value: combined_string.into(),
|
||||||
flags: StringLiteralFlags::default(),
|
flags,
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
@ -256,7 +259,7 @@ mod print_arguments {
|
||||||
/// - [`Some`]<[`Expr::StringLiteral`]> if all arguments including `sep` are string literals.
|
/// - [`Some`]<[`Expr::StringLiteral`]> if all arguments including `sep` are string literals.
|
||||||
/// - [`Some`]<[`Expr::FString`]> if any of the arguments are not string literals.
|
/// - [`Some`]<[`Expr::FString`]> if any of the arguments are not string literals.
|
||||||
/// - [`None`] if the `print` contains no positional arguments at all.
|
/// - [`None`] if the `print` contains no positional arguments at all.
|
||||||
pub(super) fn to_expr(arguments: &Arguments) -> Option<Expr> {
|
pub(super) fn to_expr(arguments: &Arguments, flags: StringLiteralFlags) -> Option<Expr> {
|
||||||
// Convert the `sep` argument into `FStringElement`s
|
// Convert the `sep` argument into `FStringElement`s
|
||||||
let sep = arguments
|
let sep = arguments
|
||||||
.find_keyword("sep")
|
.find_keyword("sep")
|
||||||
|
@ -286,7 +289,7 @@ mod print_arguments {
|
||||||
|
|
||||||
// Attempt to convert the `sep` and `args` arguments to a string literal,
|
// Attempt to convert the `sep` and `args` arguments to a string literal,
|
||||||
// falling back to an f-string if the arguments are not all string literals.
|
// falling back to an f-string if the arguments are not all string literals.
|
||||||
args_to_string_literal_expr(args.iter(), sep.iter())
|
args_to_string_literal_expr(args.iter(), sep.iter(), flags)
|
||||||
.or_else(|| args_to_fstring_expr(args.into_iter(), sep.into_iter()))
|
.or_else(|| args_to_fstring_expr(args.into_iter(), sep.into_iter()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
RUF055_0.py:6:1: RUF055 [*] Plain string pattern passed to `re` function
|
RUF055_0.py:6:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
|
|
|
|
||||||
|
@ -211,12 +210,16 @@ RUF055_0.py:94:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
94 |-re.sub(r"a", "\?", "a")
|
94 |-re.sub(r"a", "\?", "a")
|
||||||
94 |+"a".replace(r"a", "\\?")
|
94 |+"a".replace(r"a", "\\?")
|
||||||
95 95 | re.sub(r"a", r"\?", "a")
|
95 95 | re.sub(r"a", r"\?", "a")
|
||||||
|
96 96 |
|
||||||
|
97 97 | # these double as tests for preserving raw string quoting style
|
||||||
|
|
||||||
RUF055_0.py:95:1: RUF055 [*] Plain string pattern passed to `re` function
|
RUF055_0.py:95:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
|
|
|
|
||||||
94 | re.sub(r"a", "\?", "a")
|
94 | re.sub(r"a", "\?", "a")
|
||||||
95 | re.sub(r"a", r"\?", "a")
|
95 | re.sub(r"a", r"\?", "a")
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF055
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF055
|
||||||
|
96 |
|
||||||
|
97 | # these double as tests for preserving raw string quoting style
|
||||||
|
|
|
|
||||||
= help: Replace with `"a".replace(r"a", r"\?")`
|
= help: Replace with `"a".replace(r"a", r"\?")`
|
||||||
|
|
||||||
|
@ -226,3 +229,59 @@ RUF055_0.py:95:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
94 94 | re.sub(r"a", "\?", "a")
|
94 94 | re.sub(r"a", "\?", "a")
|
||||||
95 |-re.sub(r"a", r"\?", "a")
|
95 |-re.sub(r"a", r"\?", "a")
|
||||||
95 |+"a".replace(r"a", r"\?")
|
95 |+"a".replace(r"a", r"\?")
|
||||||
|
96 96 |
|
||||||
|
97 97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 98 | re.sub(r'abc', "", s)
|
||||||
|
|
||||||
|
RUF055_0.py:98:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
|
|
|
||||||
|
97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 | re.sub(r'abc', "", s)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ RUF055
|
||||||
|
99 | re.sub(r"""abc""", "", s)
|
||||||
|
100 | re.sub(r'''abc''', "", s)
|
||||||
|
|
|
||||||
|
= help: Replace with `s.replace(r'abc', "")`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
95 95 | re.sub(r"a", r"\?", "a")
|
||||||
|
96 96 |
|
||||||
|
97 97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 |-re.sub(r'abc', "", s)
|
||||||
|
98 |+s.replace(r'abc', "")
|
||||||
|
99 99 | re.sub(r"""abc""", "", s)
|
||||||
|
100 100 | re.sub(r'''abc''', "", s)
|
||||||
|
|
||||||
|
RUF055_0.py:99:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
|
|
|
||||||
|
97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 | re.sub(r'abc', "", s)
|
||||||
|
99 | re.sub(r"""abc""", "", s)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF055
|
||||||
|
100 | re.sub(r'''abc''', "", s)
|
||||||
|
|
|
||||||
|
= help: Replace with `s.replace(r"""abc""", "")`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
96 96 |
|
||||||
|
97 97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 98 | re.sub(r'abc', "", s)
|
||||||
|
99 |-re.sub(r"""abc""", "", s)
|
||||||
|
99 |+s.replace(r"""abc""", "")
|
||||||
|
100 100 | re.sub(r'''abc''', "", s)
|
||||||
|
|
||||||
|
RUF055_0.py:100:1: RUF055 [*] Plain string pattern passed to `re` function
|
||||||
|
|
|
||||||
|
98 | re.sub(r'abc', "", s)
|
||||||
|
99 | re.sub(r"""abc""", "", s)
|
||||||
|
100 | re.sub(r'''abc''', "", s)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF055
|
||||||
|
|
|
||||||
|
= help: Replace with `s.replace(r'''abc''', "")`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
97 97 | # these double as tests for preserving raw string quoting style
|
||||||
|
98 98 | re.sub(r'abc', "", s)
|
||||||
|
99 99 | re.sub(r"""abc""", "", s)
|
||||||
|
100 |-re.sub(r'''abc''', "", s)
|
||||||
|
100 |+s.replace(r'''abc''', "")
|
||||||
|
|
|
@ -1221,14 +1221,14 @@ impl fmt::Debug for FStringElements {
|
||||||
|
|
||||||
/// An AST node that represents either a single string literal or an implicitly
|
/// An AST node that represents either a single string literal or an implicitly
|
||||||
/// concatenated string literals.
|
/// concatenated string literals.
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ExprStringLiteral {
|
pub struct ExprStringLiteral {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub value: StringLiteralValue,
|
pub value: StringLiteralValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value representing a [`ExprStringLiteral`].
|
/// The value representing a [`ExprStringLiteral`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct StringLiteralValue {
|
pub struct StringLiteralValue {
|
||||||
inner: StringLiteralValueInner,
|
inner: StringLiteralValueInner,
|
||||||
}
|
}
|
||||||
|
@ -1241,6 +1241,18 @@ impl StringLiteralValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`StringLiteralFlags`] associated with this string literal.
|
||||||
|
///
|
||||||
|
/// For an implicitly concatenated string, it returns the flags for the first literal.
|
||||||
|
pub fn flags(&self) -> StringLiteralFlags {
|
||||||
|
self.iter()
|
||||||
|
.next()
|
||||||
|
.expect(
|
||||||
|
"There should always be at least one string literal in an `ExprStringLiteral` node",
|
||||||
|
)
|
||||||
|
.flags
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new string literal with the given values that represents an
|
/// Creates a new string literal with the given values that represents an
|
||||||
/// implicitly concatenated strings.
|
/// implicitly concatenated strings.
|
||||||
///
|
///
|
||||||
|
@ -1371,12 +1383,6 @@ enum StringLiteralValueInner {
|
||||||
Concatenated(ConcatenatedStringLiteral),
|
Concatenated(ConcatenatedStringLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StringLiteralValueInner {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Single(StringLiteral::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
struct StringLiteralFlagsInner: u8 {
|
struct StringLiteralFlagsInner: u8 {
|
||||||
|
@ -1414,10 +1420,33 @@ bitflags! {
|
||||||
|
|
||||||
/// Flags that can be queried to obtain information
|
/// Flags that can be queried to obtain information
|
||||||
/// regarding the prefixes and quotes used for a string literal.
|
/// regarding the prefixes and quotes used for a string literal.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
///
|
||||||
|
/// ## Notes on usage
|
||||||
|
///
|
||||||
|
/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
|
||||||
|
/// from an existing string literal, consider passing along the [`StringLiteral::flags`] field or
|
||||||
|
/// the result of the [`StringLiteralValue::flags`] method. If you don't have an existing string but
|
||||||
|
/// have a `Checker` from the `ruff_linter` crate available, consider using
|
||||||
|
/// `Checker::default_string_flags` to create instances of this struct; this method will properly
|
||||||
|
/// handle surrounding f-strings. For usage that doesn't fit into one of these categories, the
|
||||||
|
/// public constructor [`StringLiteralFlags::empty`] can be used.
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct StringLiteralFlags(StringLiteralFlagsInner);
|
pub struct StringLiteralFlags(StringLiteralFlagsInner);
|
||||||
|
|
||||||
impl StringLiteralFlags {
|
impl StringLiteralFlags {
|
||||||
|
/// Construct a new [`StringLiteralFlags`] with **no flags set**.
|
||||||
|
///
|
||||||
|
/// See [`StringLiteralFlags::with_quote_style`], [`StringLiteralFlags::with_triple_quotes`],
|
||||||
|
/// and [`StringLiteralFlags::with_prefix`] for ways of setting the quote style (single or
|
||||||
|
/// double), enabling triple quotes, and adding prefixes (such as `r` or `u`), respectively.
|
||||||
|
///
|
||||||
|
/// See the documentation for [`StringLiteralFlags`] for additional caveats on this constructor,
|
||||||
|
/// and situations in which alternative ways to construct this struct should be used, especially
|
||||||
|
/// when writing lint rules.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self(StringLiteralFlagsInner::empty())
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
|
pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
|
||||||
self.0
|
self.0
|
||||||
|
@ -1520,7 +1549,7 @@ impl fmt::Debug for StringLiteralFlags {
|
||||||
|
|
||||||
/// An AST node that represents a single string literal which is part of an
|
/// An AST node that represents a single string literal which is part of an
|
||||||
/// [`ExprStringLiteral`].
|
/// [`ExprStringLiteral`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct StringLiteral {
|
pub struct StringLiteral {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub value: Box<str>,
|
pub value: Box<str>,
|
||||||
|
@ -1546,7 +1575,7 @@ impl StringLiteral {
|
||||||
Self {
|
Self {
|
||||||
range,
|
range,
|
||||||
value: "".into(),
|
value: "".into(),
|
||||||
flags: StringLiteralFlags::default().with_invalid(),
|
flags: StringLiteralFlags::empty().with_invalid(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2115,7 +2144,7 @@ impl From<AnyStringFlags> for StringLiteralFlags {
|
||||||
value.prefix()
|
value.prefix()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let new = StringLiteralFlags::default()
|
let new = StringLiteralFlags::empty()
|
||||||
.with_quote_style(value.quote_style())
|
.with_quote_style(value.quote_style())
|
||||||
.with_prefix(prefix);
|
.with_prefix(prefix);
|
||||||
if value.is_triple_quoted() {
|
if value.is_triple_quoted() {
|
||||||
|
|
|
@ -6,8 +6,8 @@ use ruff_python_ast::str::Quote;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Alias, ArgOrKeyword, BoolOp, CmpOp, Comprehension, ConversionFlag, DebugText,
|
self as ast, Alias, ArgOrKeyword, BoolOp, CmpOp, Comprehension, ConversionFlag, DebugText,
|
||||||
ExceptHandler, Expr, Identifier, MatchCase, Operator, Parameter, Parameters, Pattern,
|
ExceptHandler, Expr, Identifier, MatchCase, Operator, Parameter, Parameters, Pattern,
|
||||||
Singleton, Stmt, Suite, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
|
Singleton, Stmt, StringFlags, Suite, TypeParam, TypeParamParamSpec, TypeParamTypeVar,
|
||||||
WithItem,
|
TypeParamTypeVarTuple, WithItem,
|
||||||
};
|
};
|
||||||
use ruff_python_ast::{ParameterWithDefault, TypeParams};
|
use ruff_python_ast::{ParameterWithDefault, TypeParams};
|
||||||
use ruff_python_literal::escape::{AsciiEscape, Escape, UnicodeEscape};
|
use ruff_python_literal::escape::{AsciiEscape, Escape, UnicodeEscape};
|
||||||
|
@ -65,7 +65,10 @@ mod precedence {
|
||||||
pub struct Generator<'a> {
|
pub struct Generator<'a> {
|
||||||
/// The indentation style to use.
|
/// The indentation style to use.
|
||||||
indent: &'a Indentation,
|
indent: &'a Indentation,
|
||||||
/// The quote style to use for string literals.
|
/// The quote style to use for bytestring and f-string literals. For a plain
|
||||||
|
/// [`StringLiteral`](ast::StringLiteral), modify its `flags` field using
|
||||||
|
/// [`StringLiteralFlags::with_quote_style`](ast::StringLiteralFlags::with_quote_style) before
|
||||||
|
/// passing it to the [`Generator`].
|
||||||
quote: Quote,
|
quote: Quote,
|
||||||
/// The line ending to use.
|
/// The line ending to use.
|
||||||
line_ending: LineEnding,
|
line_ending: LineEnding,
|
||||||
|
@ -158,8 +161,8 @@ impl<'a> Generator<'a> {
|
||||||
escape.bytes_repr().write(&mut self.buffer).unwrap(); // write to string doesn't fail
|
escape.bytes_repr().write(&mut self.buffer).unwrap(); // write to string doesn't fail
|
||||||
}
|
}
|
||||||
|
|
||||||
fn p_str_repr(&mut self, s: &str) {
|
fn p_str_repr(&mut self, s: &str, quote: Quote) {
|
||||||
let escape = UnicodeEscape::with_preferred_quote(s, self.quote);
|
let escape = UnicodeEscape::with_preferred_quote(s, quote);
|
||||||
if let Some(len) = escape.layout().len {
|
if let Some(len) = escape.layout().len {
|
||||||
self.buffer.reserve(len);
|
self.buffer.reserve(len);
|
||||||
}
|
}
|
||||||
|
@ -1288,14 +1291,14 @@ impl<'a> Generator<'a> {
|
||||||
// replacement here
|
// replacement here
|
||||||
if flags.prefix().is_raw() {
|
if flags.prefix().is_raw() {
|
||||||
self.p(flags.prefix().as_str());
|
self.p(flags.prefix().as_str());
|
||||||
self.p(self.quote.as_str());
|
self.p(flags.quote_str());
|
||||||
self.p(value);
|
self.p(value);
|
||||||
self.p(self.quote.as_str());
|
self.p(flags.quote_str());
|
||||||
} else {
|
} else {
|
||||||
if flags.prefix().is_unicode() {
|
if flags.prefix().is_unicode() {
|
||||||
self.p("u");
|
self.p("u");
|
||||||
}
|
}
|
||||||
self.p_str_repr(value);
|
self.p_str_repr(value, flags.quote_style());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1403,7 +1406,7 @@ impl<'a> Generator<'a> {
|
||||||
Generator::new(self.indent, self.quote.opposite(), self.line_ending);
|
Generator::new(self.indent, self.quote.opposite(), self.line_ending);
|
||||||
generator.unparse_f_string_body(values);
|
generator.unparse_f_string_body(values);
|
||||||
let body = &generator.buffer;
|
let body = &generator.buffer;
|
||||||
self.p_str_repr(body);
|
self.p_str_repr(body, self.quote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1444,6 +1447,24 @@ mod tests {
|
||||||
generator.generate()
|
generator.generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like [`round_trip`] but configure the [`Generator`] with the requested `indentation`,
|
||||||
|
/// `quote`, and `line_ending` settings.
|
||||||
|
///
|
||||||
|
/// Note that quoting styles for string literals are taken from their [`StringLiteralFlags`],
|
||||||
|
/// not from the [`Generator`] itself, so using this function on a plain string literal can give
|
||||||
|
/// surprising results.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// assert_eq!(
|
||||||
|
/// round_trip_with(
|
||||||
|
/// &Indentation::default(),
|
||||||
|
/// Quote::Double,
|
||||||
|
/// LineEnding::default(),
|
||||||
|
/// r#"'hello'"#
|
||||||
|
/// ),
|
||||||
|
/// r#"'hello'"#
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
fn round_trip_with(
|
fn round_trip_with(
|
||||||
indentation: &Indentation,
|
indentation: &Indentation,
|
||||||
quote: Quote,
|
quote: Quote,
|
||||||
|
@ -1719,14 +1740,14 @@ class Foo:
|
||||||
#[test]
|
#[test]
|
||||||
fn quote() {
|
fn quote() {
|
||||||
assert_eq!(round_trip(r#""hello""#), r#""hello""#);
|
assert_eq!(round_trip(r#""hello""#), r#""hello""#);
|
||||||
assert_eq!(round_trip(r"'hello'"), r#""hello""#);
|
assert_round_trip!(r"'hello'");
|
||||||
assert_eq!(round_trip(r"u'hello'"), r#"u"hello""#);
|
assert_round_trip!(r"u'hello'");
|
||||||
assert_eq!(round_trip(r"r'hello'"), r#"r"hello""#);
|
assert_round_trip!(r"r'hello'");
|
||||||
assert_eq!(round_trip(r"b'hello'"), r#"b"hello""#);
|
assert_eq!(round_trip(r"b'hello'"), r#"b"hello""#);
|
||||||
assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abc" "def" "ghi""#);
|
assert_eq!(round_trip(r#"("abc" "def" "ghi")"#), r#""abc" "def" "ghi""#);
|
||||||
assert_eq!(round_trip(r#""he\"llo""#), r#"'he"llo'"#);
|
assert_eq!(round_trip(r#""he\"llo""#), r#"'he"llo'"#);
|
||||||
assert_eq!(round_trip(r#"f"abc{'def'}{1}""#), r#"f"abc{'def'}{1}""#);
|
assert_eq!(round_trip(r#"f"abc{'def'}{1}""#), r#"f"abc{'def'}{1}""#);
|
||||||
assert_eq!(round_trip(r#"f'abc{"def"}{1}'"#), r#"f"abc{'def'}{1}""#);
|
assert_round_trip!(r#"f'abc{"def"}{1}'"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1773,42 +1794,37 @@ if True:
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_quote() {
|
fn set_quote() {
|
||||||
assert_eq!(
|
macro_rules! round_trip_with {
|
||||||
round_trip_with(
|
($quote:expr, $start:expr, $end:expr) => {
|
||||||
&Indentation::default(),
|
assert_eq!(
|
||||||
Quote::Double,
|
round_trip_with(
|
||||||
LineEnding::default(),
|
&Indentation::default(),
|
||||||
r#""hello""#
|
$quote,
|
||||||
),
|
LineEnding::default(),
|
||||||
r#""hello""#
|
$start
|
||||||
);
|
),
|
||||||
assert_eq!(
|
$end,
|
||||||
round_trip_with(
|
);
|
||||||
&Indentation::default(),
|
};
|
||||||
Quote::Single,
|
}
|
||||||
LineEnding::default(),
|
|
||||||
r#""hello""#
|
// setting Generator::quote works for bytestrings
|
||||||
),
|
round_trip_with!(Quote::Double, r#"b"hello""#, r#"b"hello""#);
|
||||||
r"'hello'"
|
round_trip_with!(Quote::Single, r#"b"hello""#, r"b'hello'");
|
||||||
);
|
round_trip_with!(Quote::Double, r"b'hello'", r#"b"hello""#);
|
||||||
assert_eq!(
|
round_trip_with!(Quote::Single, r"b'hello'", r"b'hello'");
|
||||||
round_trip_with(
|
|
||||||
&Indentation::default(),
|
// and for f-strings
|
||||||
Quote::Double,
|
round_trip_with!(Quote::Double, r#"f"hello""#, r#"f"hello""#);
|
||||||
LineEnding::default(),
|
round_trip_with!(Quote::Single, r#"f"hello""#, r"f'hello'");
|
||||||
r"'hello'"
|
round_trip_with!(Quote::Double, r"f'hello'", r#"f"hello""#);
|
||||||
),
|
round_trip_with!(Quote::Single, r"f'hello'", r"f'hello'");
|
||||||
r#""hello""#
|
|
||||||
);
|
// but not for string literals, where the `Quote` is taken directly from their flags
|
||||||
assert_eq!(
|
round_trip_with!(Quote::Double, r#""hello""#, r#""hello""#);
|
||||||
round_trip_with(
|
round_trip_with!(Quote::Single, r#""hello""#, r#""hello""#); // no effect
|
||||||
&Indentation::default(),
|
round_trip_with!(Quote::Double, r"'hello'", r#"'hello'"#); // no effect
|
||||||
Quote::Single,
|
round_trip_with!(Quote::Single, r"'hello'", r"'hello'");
|
||||||
LineEnding::default(),
|
|
||||||
r"'hello'"
|
|
||||||
),
|
|
||||||
r"'hello'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -4,12 +4,12 @@ use {
|
||||||
regex::Regex,
|
regex::Regex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ruff_python_ast::visitor::transformer;
|
|
||||||
use ruff_python_ast::visitor::transformer::Transformer;
|
use ruff_python_ast::visitor::transformer::Transformer;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, BytesLiteralFlags, Expr, FStringElement, FStringFlags, FStringLiteralElement,
|
self as ast, BytesLiteralFlags, Expr, FStringElement, FStringFlags, FStringLiteralElement,
|
||||||
FStringPart, Stmt, StringFlags, StringLiteralFlags,
|
FStringPart, Stmt, StringFlags,
|
||||||
};
|
};
|
||||||
|
use ruff_python_ast::{visitor::transformer, StringLiteralFlags};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
/// A struct to normalize AST nodes for the purpose of comparing formatted representations for
|
/// A struct to normalize AST nodes for the purpose of comparing formatted representations for
|
||||||
|
@ -81,7 +81,7 @@ impl Transformer for Normalizer {
|
||||||
string.value = ast::StringLiteralValue::single(ast::StringLiteral {
|
string.value = ast::StringLiteralValue::single(ast::StringLiteral {
|
||||||
value: string.value.to_str().to_string().into_boxed_str(),
|
value: string.value.to_str().to_string().into_boxed_str(),
|
||||||
range: string.range,
|
range: string.range,
|
||||||
flags: StringLiteralFlags::default(),
|
flags: StringLiteralFlags::empty(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ pub fn parse_parenthesized_expression_range(
|
||||||
///
|
///
|
||||||
/// let string = StringLiteral {
|
/// let string = StringLiteral {
|
||||||
/// value: "'''\n int | str'''".to_string().into_boxed_str(),
|
/// value: "'''\n int | str'''".to_string().into_boxed_str(),
|
||||||
/// flags: StringLiteralFlags::default(),
|
/// flags: StringLiteralFlags::empty(),
|
||||||
/// range: TextRange::new(TextSize::new(0), TextSize::new(16)),
|
/// range: TextRange::new(TextSize::new(0), TextSize::new(16)),
|
||||||
/// };
|
/// };
|
||||||
/// let parsed = parse_string_annotation("'''\n int | str'''", &string);
|
/// let parsed = parse_string_annotation("'''\n int | str'''", &string);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue