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<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() # []
|
||||
"/abc/".split() # ['/abc/']
|
||||
"/abc/".split() # ["/abc/"]
|
||||
("a,b,c"
|
||||
# comment
|
||||
.split()
|
||||
) # ['a,b,c']
|
||||
) # ["a,b,c"]
|
||||
("a,b,c"
|
||||
# comment1
|
||||
.split(",")
|
||||
) # ['a', 'b', 'c']
|
||||
) # ["a", "b", "c"]
|
||||
("a,"
|
||||
# comment
|
||||
"b,"
|
||||
"c"
|
||||
.split(",")
|
||||
) # ['a', 'b', 'c']
|
||||
) # ["a", "b", "c"]
|
||||
|
||||
"hello "\
|
||||
"world".split()
|
||||
# ['hello', 'world']
|
||||
# ["hello", "world"]
|
||||
|
||||
# prefixes and isc
|
||||
u"a b".split() # ['a', 'b']
|
||||
r"a \n b".split() # ['a', '\\n', 'b']
|
||||
("a " "b").split() # ['a', 'b']
|
||||
"a " "b".split() # ['a', 'b']
|
||||
u"a " "b".split() # ['a', 'b']
|
||||
"a " u"b".split() # ['a', 'b']
|
||||
u"a " r"\n".split() # ['a', '\\n']
|
||||
r"\n " u"\n".split() # ['\\n']
|
||||
r"\n " "\n".split() # ['\\n']
|
||||
"a " r"\n".split() # ['a', '\\n']
|
||||
u"a b".split() # [u"a", u"b"]
|
||||
r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
("a " "b").split() # ["a", "b"]
|
||||
"a " "b".split() # ["a", "b"]
|
||||
u"a " "b".split() # [u"a", u"b"]
|
||||
"a " u"b".split() # ["a", "b"]
|
||||
u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
r"\n " u"\n".split() # [r"\n"]
|
||||
r"\n " "\n".split() # [r"\n"]
|
||||
"a " r"\n".split() # ["a", "\\n"]
|
||||
|
||||
"a,b,c".split(',', maxsplit=0) # ['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=-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=-2) # ["a", "b", "c"]
|
||||
"a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||
|
||||
# negatives
|
||||
|
||||
|
|
|
@ -82,3 +82,11 @@ class Collection(Protocol[*_B0]):
|
|||
# Regression test for: https://github.com/astral-sh/ruff/issues/8609
|
||||
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", 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,
|
||||
attr,
|
||||
call,
|
||||
string_value.to_str(),
|
||||
string_value,
|
||||
);
|
||||
}
|
||||
} else if attr == "format" {
|
||||
|
|
|
@ -296,11 +296,23 @@ impl<'a> Checker<'a> {
|
|||
pub(crate) fn generator(&self) -> Generator {
|
||||
Generator::new(
|
||||
self.stylist.indentation(),
|
||||
self.f_string_quote_style().unwrap_or(self.stylist.quote()),
|
||||
self.preferred_quote(),
|
||||
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
|
||||
/// the f-string.
|
||||
///
|
||||
|
|
|
@ -4,7 +4,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
|||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::comparable::ComparableExpr;
|
||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext};
|
||||
use ruff_python_ast::{self as ast, Expr, ExprCall, ExprContext, StringLiteralFlags};
|
||||
use ruff_python_codegen::Generator;
|
||||
use ruff_python_trivia::CommentRanges;
|
||||
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) {
|
||||
return None;
|
||||
}
|
||||
|
@ -298,7 +298,8 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
|
|||
acc
|
||||
})
|
||||
.into_boxed_str(),
|
||||
..ast::StringLiteral::default()
|
||||
range: TextRange::default(),
|
||||
flags,
|
||||
});
|
||||
Some(generator.expr(&node))
|
||||
}
|
||||
|
@ -358,8 +359,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
|||
.iter()
|
||||
.map(|name| {
|
||||
Expr::from(ast::StringLiteral {
|
||||
value: (*name).to_string().into_boxed_str(),
|
||||
..ast::StringLiteral::default()
|
||||
value: Box::from(*name),
|
||||
range: TextRange::default(),
|
||||
flags: checker.default_string_flags(),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
|
@ -393,8 +395,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
|||
.iter()
|
||||
.map(|name| {
|
||||
Expr::from(ast::StringLiteral {
|
||||
value: (*name).to_string().into_boxed_str(),
|
||||
..ast::StringLiteral::default()
|
||||
value: Box::from(*name),
|
||||
range: TextRange::default(),
|
||||
flags: checker.default_string_flags(),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
|
@ -444,7 +447,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
|||
},
|
||||
expr.range(),
|
||||
);
|
||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
||||
if let Some(content) =
|
||||
elts_to_csv(elts, checker.generator(), checker.default_string_flags())
|
||||
{
|
||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||
content,
|
||||
expr.range(),
|
||||
|
@ -489,7 +494,9 @@ fn check_names(checker: &mut Checker, call: &ExprCall, expr: &Expr, argvalues: &
|
|||
},
|
||||
expr.range(),
|
||||
);
|
||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
||||
if let Some(content) =
|
||||
elts_to_csv(elts, checker.generator(), checker.default_string_flags())
|
||||
{
|
||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||
content,
|
||||
expr.range(),
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use ruff_python_ast::{
|
||||
self as ast, str_prefix::StringLiteralPrefix, Arguments, Expr, StringLiteralFlags,
|
||||
};
|
||||
use ruff_text_size::Ranged;
|
||||
use ruff_python_ast::{self as ast, str_prefix::StringLiteralPrefix, Arguments, Expr};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::fix::snippet::SourceCodeSnippet;
|
||||
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 {
|
||||
value: capital_env_var.into_boxed_str(),
|
||||
flags: StringLiteralFlags::default().with_prefix({
|
||||
flags: checker.default_string_flags().with_prefix({
|
||||
if env_var.is_unicode() {
|
||||
StringLiteralPrefix::Unicode
|
||||
} else {
|
||||
StringLiteralPrefix::Empty
|
||||
}
|
||||
}),
|
||||
..ast::StringLiteral::default()
|
||||
range: TextRange::default(),
|
||||
};
|
||||
let new_env_var = node.into();
|
||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn split_static_string(
|
|||
checker: &mut Checker,
|
||||
attr: &str,
|
||||
call: &ExprCall,
|
||||
str_value: &str,
|
||||
str_value: &StringLiteralValue,
|
||||
) {
|
||||
let ExprCall { arguments, .. } = call;
|
||||
|
||||
|
@ -115,16 +115,16 @@ pub(crate) fn split_static_string(
|
|||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
fn construct_replacement(elts: &[&str]) -> Expr {
|
||||
fn construct_replacement(elts: &[&str], flags: StringLiteralFlags) -> Expr {
|
||||
Expr::List(ExprList {
|
||||
elts: elts
|
||||
.iter()
|
||||
.map(|elt| {
|
||||
Expr::StringLiteral(ExprStringLiteral {
|
||||
value: StringLiteralValue::single(StringLiteral {
|
||||
value: (*elt).to_string().into_boxed_str(),
|
||||
value: Box::from(*elt),
|
||||
range: TextRange::default(),
|
||||
flags: StringLiteralFlags::default(),
|
||||
flags,
|
||||
}),
|
||||
range: TextRange::default(),
|
||||
})
|
||||
|
@ -135,7 +135,7 @@ fn construct_replacement(elts: &[&str]) -> Expr {
|
|||
})
|
||||
}
|
||||
|
||||
fn split_default(str_value: &str, max_split: i32) -> Option<Expr> {
|
||||
fn split_default(str_value: &StringLiteralValue, max_split: i32) -> Option<Expr> {
|
||||
// From the Python documentation:
|
||||
// > If sep is not specified or is None, a different splitting algorithm is applied: runs of
|
||||
// > consecutive whitespace are regarded as a single separator, and the result will contain
|
||||
|
@ -151,30 +151,36 @@ fn split_default(str_value: &str, max_split: i32) -> Option<Expr> {
|
|||
None
|
||||
}
|
||||
Ordering::Equal => {
|
||||
let list_items: Vec<&str> = vec![str_value];
|
||||
Some(construct_replacement(&list_items))
|
||||
let list_items: Vec<&str> = vec![str_value.to_str()];
|
||||
Some(construct_replacement(&list_items, str_value.flags()))
|
||||
}
|
||||
Ordering::Less => {
|
||||
let list_items: Vec<&str> = str_value.split_whitespace().collect();
|
||||
Some(construct_replacement(&list_items))
|
||||
let list_items: Vec<&str> = str_value.to_str().split_whitespace().collect();
|
||||
Some(construct_replacement(&list_items, str_value.flags()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn split_sep(str_value: &str, sep_value: &str, max_split: i32, direction: Direction) -> Expr {
|
||||
fn split_sep(
|
||||
str_value: &StringLiteralValue,
|
||||
sep_value: &str,
|
||||
max_split: i32,
|
||||
direction: Direction,
|
||||
) -> Expr {
|
||||
let value = str_value.to_str();
|
||||
let list_items: Vec<&str> = if let Ok(split_n) = usize::try_from(max_split) {
|
||||
match direction {
|
||||
Direction::Left => str_value.splitn(split_n + 1, sep_value).collect(),
|
||||
Direction::Right => str_value.rsplitn(split_n + 1, sep_value).collect(),
|
||||
Direction::Left => value.splitn(split_n + 1, sep_value).collect(),
|
||||
Direction::Right => value.rsplitn(split_n + 1, sep_value).collect(),
|
||||
}
|
||||
} else {
|
||||
match direction {
|
||||
Direction::Left => str_value.split(sep_value).collect(),
|
||||
Direction::Right => str_value.rsplit(sep_value).collect(),
|
||||
Direction::Left => value.split(sep_value).collect(),
|
||||
Direction::Right => value.rsplit(sep_value).collect(),
|
||||
}
|
||||
};
|
||||
|
||||
construct_replacement(&list_items)
|
||||
construct_replacement(&list_items, str_value.flags())
|
||||
}
|
||||
|
||||
/// Returns the value of the `maxsplit` argument as an `i32`, if it is a numeric value.
|
||||
|
|
|
@ -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)
|
||||
28 28 | "VERB AUX PRON ADP DET".split(" ")
|
||||
29 |-' 1 2 3 '.split()
|
||||
29 |+["1", "2", "3"]
|
||||
29 |+['1', '2', '3']
|
||||
30 30 | '1<>2<>3<4'.split('<>')
|
||||
31 31 |
|
||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
||||
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`
|
||||
|
|
||||
|
@ -331,7 +331,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
|||
30 | '1<>2<>3<4'.split('<>')
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
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
|
||||
|
||||
|
@ -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(" ")
|
||||
29 29 | ' 1 2 3 '.split()
|
||||
30 |-'1<>2<>3<4'.split('<>')
|
||||
30 |+["1", "2", "3<4"]
|
||||
30 |+['1', '2', '3<4']
|
||||
31 31 |
|
||||
32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a ']
|
||||
32 32 | " a*a a*a a ".split("*", -1) # [" a", "a a", "a a "]
|
||||
33 33 | "".split() # []
|
||||
|
||||
SIM905.py:32:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
30 | '1<>2<>3<4'.split('<>')
|
||||
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
|
||||
33 | "".split() # []
|
||||
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()
|
||||
30 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 "] # [' 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 "]
|
||||
33 33 | "".split() # []
|
||||
34 34 | """
|
||||
35 35 | """.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() # []
|
||||
| ^^^^^^^^^^ SIM905
|
||||
34 | """
|
||||
|
@ -379,7 +379,7 @@ SIM905.py:33:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
|||
ℹ Safe fix
|
||||
30 30 | '1<>2<>3<4'.split('<>')
|
||||
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 |+[] # []
|
||||
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`
|
||||
|
|
||||
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() # []
|
||||
34 | / """
|
||||
35 | | """.split() # []
|
||||
| |___________^ SIM905
|
||||
36 | " ".split() # []
|
||||
37 | "/abc/".split() # ['/abc/']
|
||||
37 | "/abc/".split() # ["/abc/"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
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() # []
|
||||
34 |-"""
|
||||
35 |-""".split() # []
|
||||
34 |+[] # []
|
||||
36 35 | " ".split() # []
|
||||
37 36 | "/abc/".split() # ['/abc/']
|
||||
37 36 | "/abc/".split() # ["/abc/"]
|
||||
38 37 | ("a,b,c"
|
||||
|
||||
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() # []
|
||||
36 | " ".split() # []
|
||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||
37 | "/abc/".split() # ['/abc/']
|
||||
37 | "/abc/".split() # ["/abc/"]
|
||||
38 | ("a,b,c"
|
||||
|
|
||||
= 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() # []
|
||||
36 |-" ".split() # []
|
||||
36 |+[] # []
|
||||
37 37 | "/abc/".split() # ['/abc/']
|
||||
37 37 | "/abc/".split() # ["/abc/"]
|
||||
38 38 | ("a,b,c"
|
||||
39 39 | # comment
|
||||
|
||||
|
@ -434,7 +434,7 @@ SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
|||
|
|
||||
35 | """.split() # []
|
||||
36 | " ".split() # []
|
||||
37 | "/abc/".split() # ['/abc/']
|
||||
37 | "/abc/".split() # ["/abc/"]
|
||||
| ^^^^^^^^^^^^^^^ SIM905
|
||||
38 | ("a,b,c"
|
||||
39 | # comment
|
||||
|
@ -445,8 +445,8 @@ SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
|||
34 34 | """
|
||||
35 35 | """.split() # []
|
||||
36 36 | " ".split() # []
|
||||
37 |-"/abc/".split() # ['/abc/']
|
||||
37 |+["/abc/"] # ['/abc/']
|
||||
37 |-"/abc/".split() # ["/abc/"]
|
||||
37 |+["/abc/"] # ["/abc/"]
|
||||
38 38 | ("a,b,c"
|
||||
39 39 | # comment
|
||||
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`
|
||||
|
|
||||
36 | " ".split() # []
|
||||
37 | "/abc/".split() # ['/abc/']
|
||||
37 | "/abc/".split() # ["/abc/"]
|
||||
38 | ("a,b,c"
|
||||
| __^
|
||||
39 | | # comment
|
||||
40 | | .split()
|
||||
| |________^ SIM905
|
||||
41 | ) # ['a,b,c']
|
||||
41 | ) # ["a,b,c"]
|
||||
42 | ("a,b,c"
|
||||
|
|
||||
= 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
|
||||
35 35 | """.split() # []
|
||||
36 36 | " ".split() # []
|
||||
37 37 | "/abc/".split() # ['/abc/']
|
||||
37 37 | "/abc/".split() # ["/abc/"]
|
||||
38 |-("a,b,c"
|
||||
39 |-# comment
|
||||
40 |-.split()
|
||||
38 |+(["a,b,c"]
|
||||
41 39 | ) # ['a,b,c']
|
||||
41 39 | ) # ["a,b,c"]
|
||||
42 40 | ("a,b,c"
|
||||
43 41 | # comment1
|
||||
|
||||
SIM905.py:42:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
40 | .split()
|
||||
41 | ) # ['a,b,c']
|
||||
41 | ) # ["a,b,c"]
|
||||
42 | ("a,b,c"
|
||||
| __^
|
||||
43 | | # comment1
|
||||
44 | | .split(",")
|
||||
| |___________^ SIM905
|
||||
45 | ) # ['a', 'b', 'c']
|
||||
45 | ) # ["a", "b", "c"]
|
||||
46 | ("a,"
|
||||
|
|
||||
= 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
|
||||
39 39 | # comment
|
||||
40 40 | .split()
|
||||
41 41 | ) # ['a,b,c']
|
||||
41 41 | ) # ["a,b,c"]
|
||||
42 |-("a,b,c"
|
||||
43 |-# comment1
|
||||
44 |-.split(",")
|
||||
42 |+(["a", "b", "c"]
|
||||
45 43 | ) # ['a', 'b', 'c']
|
||||
45 43 | ) # ["a", "b", "c"]
|
||||
46 44 | ("a,"
|
||||
47 45 | # comment
|
||||
|
||||
SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
44 | .split(",")
|
||||
45 | ) # ['a', 'b', 'c']
|
||||
45 | ) # ["a", "b", "c"]
|
||||
46 | ("a,"
|
||||
| __^
|
||||
47 | | # comment
|
||||
|
@ -514,320 +514,320 @@ SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split`
|
|||
49 | | "c"
|
||||
50 | | .split(",")
|
||||
| |___________^ SIM905
|
||||
51 | ) # ['a', 'b', 'c']
|
||||
51 | ) # ["a", "b", "c"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Unsafe fix
|
||||
43 43 | # comment1
|
||||
44 44 | .split(",")
|
||||
45 45 | ) # ['a', 'b', 'c']
|
||||
45 45 | ) # ["a", "b", "c"]
|
||||
46 |-("a,"
|
||||
47 |-# comment
|
||||
48 |-"b,"
|
||||
49 |-"c"
|
||||
50 |-.split(",")
|
||||
46 |+(["a", "b", "c"]
|
||||
51 47 | ) # ['a', 'b', 'c']
|
||||
51 47 | ) # ["a", "b", "c"]
|
||||
52 48 |
|
||||
53 49 | "hello "\
|
||||
|
||||
SIM905.py:53:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
51 | ) # ['a', 'b', 'c']
|
||||
51 | ) # ["a", "b", "c"]
|
||||
52 |
|
||||
53 | / "hello "\
|
||||
54 | | "world".split()
|
||||
| |___________________^ SIM905
|
||||
55 | # ['hello', 'world']
|
||||
55 | # ["hello", "world"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
50 50 | .split(",")
|
||||
51 51 | ) # ['a', 'b', 'c']
|
||||
51 51 | ) # ["a", "b", "c"]
|
||||
52 52 |
|
||||
53 |-"hello "\
|
||||
54 |- "world".split()
|
||||
53 |+["hello", "world"]
|
||||
55 54 | # ['hello', 'world']
|
||||
55 54 | # ["hello", "world"]
|
||||
56 55 |
|
||||
57 56 | # prefixes and isc
|
||||
|
||||
SIM905.py:58:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
57 | # prefixes and isc
|
||||
58 | u"a b".split() # ['a', 'b']
|
||||
58 | u"a b".split() # [u"a", u"b"]
|
||||
| ^^^^^^^^^^^^^^ SIM905
|
||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 | ("a " "b").split() # ['a', 'b']
|
||||
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 | ("a " "b").split() # ["a", "b"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
55 55 | # ['hello', 'world']
|
||||
55 55 | # ["hello", "world"]
|
||||
56 56 |
|
||||
57 57 | # prefixes and isc
|
||||
58 |-u"a b".split() # ['a', 'b']
|
||||
58 |+["a", "b"] # ['a', 'b']
|
||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 60 | ("a " "b").split() # ['a', 'b']
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
58 |-u"a b".split() # [u"a", u"b"]
|
||||
58 |+[u"a", u"b"] # [u"a", u"b"]
|
||||
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 60 | ("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`
|
||||
|
|
||||
57 | # prefixes and isc
|
||||
58 | u"a b".split() # ['a', 'b']
|
||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
58 | u"a b".split() # [u"a", u"b"]
|
||||
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||
60 | ("a " "b").split() # ['a', 'b']
|
||||
61 | "a " "b".split() # ['a', 'b']
|
||||
60 | ("a " "b").split() # ["a", "b"]
|
||||
61 | "a " "b".split() # ["a", "b"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
56 56 |
|
||||
57 57 | # prefixes and isc
|
||||
58 58 | u"a b".split() # ['a', 'b']
|
||||
59 |-r"a \n b".split() # ['a', '\\n', 'b']
|
||||
59 |+["a", "\\n", "b"] # ['a', '\\n', 'b']
|
||||
60 60 | ("a " "b").split() # ['a', 'b']
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
58 58 | u"a b".split() # [u"a", u"b"]
|
||||
59 |-r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
59 |+[r"a", r"\n", r"b"] # [r"a", r"\n", r"b"]
|
||||
60 60 | ("a " "b").split() # ["a", "b"]
|
||||
61 61 | "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`
|
||||
|
|
||||
58 | u"a b".split() # ['a', 'b']
|
||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 | ("a " "b").split() # ['a', 'b']
|
||||
58 | u"a b".split() # [u"a", u"b"]
|
||||
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 | ("a " "b").split() # ["a", "b"]
|
||||
| ^^^^^^^^^^^^^^^^^^ SIM905
|
||||
61 | "a " "b".split() # ['a', 'b']
|
||||
62 | u"a " "b".split() # ['a', 'b']
|
||||
61 | "a " "b".split() # ["a", "b"]
|
||||
62 | u"a " "b".split() # [u"a", u"b"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
57 57 | # prefixes and isc
|
||||
58 58 | u"a b".split() # ['a', 'b']
|
||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 |-("a " "b").split() # ['a', 'b']
|
||||
60 |+["a", "b"] # ['a', 'b']
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
58 58 | u"a b".split() # [u"a", u"b"]
|
||||
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 |-("a " "b").split() # ["a", "b"]
|
||||
60 |+["a", "b"] # ["a", "b"]
|
||||
61 61 | "a " "b".split() # ["a", "b"]
|
||||
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
|
||||
SIM905.py:61:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 | ("a " "b").split() # ['a', 'b']
|
||||
61 | "a " "b".split() # ['a', 'b']
|
||||
59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 | ("a " "b").split() # ["a", "b"]
|
||||
61 | "a " "b".split() # ["a", "b"]
|
||||
| ^^^^^^^^^^^^^^^^ SIM905
|
||||
62 | u"a " "b".split() # ['a', 'b']
|
||||
63 | "a " u"b".split() # ['a', 'b']
|
||||
62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 | "a " u"b".split() # ["a", "b"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
58 58 | u"a b".split() # ['a', 'b']
|
||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 60 | ("a " "b").split() # ['a', 'b']
|
||||
61 |-"a " "b".split() # ['a', 'b']
|
||||
61 |+["a", "b"] # ['a', 'b']
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
58 58 | u"a b".split() # [u"a", u"b"]
|
||||
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 60 | ("a " "b").split() # ["a", "b"]
|
||||
61 |-"a " "b".split() # ["a", "b"]
|
||||
61 |+["a", "b"] # ["a", "b"]
|
||||
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
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`
|
||||
|
|
||||
60 | ("a " "b").split() # ['a', 'b']
|
||||
61 | "a " "b".split() # ['a', 'b']
|
||||
62 | u"a " "b".split() # ['a', 'b']
|
||||
60 | ("a " "b").split() # ["a", "b"]
|
||||
61 | "a " "b".split() # ["a", "b"]
|
||||
62 | u"a " "b".split() # [u"a", u"b"]
|
||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||
63 | "a " u"b".split() # ['a', 'b']
|
||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
63 | "a " u"b".split() # ["a", "b"]
|
||||
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
59 59 | r"a \n b".split() # ['a', '\\n', 'b']
|
||||
60 60 | ("a " "b").split() # ['a', 'b']
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
62 |-u"a " "b".split() # ['a', 'b']
|
||||
62 |+["a", "b"] # ['a', 'b']
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
||||
59 59 | r"a \n b".split() # [r"a", r"\n", r"b"]
|
||||
60 60 | ("a " "b").split() # ["a", "b"]
|
||||
61 61 | "a " "b".split() # ["a", "b"]
|
||||
62 |-u"a " "b".split() # [u"a", u"b"]
|
||||
62 |+[u"a", u"b"] # [u"a", u"b"]
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||
|
||||
SIM905.py:63:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
61 | "a " "b".split() # ['a', 'b']
|
||||
62 | u"a " "b".split() # ['a', 'b']
|
||||
63 | "a " u"b".split() # ['a', 'b']
|
||||
61 | "a " "b".split() # ["a", "b"]
|
||||
62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 | "a " u"b".split() # ["a", "b"]
|
||||
| ^^^^^^^^^^^^^^^^^ SIM905
|
||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 | r"\n " u"\n".split() # ['\\n']
|
||||
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 | r"\n " u"\n".split() # [r"\n"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
60 60 | ("a " "b").split() # ['a', 'b']
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
63 |-"a " u"b".split() # ['a', 'b']
|
||||
63 |+["a", "b"] # ['a', 'b']
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 66 | r"\n " "\n".split() # ['\\n']
|
||||
60 60 | ("a " "b").split() # ["a", "b"]
|
||||
61 61 | "a " "b".split() # ["a", "b"]
|
||||
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 |-"a " u"b".split() # ["a", "b"]
|
||||
63 |+["a", "b"] # ["a", "b"]
|
||||
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||
|
||||
SIM905.py:64:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
62 | u"a " "b".split() # ['a', 'b']
|
||||
63 | "a " u"b".split() # ['a', 'b']
|
||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 | "a " u"b".split() # ["a", "b"]
|
||||
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 | r"\n " "\n".split() # ['\\n']
|
||||
65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 | r"\n " "\n".split() # [r"\n"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
61 61 | "a " "b".split() # ['a', 'b']
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
64 |-u"a " r"\n".split() # ['a', '\\n']
|
||||
64 |+["a", "\\n"] # ['a', '\\n']
|
||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 66 | r"\n " "\n".split() # ['\\n']
|
||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
||||
61 61 | "a " "b".split() # ["a", "b"]
|
||||
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
64 |-u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
64 |+[u"a", u"\\n"] # [u"a", u"\\n"]
|
||||
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
|
||||
SIM905.py:65:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
63 | "a " u"b".split() # ['a', 'b']
|
||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 | r"\n " u"\n".split() # ['\\n']
|
||||
63 | "a " u"b".split() # ["a", "b"]
|
||||
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 | r"\n " u"\n".split() # [r"\n"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
66 | r"\n " "\n".split() # ['\\n']
|
||||
67 | "a " r"\n".split() # ['a', '\\n']
|
||||
66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
62 62 | u"a " "b".split() # ['a', 'b']
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 |-r"\n " u"\n".split() # ['\\n']
|
||||
65 |+["\\n"] # ['\\n']
|
||||
66 66 | r"\n " "\n".split() # ['\\n']
|
||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
||||
62 62 | u"a " "b".split() # [u"a", u"b"]
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 |-r"\n " u"\n".split() # [r"\n"]
|
||||
65 |+[r"\n"] # [r"\n"]
|
||||
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
68 68 |
|
||||
|
||||
SIM905.py:66:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 | r"\n " "\n".split() # ['\\n']
|
||||
64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 | r"\n " "\n".split() # [r"\n"]
|
||||
| ^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
67 | "a " r"\n".split() # ['a', '\\n']
|
||||
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
63 63 | "a " u"b".split() # ['a', 'b']
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 |-r"\n " "\n".split() # ['\\n']
|
||||
66 |+["\\n"] # ['\\n']
|
||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
||||
63 63 | "a " u"b".split() # ["a", "b"]
|
||||
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 |-r"\n " "\n".split() # [r"\n"]
|
||||
66 |+[r"\n"] # [r"\n"]
|
||||
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
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`
|
||||
|
|
||||
65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 | r"\n " "\n".split() # ['\\n']
|
||||
67 | "a " r"\n".split() # ['a', '\\n']
|
||||
65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
| ^^^^^^^^^^^^^^^^^^ SIM905
|
||||
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
|
||||
|
||||
ℹ Safe fix
|
||||
64 64 | u"a " r"\n".split() # ['a', '\\n']
|
||||
65 65 | r"\n " u"\n".split() # ['\\n']
|
||||
66 66 | r"\n " "\n".split() # ['\\n']
|
||||
67 |-"a " r"\n".split() # ['a', '\\n']
|
||||
67 |+["a", "\\n"] # ['a', '\\n']
|
||||
64 64 | u"a " r"\n".split() # [u"a", u"\\n"]
|
||||
65 65 | r"\n " u"\n".split() # [r"\n"]
|
||||
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 |-"a " r"\n".split() # ["a", "\\n"]
|
||||
67 |+["a", "\\n"] # ["a", "\\n"]
|
||||
68 68 |
|
||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ['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"]
|
||||
|
||||
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 |
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
66 66 | r"\n " "\n".split() # ['\\n']
|
||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
||||
66 66 | r"\n " "\n".split() # [r"\n"]
|
||||
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
68 68 |
|
||||
69 |-"a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
||||
69 |+["a,b,c"] # ['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']
|
||||
72 72 | "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"]
|
||||
70 70 | "a,b,c".split(',', maxsplit=-1) # ["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"]
|
||||
|
||||
SIM905.py:70:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
||||
72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||
72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||
|
|
||||
= help: Replace with list literal
|
||||
|
||||
ℹ Safe fix
|
||||
67 67 | "a " r"\n".split() # ['a', '\\n']
|
||||
67 67 | "a " r"\n".split() # ["a", "\\n"]
|
||||
68 68 |
|
||||
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"] # ['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']
|
||||
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"] # ["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"]
|
||||
73 73 |
|
||||
|
||||
SIM905.py:71:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c']
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
||||
69 | "a,b,c".split(',', maxsplit=0) # ["a,b,c"]
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||
|
||||
ℹ Safe fix
|
||||
68 68 |
|
||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['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"] # ['a', 'b', 'c']
|
||||
72 72 | "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"]
|
||||
71 |-"a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||
71 |+["a", "b", "c"] # ["a", "b", "c"]
|
||||
72 72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||
73 73 |
|
||||
74 74 | # negatives
|
||||
|
||||
SIM905.py:72:1: SIM905 [*] Consider using a list literal instead of `str.split`
|
||||
|
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c']
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c']
|
||||
72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
||||
70 | "a,b,c".split(',', maxsplit=-1) # ["a", "b", "c"]
|
||||
71 | "a,b,c".split(',', maxsplit=-2) # ["a", "b", "c"]
|
||||
72 | "a,b,c".split(',', maxsplit=-0) # ["a,b,c"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905
|
||||
73 |
|
||||
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
|
||||
|
||||
ℹ Safe fix
|
||||
69 69 | "a,b,c".split(',', maxsplit=0) # ['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']
|
||||
72 |-"a,b,c".split(',', maxsplit=-0) # ['a,b,c']
|
||||
72 |+["a,b,c"] # ['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"]
|
||||
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"] # ["a,b,c"]
|
||||
73 73 |
|
||||
74 74 | # negatives
|
||||
75 75 |
|
||||
|
|
|
@ -3,8 +3,9 @@ use std::cmp::Reverse;
|
|||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
||||
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::{self as ast, Decorator, Expr};
|
||||
use ruff_python_ast::{self as ast, Decorator, Expr, StringLiteralFlags};
|
||||
use ruff_python_codegen::{Generator, Stylist};
|
||||
use ruff_python_parser::typing::parse_type_annotation;
|
||||
use ruff_python_semantic::{
|
||||
|
@ -249,6 +250,7 @@ pub(crate) fn quote_annotation(
|
|||
semantic: &SemanticModel,
|
||||
stylist: &Stylist,
|
||||
locator: &Locator,
|
||||
flags: StringLiteralFlags,
|
||||
) -> Edit {
|
||||
let expr = semantic.expression(node_id).expect("Expression not found");
|
||||
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
|
||||
// expression. For example, when quoting `DataFrame` in `DataFrame[int]`, we
|
||||
// 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)) => {
|
||||
|
@ -266,7 +268,7 @@ pub(crate) fn quote_annotation(
|
|||
// 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
|
||||
// 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)) => {
|
||||
|
@ -274,7 +276,7 @@ pub(crate) fn quote_annotation(
|
|||
// If we're quoting the function of a call, we need to quote the entire
|
||||
// expression. For example, when quoting `DataFrame` in `DataFrame()`, we
|
||||
// should generate `"DataFrame()"`.
|
||||
return quote_annotation(parent_id, semantic, stylist, locator);
|
||||
return quote_annotation(parent_id, semantic, stylist, locator, flags);
|
||||
}
|
||||
}
|
||||
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
|
||||
// quote the entire expression. For example, when quoting `DataFrame` in
|
||||
// `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.
|
||||
|
@ -305,9 +307,10 @@ pub(crate) fn quote_type_expression(
|
|||
semantic: &SemanticModel,
|
||||
stylist: &Stylist,
|
||||
locator: &Locator,
|
||||
flags: StringLiteralFlags,
|
||||
) -> Edit {
|
||||
// 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())
|
||||
}
|
||||
|
@ -336,6 +339,7 @@ pub(crate) struct QuoteAnnotator<'a> {
|
|||
semantic: &'a SemanticModel<'a>,
|
||||
stylist: &'a Stylist<'a>,
|
||||
locator: &'a Locator<'a>,
|
||||
flags: StringLiteralFlags,
|
||||
}
|
||||
|
||||
impl<'a> QuoteAnnotator<'a> {
|
||||
|
@ -343,11 +347,13 @@ impl<'a> QuoteAnnotator<'a> {
|
|||
semantic: &'a SemanticModel<'a>,
|
||||
stylist: &'a Stylist<'a>,
|
||||
locator: &'a Locator<'a>,
|
||||
flags: StringLiteralFlags,
|
||||
) -> Self {
|
||||
Self {
|
||||
semantic,
|
||||
stylist,
|
||||
locator,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,7 +372,7 @@ impl<'a> QuoteAnnotator<'a> {
|
|||
generator.expr(&Expr::from(ast::StringLiteral {
|
||||
range: TextRange::default(),
|
||||
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 !elts.is_empty() {
|
||||
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
|
||||
.match_typing_qualified_name(&qualified_name, "Literal")
|
||||
{
|
||||
// we don't want to modify anything inside `Literal`
|
||||
// so skip visiting this subscripts' slice
|
||||
// The outer annotation will use the preferred quote.
|
||||
// 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
|
||||
.semantic
|
||||
.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.stylist(),
|
||||
checker.locator(),
|
||||
checker.default_string_flags(),
|
||||
);
|
||||
if checker.comment_ranges().intersects(type_expr.range()) {
|
||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||
|
|
|
@ -278,6 +278,7 @@ fn quote_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding])
|
|||
checker.semantic(),
|
||||
checker.stylist(),
|
||||
checker.locator(),
|
||||
checker.default_string_flags(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -175,6 +175,7 @@ pub(crate) fn unquoted_type_alias(checker: &Checker, binding: &Binding) -> Optio
|
|||
checker.semantic(),
|
||||
checker.stylist(),
|
||||
checker.locator(),
|
||||
checker.default_string_flags(),
|
||||
);
|
||||
let mut diagnostics = Vec::with_capacity(names.len());
|
||||
for name in names {
|
||||
|
|
|
@ -510,6 +510,7 @@ fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) ->
|
|||
checker.semantic(),
|
||||
checker.stylist(),
|
||||
checker.locator(),
|
||||
checker.default_string_flags(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -63,11 +63,16 @@ fn is_static_length(elts: &[Expr]) -> bool {
|
|||
fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
||||
// If all elements are string constants, join them into a single string.
|
||||
if joinees.iter().all(Expr::is_string_literal_expr) {
|
||||
let mut flags = None;
|
||||
let node = ast::StringLiteral {
|
||||
value: joinees
|
||||
.iter()
|
||||
.filter_map(|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())
|
||||
} else {
|
||||
None
|
||||
|
@ -75,7 +80,8 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
|
|||
})
|
||||
.join(joiner)
|
||||
.into_boxed_str(),
|
||||
..ast::StringLiteral::default()
|
||||
flags: flags?,
|
||||
range: TextRange::default(),
|
||||
};
|
||||
return Some(node.into());
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
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_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,
|
||||
/// 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,
|
||||
/// to make the encoding explicit.
|
||||
///
|
||||
|
@ -158,14 +158,9 @@ fn generate_keyword_fix(checker: &Checker, call: &ast::ExprCall) -> Fix {
|
|||
Fix::unsafe_edit(add_argument(
|
||||
&format!(
|
||||
"encoding={}",
|
||||
checker
|
||||
.generator()
|
||||
.expr(&Expr::StringLiteral(ast::ExprStringLiteral {
|
||||
value: ast::StringLiteralValue::single(ast::StringLiteral {
|
||||
value: "utf-8".to_string().into_boxed_str(),
|
||||
flags: StringLiteralFlags::default(),
|
||||
range: TextRange::default(),
|
||||
}),
|
||||
checker.generator().expr(&Expr::from(ast::StringLiteral {
|
||||
value: Box::from("utf-8"),
|
||||
flags: checker.default_string_flags(),
|
||||
range: TextRange::default(),
|
||||
}))
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
|||
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
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 crate::checkers::ast::Checker;
|
||||
|
@ -33,9 +33,14 @@ impl FromStr for LiteralType {
|
|||
}
|
||||
|
||||
impl LiteralType {
|
||||
fn as_zero_value_expr(self) -> Expr {
|
||||
fn as_zero_value_expr(self, flags: StringLiteralFlags) -> Expr {
|
||||
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::Int => ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(Int::from(0u8)),
|
||||
|
@ -186,7 +191,7 @@ pub(crate) fn native_literals(
|
|||
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);
|
||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||
content,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
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: int | str | bytes) -> None:
|
||||
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(
|
||||
checker.generator().stmt(&Stmt::Assert(ast::StmtAssert {
|
||||
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(),
|
||||
})),
|
||||
// We have to replace the entire statement,
|
||||
|
@ -140,12 +141,13 @@ mod print_arguments {
|
|||
/// literals.
|
||||
fn fstring_elements_to_string_literals<'a>(
|
||||
mut elements: impl ExactSizeIterator<Item = &'a FStringElement>,
|
||||
flags: StringLiteralFlags,
|
||||
) -> Option<Vec<StringLiteral>> {
|
||||
elements.try_fold(Vec::with_capacity(elements.len()), |mut acc, element| {
|
||||
if let FStringElement::Literal(literal) = element {
|
||||
acc.push(StringLiteral {
|
||||
value: literal.value.clone(),
|
||||
flags: StringLiteralFlags::default(),
|
||||
flags,
|
||||
range: TextRange::default(),
|
||||
});
|
||||
Some(acc)
|
||||
|
@ -162,6 +164,7 @@ mod print_arguments {
|
|||
fn args_to_string_literal_expr<'a>(
|
||||
args: impl ExactSizeIterator<Item = &'a Vec<FStringElement>>,
|
||||
sep: impl ExactSizeIterator<Item = &'a FStringElement>,
|
||||
flags: StringLiteralFlags,
|
||||
) -> Option<Expr> {
|
||||
// If there are no arguments, short-circuit and return `None`
|
||||
if args.len() == 0 {
|
||||
|
@ -174,8 +177,8 @@ mod print_arguments {
|
|||
// of a concatenated string literal. (e.g. "text", "text" "text") The `sep` will
|
||||
// be inserted only between the outer Vecs.
|
||||
let (Some(sep), Some(args)) = (
|
||||
fstring_elements_to_string_literals(sep),
|
||||
args.map(|arg| fstring_elements_to_string_literals(arg.iter()))
|
||||
fstring_elements_to_string_literals(sep, flags),
|
||||
args.map(|arg| fstring_elements_to_string_literals(arg.iter(), flags))
|
||||
.collect::<Option<Vec<_>>>(),
|
||||
) else {
|
||||
// If any of the arguments are not string literals, return None
|
||||
|
@ -203,7 +206,7 @@ mod print_arguments {
|
|||
range: TextRange::default(),
|
||||
value: StringLiteralValue::single(StringLiteral {
|
||||
value: combined_string.into(),
|
||||
flags: StringLiteralFlags::default(),
|
||||
flags,
|
||||
range: TextRange::default(),
|
||||
}),
|
||||
}))
|
||||
|
@ -256,7 +259,7 @@ mod print_arguments {
|
|||
/// - [`Some`]<[`Expr::StringLiteral`]> if all arguments including `sep` are string literals.
|
||||
/// - [`Some`]<[`Expr::FString`]> if any of the arguments are not string literals.
|
||||
/// - [`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
|
||||
let sep = arguments
|
||||
.find_keyword("sep")
|
||||
|
@ -286,7 +289,7 @@ mod print_arguments {
|
|||
|
||||
// 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.
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
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
|
||||
|
|
||||
|
@ -211,12 +210,16 @@ RUF055_0.py:94:1: RUF055 [*] Plain string pattern passed to `re` function
|
|||
94 |-re.sub(r"a", "\?", "a")
|
||||
94 |+"a".replace(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
|
||||
|
|
||||
94 | re.sub(r"a", "\?", "a")
|
||||
95 | re.sub(r"a", r"\?", "a")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF055
|
||||
96 |
|
||||
97 | # these double as tests for preserving raw string quoting style
|
||||
|
|
||||
= 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")
|
||||
95 |-re.sub(r"a", r"\?", "a")
|
||||
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
|
||||
/// concatenated string literals.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ExprStringLiteral {
|
||||
pub range: TextRange,
|
||||
pub value: StringLiteralValue,
|
||||
}
|
||||
|
||||
/// The value representing a [`ExprStringLiteral`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct StringLiteralValue {
|
||||
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
|
||||
/// implicitly concatenated strings.
|
||||
///
|
||||
|
@ -1371,12 +1383,6 @@ enum StringLiteralValueInner {
|
|||
Concatenated(ConcatenatedStringLiteral),
|
||||
}
|
||||
|
||||
impl Default for StringLiteralValueInner {
|
||||
fn default() -> Self {
|
||||
Self::Single(StringLiteral::default())
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct StringLiteralFlagsInner: u8 {
|
||||
|
@ -1414,10 +1420,33 @@ bitflags! {
|
|||
|
||||
/// Flags that can be queried to obtain information
|
||||
/// 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);
|
||||
|
||||
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]
|
||||
pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
|
||||
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
|
||||
/// [`ExprStringLiteral`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct StringLiteral {
|
||||
pub range: TextRange,
|
||||
pub value: Box<str>,
|
||||
|
@ -1546,7 +1575,7 @@ impl StringLiteral {
|
|||
Self {
|
||||
range,
|
||||
value: "".into(),
|
||||
flags: StringLiteralFlags::default().with_invalid(),
|
||||
flags: StringLiteralFlags::empty().with_invalid(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2115,7 +2144,7 @@ impl From<AnyStringFlags> for StringLiteralFlags {
|
|||
value.prefix()
|
||||
)
|
||||
};
|
||||
let new = StringLiteralFlags::default()
|
||||
let new = StringLiteralFlags::empty()
|
||||
.with_quote_style(value.quote_style())
|
||||
.with_prefix(prefix);
|
||||
if value.is_triple_quoted() {
|
||||
|
|
|
@ -6,8 +6,8 @@ use ruff_python_ast::str::Quote;
|
|||
use ruff_python_ast::{
|
||||
self as ast, Alias, ArgOrKeyword, BoolOp, CmpOp, Comprehension, ConversionFlag, DebugText,
|
||||
ExceptHandler, Expr, Identifier, MatchCase, Operator, Parameter, Parameters, Pattern,
|
||||
Singleton, Stmt, Suite, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
|
||||
WithItem,
|
||||
Singleton, Stmt, StringFlags, Suite, TypeParam, TypeParamParamSpec, TypeParamTypeVar,
|
||||
TypeParamTypeVarTuple, WithItem,
|
||||
};
|
||||
use ruff_python_ast::{ParameterWithDefault, TypeParams};
|
||||
use ruff_python_literal::escape::{AsciiEscape, Escape, UnicodeEscape};
|
||||
|
@ -65,7 +65,10 @@ mod precedence {
|
|||
pub struct Generator<'a> {
|
||||
/// The indentation style to use.
|
||||
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,
|
||||
/// The line ending to use.
|
||||
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
|
||||
}
|
||||
|
||||
fn p_str_repr(&mut self, s: &str) {
|
||||
let escape = UnicodeEscape::with_preferred_quote(s, self.quote);
|
||||
fn p_str_repr(&mut self, s: &str, quote: Quote) {
|
||||
let escape = UnicodeEscape::with_preferred_quote(s, quote);
|
||||
if let Some(len) = escape.layout().len {
|
||||
self.buffer.reserve(len);
|
||||
}
|
||||
|
@ -1288,14 +1291,14 @@ impl<'a> Generator<'a> {
|
|||
// replacement here
|
||||
if flags.prefix().is_raw() {
|
||||
self.p(flags.prefix().as_str());
|
||||
self.p(self.quote.as_str());
|
||||
self.p(flags.quote_str());
|
||||
self.p(value);
|
||||
self.p(self.quote.as_str());
|
||||
self.p(flags.quote_str());
|
||||
} else {
|
||||
if flags.prefix().is_unicode() {
|
||||
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.unparse_f_string_body(values);
|
||||
let body = &generator.buffer;
|
||||
self.p_str_repr(body);
|
||||
self.p_str_repr(body, self.quote);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1444,6 +1447,24 @@ mod tests {
|
|||
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(
|
||||
indentation: &Indentation,
|
||||
quote: Quote,
|
||||
|
@ -1719,14 +1740,14 @@ class Foo:
|
|||
#[test]
|
||||
fn quote() {
|
||||
assert_eq!(round_trip(r#""hello""#), r#""hello""#);
|
||||
assert_eq!(round_trip(r"'hello'"), r#""hello""#);
|
||||
assert_eq!(round_trip(r"u'hello'"), r#"u"hello""#);
|
||||
assert_eq!(round_trip(r"r'hello'"), r#"r"hello""#);
|
||||
assert_round_trip!(r"'hello'");
|
||||
assert_round_trip!(r"u'hello'");
|
||||
assert_round_trip!(r"r'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#""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_round_trip!(r#"f'abc{"def"}{1}'"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1773,42 +1794,37 @@ if True:
|
|||
|
||||
#[test]
|
||||
fn set_quote() {
|
||||
macro_rules! round_trip_with {
|
||||
($quote:expr, $start:expr, $end:expr) => {
|
||||
assert_eq!(
|
||||
round_trip_with(
|
||||
&Indentation::default(),
|
||||
Quote::Double,
|
||||
$quote,
|
||||
LineEnding::default(),
|
||||
r#""hello""#
|
||||
$start
|
||||
),
|
||||
r#""hello""#
|
||||
);
|
||||
assert_eq!(
|
||||
round_trip_with(
|
||||
&Indentation::default(),
|
||||
Quote::Single,
|
||||
LineEnding::default(),
|
||||
r#""hello""#
|
||||
),
|
||||
r"'hello'"
|
||||
);
|
||||
assert_eq!(
|
||||
round_trip_with(
|
||||
&Indentation::default(),
|
||||
Quote::Double,
|
||||
LineEnding::default(),
|
||||
r"'hello'"
|
||||
),
|
||||
r#""hello""#
|
||||
);
|
||||
assert_eq!(
|
||||
round_trip_with(
|
||||
&Indentation::default(),
|
||||
Quote::Single,
|
||||
LineEnding::default(),
|
||||
r"'hello'"
|
||||
),
|
||||
r"'hello'"
|
||||
$end,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// setting Generator::quote works for bytestrings
|
||||
round_trip_with!(Quote::Double, r#"b"hello""#, r#"b"hello""#);
|
||||
round_trip_with!(Quote::Single, r#"b"hello""#, r"b'hello'");
|
||||
round_trip_with!(Quote::Double, r"b'hello'", r#"b"hello""#);
|
||||
round_trip_with!(Quote::Single, r"b'hello'", r"b'hello'");
|
||||
|
||||
// and for f-strings
|
||||
round_trip_with!(Quote::Double, r#"f"hello""#, r#"f"hello""#);
|
||||
round_trip_with!(Quote::Single, r#"f"hello""#, r"f'hello'");
|
||||
round_trip_with!(Quote::Double, r"f'hello'", r#"f"hello""#);
|
||||
round_trip_with!(Quote::Single, r"f'hello'", r"f'hello'");
|
||||
|
||||
// but not for string literals, where the `Quote` is taken directly from their flags
|
||||
round_trip_with!(Quote::Double, r#""hello""#, r#""hello""#);
|
||||
round_trip_with!(Quote::Single, r#""hello""#, r#""hello""#); // no effect
|
||||
round_trip_with!(Quote::Double, r"'hello'", r#"'hello'"#); // no effect
|
||||
round_trip_with!(Quote::Single, r"'hello'", r"'hello'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -4,12 +4,12 @@ use {
|
|||
regex::Regex,
|
||||
};
|
||||
|
||||
use ruff_python_ast::visitor::transformer;
|
||||
use ruff_python_ast::visitor::transformer::Transformer;
|
||||
use ruff_python_ast::{
|
||||
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};
|
||||
|
||||
/// 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 {
|
||||
value: string.value.to_str().to_string().into_boxed_str(),
|
||||
range: string.range,
|
||||
flags: StringLiteralFlags::default(),
|
||||
flags: StringLiteralFlags::empty(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ pub fn parse_parenthesized_expression_range(
|
|||
///
|
||||
/// let string = StringLiteral {
|
||||
/// value: "'''\n int | str'''".to_string().into_boxed_str(),
|
||||
/// flags: StringLiteralFlags::default(),
|
||||
/// flags: StringLiteralFlags::empty(),
|
||||
/// range: TextRange::new(TextSize::new(0), TextSize::new(16)),
|
||||
/// };
|
||||
/// let parsed = parse_string_annotation("'''\n int | str'''", &string);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue