From 05e0a1a8160189aa8d1c433f0ef4f016b7b91def Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Wed, 30 Oct 2024 20:37:05 +0100 Subject: [PATCH 1/7] Implementation for RUF035 split-of-static-string --- .../resources/test/fixtures/ruff/RUF035.py | 56 +++ .../src/checkers/ast/analyze/expression.rs | 12 + crates/ruff_linter/src/codes.rs | 1 + crates/ruff_linter/src/rules/ruff/mod.rs | 1 + .../ruff_linter/src/rules/ruff/rules/mod.rs | 3 + .../ruff/rules/split_of_static_string.rs | 166 +++++++++ ..._rules__ruff__tests__RUF035_RUF035.py.snap | 346 ++++++++++++++++++ ruff.schema.json | 1 + 8 files changed, 586 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py create mode 100644 crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs create mode 100644 crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py new file mode 100644 index 0000000000000..db361640811e6 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py @@ -0,0 +1,56 @@ +# setup +sep = "," +no_sep = None + +# positives +""" + itemA + itemB + itemC +""".split() + +"a,b,c,d".split(",") +"a,b,c,d".split(None) +"a,b,c,d".split(",", 1) +"a,b,c,d".split(None, 1) +"a,b,c,d".split(sep=",") +"a,b,c,d".split(sep=None) +"a,b,c,d".split(sep=",", maxsplit=1) +"a,b,c,d".split(sep=None, maxsplit=1) +"a,b,c,d".split(maxsplit=1, sep=",") +"a,b,c,d".split(maxsplit=1, sep=None) +"a,b,c,d".split(",", maxsplit=1) +"a,b,c,d".split(None, maxsplit=1) +"a,b,c,d".split(maxsplit=1) +"a,b,c,d".split(maxsplit=1.0) +"a,b,c,d".split(maxsplit=1) +"a,b,c,d".split(maxsplit=0) +"VERB AUX PRON ADP DET".split(" ") +' 1 2 3 '.split() +'1<>2<>3<4'.split('<>') + +# negatives + +# test +"a,b,c,d".split(maxsplit="hello") + +# variable names not implemented +"a,b,c,d".split(sep) +"a,b,c,d".split(no_sep) +for n in range(3): + "a,b,c,d".split(",", maxsplit=n) + +# f-strings not yet implemented +world = "world" +_ = f"{world}_hello_world".split("_") + +hello = "hello_world" +_ = f"{hello}_world".split("_") + +# split on bytes not yet implemented, much less frequent +b"TesT.WwW.ExamplE.CoM".split(b".") + +# str.splitlines not yet implemented +"hello\nworld".splitlines() +"hello\nworld".splitlines(keepends=True) +"hello\nworld".splitlines(keepends=False) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 99deb3b994998..1a2af6713c5ab 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -384,6 +384,8 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { Rule::StaticJoinToFString, // refurb Rule::HashlibDigestHex, + // ruff + Rule::SplitOfStaticString, ]) { if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { let attr = attr.as_str(); @@ -401,6 +403,16 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { string_value.to_str(), ); } + } else if attr == "split" || attr == "rsplit" { + // "...".split(...) call + if checker.enabled(Rule::SplitOfStaticString) { + ruff::rules::split_of_static_string( + checker, + attr, + call, + string_value.to_str(), + ); + } } else if attr == "format" { // "...".format(...) call let location = expr.range(); diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index caa4af3312fcc..5789696b1654f 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -963,6 +963,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Ruff, "032") => (RuleGroup::Preview, rules::ruff::rules::DecimalFromFloatLiteral), (Ruff, "033") => (RuleGroup::Preview, rules::ruff::rules::PostInitDefault), (Ruff, "034") => (RuleGroup::Preview, rules::ruff::rules::UselessIfElse), + (Ruff, "035") => (RuleGroup::Preview, rules::ruff::rules::SplitOfStaticString), (Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA), (Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA), diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 84b7fd0d8ff7d..77241802c8cd3 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -61,6 +61,7 @@ mod tests { #[test_case(Rule::UselessIfElse, Path::new("RUF034.py"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101.py"))] #[test_case(Rule::PostInitDefault, Path::new("RUF033.py"))] + #[test_case(Rule::SplitOfStaticString, Path::new("RUF035.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/ruff/rules/mod.rs b/crates/ruff_linter/src/rules/ruff/rules/mod.rs index 49b40b0b7900d..b5466c456070f 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/mod.rs @@ -79,3 +79,6 @@ pub(crate) enum Context { pub(crate) use post_init_default::*; mod post_init_default; +pub(crate) use split_of_static_string::*; + +mod split_of_static_string; diff --git a/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs b/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs new file mode 100644 index 0000000000000..d1d4a9be0c0eb --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs @@ -0,0 +1,166 @@ +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{ + Expr, ExprCall, ExprContext, ExprList, ExprStringLiteral, StringLiteral, StringLiteralFlags, + StringLiteralValue, +}; +use ruff_text_size::{Ranged, TextRange}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for str.split calls that can be replaced with a `list` literal. +/// +/// ## Why is this bad? +/// List literals are more readable and do not require the overhead of calling `str.split`. +/// +/// ## Example +/// ```python +/// "a,b,c,d".split(",") +/// ``` +/// +/// Use instead: +/// ```python +/// ["a", "b", "c", "d"] +/// ``` +/// +/// ## References +/// +/// - [Python documentation: `str.split`](https://docs.python.org/3/library/stdtypes.html#str.split) +/// +/// ``` +#[violation] +pub struct SplitOfStaticString; + +impl Violation for SplitOfStaticString { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + + #[derive_message_formats] + fn message(&self) -> String { + format!("Consider using a list instead of string split") + } + + fn fix_title(&self) -> Option { + Some(format!("Replace string split with list literal")) + } +} + +fn construct_replacement(list_items: &[&str]) -> Expr { + Expr::List(ExprList { + elts: list_items + .iter() + .map(|list_item| { + Expr::StringLiteral(ExprStringLiteral { + value: StringLiteralValue::single(StringLiteral { + value: (*list_item).to_string().into_boxed_str(), + range: TextRange::default(), + flags: StringLiteralFlags::default(), + }), + range: TextRange::default(), + }) + }) + .collect(), + ctx: ExprContext::Load, + range: TextRange::default(), + }) +} + +fn split_default(str_value: &str, max_split: usize) -> Option { + // 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 + // > no empty strings at the start or end if the string has leading or trailing whitespace. + // > Consequently, splitting an empty string or a string consisting of just whitespace with + // > a None separator returns []. + // https://docs.python.org/3/library/stdtypes.html#str.split + if max_split == 0 { + let list_items: Vec<&str> = str_value.split_whitespace().collect(); + Some(construct_replacement(&list_items)) + } else { + // Autofix for maxsplit without separator not yet implemented + None + } +} + +fn split_sep(str_value: &str, sep_value: &str, max_split: usize, direction_left: bool) -> Expr { + let list_items: Vec<&str> = if direction_left && max_split > 0 { + str_value.splitn(max_split + 1, sep_value).collect() + } else if !direction_left && max_split > 0 { + str_value.rsplitn(max_split + 1, sep_value).collect() + } else if direction_left && max_split == 0 { + str_value.split(sep_value).collect() + } else { + str_value.rsplit(sep_value).collect() + }; + construct_replacement(&list_items) +} + +/// RUF035 +pub(crate) fn split_of_static_string( + checker: &mut Checker, + attr: &str, + call: &ExprCall, + str_value: &str, +) { + let ExprCall { arguments, .. } = call; + + let sep_arg = arguments.find_argument("sep", 0); + let maxsplit_arg = arguments.find_argument("maxsplit", 1); + + // `split` vs `rsplit` + let direction_left = attr == "split"; + + let maxsplit_value = if let Some(maxsplit) = maxsplit_arg { + match maxsplit { + Expr::NumberLiteral(maxsplit_val) => { + if let Some(int_value) = maxsplit_val.value.as_int() { + if let Some(usize_value) = int_value.as_usize() { + usize_value + } else { + return; + } + } else { + return; + } + } + // Ignore when `maxsplit` is not a numeric value + _ => { + return; + } + } + } else { + 0 + }; + + let split_replacement = if let Some(sep) = sep_arg { + match sep { + Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value), + Expr::StringLiteral(sep_value) => { + let sep_value_str = sep_value.value.to_str(); + Some(split_sep( + str_value, + sep_value_str, + maxsplit_value, + direction_left, + )) + } + // Ignore names until type inference is available + _ => { + return; + } + } + } else { + split_default(str_value, maxsplit_value) + }; + + let mut diagnostic = Diagnostic::new(SplitOfStaticString, call.range()); + if let Some(ref replacement_expr) = split_replacement { + // Construct replacement list + let replacement = checker.generator().expr(replacement_expr); + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( + replacement, + call.range(), + ))); + } + checker.diagnostics.push(diagnostic); +} diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap new file mode 100644 index 0000000000000..f898dbcd2395a --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap @@ -0,0 +1,346 @@ +--- +source: crates/ruff_linter/src/rules/ruff/mod.rs +--- +RUF035.py:6:1: RUF035 [*] Consider using a list instead of string split + | + 5 | # positives + 6 | / """ + 7 | | itemA + 8 | | itemB + 9 | | itemC +10 | | """.split() + | |___________^ RUF035 +11 | +12 | "a,b,c,d".split(",") + | + = help: Replace string split with list literal + +ℹ Unsafe fix +3 3 | no_sep = None +4 4 | +5 5 | # positives +6 |-""" +7 |- itemA +8 |- itemB +9 |- itemC +10 |-""".split() + 6 |+["itemA", "itemB", "itemC"] +11 7 | +12 8 | "a,b,c,d".split(",") +13 9 | "a,b,c,d".split(None) + +RUF035.py:12:1: RUF035 [*] Consider using a list instead of string split + | +10 | """.split() +11 | +12 | "a,b,c,d".split(",") + | ^^^^^^^^^^^^^^^^^^^^ RUF035 +13 | "a,b,c,d".split(None) +14 | "a,b,c,d".split(",", 1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +9 9 | itemC +10 10 | """.split() +11 11 | +12 |-"a,b,c,d".split(",") + 12 |+["a", "b", "c", "d"] +13 13 | "a,b,c,d".split(None) +14 14 | "a,b,c,d".split(",", 1) +15 15 | "a,b,c,d".split(None, 1) + +RUF035.py:13:1: RUF035 [*] Consider using a list instead of string split + | +12 | "a,b,c,d".split(",") +13 | "a,b,c,d".split(None) + | ^^^^^^^^^^^^^^^^^^^^^ RUF035 +14 | "a,b,c,d".split(",", 1) +15 | "a,b,c,d".split(None, 1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +10 10 | """.split() +11 11 | +12 12 | "a,b,c,d".split(",") +13 |-"a,b,c,d".split(None) + 13 |+["a,b,c,d"] +14 14 | "a,b,c,d".split(",", 1) +15 15 | "a,b,c,d".split(None, 1) +16 16 | "a,b,c,d".split(sep=",") + +RUF035.py:14:1: RUF035 [*] Consider using a list instead of string split + | +12 | "a,b,c,d".split(",") +13 | "a,b,c,d".split(None) +14 | "a,b,c,d".split(",", 1) + | ^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +15 | "a,b,c,d".split(None, 1) +16 | "a,b,c,d".split(sep=",") + | + = help: Replace string split with list literal + +ℹ Unsafe fix +11 11 | +12 12 | "a,b,c,d".split(",") +13 13 | "a,b,c,d".split(None) +14 |-"a,b,c,d".split(",", 1) + 14 |+["a", "b,c,d"] +15 15 | "a,b,c,d".split(None, 1) +16 16 | "a,b,c,d".split(sep=",") +17 17 | "a,b,c,d".split(sep=None) + +RUF035.py:15:1: RUF035 Consider using a list instead of string split + | +13 | "a,b,c,d".split(None) +14 | "a,b,c,d".split(",", 1) +15 | "a,b,c,d".split(None, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +16 | "a,b,c,d".split(sep=",") +17 | "a,b,c,d".split(sep=None) + | + = help: Replace string split with list literal + +RUF035.py:16:1: RUF035 [*] Consider using a list instead of string split + | +14 | "a,b,c,d".split(",", 1) +15 | "a,b,c,d".split(None, 1) +16 | "a,b,c,d".split(sep=",") + | ^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +17 | "a,b,c,d".split(sep=None) +18 | "a,b,c,d".split(sep=",", maxsplit=1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +13 13 | "a,b,c,d".split(None) +14 14 | "a,b,c,d".split(",", 1) +15 15 | "a,b,c,d".split(None, 1) +16 |-"a,b,c,d".split(sep=",") + 16 |+["a", "b", "c", "d"] +17 17 | "a,b,c,d".split(sep=None) +18 18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 19 | "a,b,c,d".split(sep=None, maxsplit=1) + +RUF035.py:17:1: RUF035 [*] Consider using a list instead of string split + | +15 | "a,b,c,d".split(None, 1) +16 | "a,b,c,d".split(sep=",") +17 | "a,b,c,d".split(sep=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 | "a,b,c,d".split(sep=None, maxsplit=1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +14 14 | "a,b,c,d".split(",", 1) +15 15 | "a,b,c,d".split(None, 1) +16 16 | "a,b,c,d".split(sep=",") +17 |-"a,b,c,d".split(sep=None) + 17 |+["a,b,c,d"] +18 18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 20 | "a,b,c,d".split(maxsplit=1, sep=",") + +RUF035.py:18:1: RUF035 [*] Consider using a list instead of string split + | +16 | "a,b,c,d".split(sep=",") +17 | "a,b,c,d".split(sep=None) +18 | "a,b,c,d".split(sep=",", maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 | "a,b,c,d".split(maxsplit=1, sep=",") + | + = help: Replace string split with list literal + +ℹ Unsafe fix +15 15 | "a,b,c,d".split(None, 1) +16 16 | "a,b,c,d".split(sep=",") +17 17 | "a,b,c,d".split(sep=None) +18 |-"a,b,c,d".split(sep=",", maxsplit=1) + 18 |+["a", "b,c,d"] +19 19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 20 | "a,b,c,d".split(maxsplit=1, sep=",") +21 21 | "a,b,c,d".split(maxsplit=1, sep=None) + +RUF035.py:19:1: RUF035 Consider using a list instead of string split + | +17 | "a,b,c,d".split(sep=None) +18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 | "a,b,c,d".split(sep=None, maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +20 | "a,b,c,d".split(maxsplit=1, sep=",") +21 | "a,b,c,d".split(maxsplit=1, sep=None) + | + = help: Replace string split with list literal + +RUF035.py:20:1: RUF035 [*] Consider using a list instead of string split + | +18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 | "a,b,c,d".split(maxsplit=1, sep=",") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +21 | "a,b,c,d".split(maxsplit=1, sep=None) +22 | "a,b,c,d".split(",", maxsplit=1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +17 17 | "a,b,c,d".split(sep=None) +18 18 | "a,b,c,d".split(sep=",", maxsplit=1) +19 19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 |-"a,b,c,d".split(maxsplit=1, sep=",") + 20 |+["a", "b,c,d"] +21 21 | "a,b,c,d".split(maxsplit=1, sep=None) +22 22 | "a,b,c,d".split(",", maxsplit=1) +23 23 | "a,b,c,d".split(None, maxsplit=1) + +RUF035.py:21:1: RUF035 Consider using a list instead of string split + | +19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 | "a,b,c,d".split(maxsplit=1, sep=",") +21 | "a,b,c,d".split(maxsplit=1, sep=None) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +22 | "a,b,c,d".split(",", maxsplit=1) +23 | "a,b,c,d".split(None, maxsplit=1) + | + = help: Replace string split with list literal + +RUF035.py:22:1: RUF035 [*] Consider using a list instead of string split + | +20 | "a,b,c,d".split(maxsplit=1, sep=",") +21 | "a,b,c,d".split(maxsplit=1, sep=None) +22 | "a,b,c,d".split(",", maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +23 | "a,b,c,d".split(None, maxsplit=1) +24 | "a,b,c,d".split(maxsplit=1) + | + = help: Replace string split with list literal + +ℹ Unsafe fix +19 19 | "a,b,c,d".split(sep=None, maxsplit=1) +20 20 | "a,b,c,d".split(maxsplit=1, sep=",") +21 21 | "a,b,c,d".split(maxsplit=1, sep=None) +22 |-"a,b,c,d".split(",", maxsplit=1) + 22 |+["a", "b,c,d"] +23 23 | "a,b,c,d".split(None, maxsplit=1) +24 24 | "a,b,c,d".split(maxsplit=1) +25 25 | "a,b,c,d".split(maxsplit=1.0) + +RUF035.py:23:1: RUF035 Consider using a list instead of string split + | +21 | "a,b,c,d".split(maxsplit=1, sep=None) +22 | "a,b,c,d".split(",", maxsplit=1) +23 | "a,b,c,d".split(None, maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +24 | "a,b,c,d".split(maxsplit=1) +25 | "a,b,c,d".split(maxsplit=1.0) + | + = help: Replace string split with list literal + +RUF035.py:24:1: RUF035 Consider using a list instead of string split + | +22 | "a,b,c,d".split(",", maxsplit=1) +23 | "a,b,c,d".split(None, maxsplit=1) +24 | "a,b,c,d".split(maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +25 | "a,b,c,d".split(maxsplit=1.0) +26 | "a,b,c,d".split(maxsplit=1) + | + = help: Replace string split with list literal + +RUF035.py:26:1: RUF035 Consider using a list instead of string split + | +24 | "a,b,c,d".split(maxsplit=1) +25 | "a,b,c,d".split(maxsplit=1.0) +26 | "a,b,c,d".split(maxsplit=1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +27 | "a,b,c,d".split(maxsplit=0) +28 | "VERB AUX PRON ADP DET".split(" ") + | + = help: Replace string split with list literal + +RUF035.py:27:1: RUF035 [*] Consider using a list instead of string split + | +25 | "a,b,c,d".split(maxsplit=1.0) +26 | "a,b,c,d".split(maxsplit=1) +27 | "a,b,c,d".split(maxsplit=0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +28 | "VERB AUX PRON ADP DET".split(" ") +29 | ' 1 2 3 '.split() + | + = help: Replace string split with list literal + +ℹ Unsafe fix +24 24 | "a,b,c,d".split(maxsplit=1) +25 25 | "a,b,c,d".split(maxsplit=1.0) +26 26 | "a,b,c,d".split(maxsplit=1) +27 |-"a,b,c,d".split(maxsplit=0) + 27 |+["a,b,c,d"] +28 28 | "VERB AUX PRON ADP DET".split(" ") +29 29 | ' 1 2 3 '.split() +30 30 | '1<>2<>3<4'.split('<>') + +RUF035.py:28:1: RUF035 [*] Consider using a list instead of string split + | +26 | "a,b,c,d".split(maxsplit=1) +27 | "a,b,c,d".split(maxsplit=0) +28 | "VERB AUX PRON ADP DET".split(" ") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +29 | ' 1 2 3 '.split() +30 | '1<>2<>3<4'.split('<>') + | + = help: Replace string split with list literal + +ℹ Unsafe fix +25 25 | "a,b,c,d".split(maxsplit=1.0) +26 26 | "a,b,c,d".split(maxsplit=1) +27 27 | "a,b,c,d".split(maxsplit=0) +28 |-"VERB AUX PRON ADP DET".split(" ") + 28 |+["VERB", "AUX", "PRON", "ADP", "DET"] +29 29 | ' 1 2 3 '.split() +30 30 | '1<>2<>3<4'.split('<>') +31 31 | + +RUF035.py:29:1: RUF035 [*] Consider using a list instead of string split + | +27 | "a,b,c,d".split(maxsplit=0) +28 | "VERB AUX PRON ADP DET".split(" ") +29 | ' 1 2 3 '.split() + | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +30 | '1<>2<>3<4'.split('<>') + | + = help: Replace string split with list literal + +ℹ Unsafe fix +26 26 | "a,b,c,d".split(maxsplit=1) +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"] +30 30 | '1<>2<>3<4'.split('<>') +31 31 | +32 32 | # negatives + +RUF035.py:30:1: RUF035 [*] Consider using a list instead of string split + | +28 | "VERB AUX PRON ADP DET".split(" ") +29 | ' 1 2 3 '.split() +30 | '1<>2<>3<4'.split('<>') + | ^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +31 | +32 | # negatives + | + = help: Replace string split with list literal + +ℹ Unsafe fix +27 27 | "a,b,c,d".split(maxsplit=0) +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"] +31 31 | +32 32 | # negatives +33 33 | diff --git a/ruff.schema.json b/ruff.schema.json index 7412f47258dda..345fbefa3b523 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3815,6 +3815,7 @@ "RUF032", "RUF033", "RUF034", + "RUF035", "RUF1", "RUF10", "RUF100", From 135944192222d6b0685fa1a8554a2a8cea8c590e Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Thu, 31 Oct 2024 13:36:52 +0100 Subject: [PATCH 2/7] Extending test cases and handling negative maxsize --- .../resources/test/fixtures/ruff/RUF035.py | 40 +- .../src/checkers/ast/analyze/expression.rs | 2 +- .../ruff/rules/split_of_static_string.rs | 29 +- ..._rules__ruff__tests__RUF035_RUF035.py.snap | 501 ++++++++++++++++-- 4 files changed, 518 insertions(+), 54 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py index db361640811e6..696da476bbc45 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py @@ -29,10 +29,48 @@ ' 1 2 3 '.split() '1<>2<>3<4'.split('<>') +" a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] +"".split() # [] +""" +""".split() # [] +" ".split() # [] +"/abc/".split() # ['/abc/'] +("a,b,c" +# comment +.split() +) # ['a,b,c'] +("a,b,c" +# comment +.split(",") +) # ['a', 'b', 'c'] +("a," +# comment +"b," +"c" +.split(",") +) # ['a', 'b', 'c'] + +"hello "\ + "world".split() +# ['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'] + # negatives -# test +# invalid values should not cause panic "a,b,c,d".split(maxsplit="hello") +"a,b,c,d".split(maxsplit=-"hello") # variable names not implemented "a,b,c,d".split(sep) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 1a2af6713c5ab..ebee47cd67359 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -403,7 +403,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { string_value.to_str(), ); } - } else if attr == "split" || attr == "rsplit" { + } else if matches!(attr, "split" | "rsplit") { // "...".split(...) call if checker.enabled(Rule::SplitOfStaticString) { ruff::rules::split_of_static_string( diff --git a/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs b/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs index d1d4a9be0c0eb..5619908c2138a 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs @@ -1,8 +1,8 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{ - Expr, ExprCall, ExprContext, ExprList, ExprStringLiteral, StringLiteral, StringLiteralFlags, - StringLiteralValue, + Expr, ExprCall, ExprContext, ExprList, ExprStringLiteral, ExprUnaryOp, StringLiteral, + StringLiteralFlags, StringLiteralValue, UnaryOp, }; use ruff_text_size::{Ranged, TextRange}; @@ -37,11 +37,11 @@ impl Violation for SplitOfStaticString { #[derive_message_formats] fn message(&self) -> String { - format!("Consider using a list instead of string split") + format!("Consider using a list instead of `str.split`") } fn fix_title(&self) -> Option { - Some(format!("Replace string split with list literal")) + Some(format!("Replace `str.split` with list literal")) } } @@ -78,6 +78,8 @@ fn split_default(str_value: &str, max_split: usize) -> Option { Some(construct_replacement(&list_items)) } else { // Autofix for maxsplit without separator not yet implemented + // split_whitespace().remainder() is still experimental: + // https://doc.rust-lang.org/std/str/struct.SplitWhitespace.html#method.remainder None } } @@ -112,13 +114,19 @@ pub(crate) fn split_of_static_string( let maxsplit_value = if let Some(maxsplit) = maxsplit_arg { match maxsplit { + // Python allows maxsplit to be set to -1 + Expr::UnaryOp(ExprUnaryOp { + op: UnaryOp::USub, + operand, + .. + }) if matches!(**operand, Expr::NumberLiteral { .. }) => 0, Expr::NumberLiteral(maxsplit_val) => { - if let Some(int_value) = maxsplit_val.value.as_int() { - if let Some(usize_value) = int_value.as_usize() { - usize_value - } else { - return; - } + if let Some(value) = maxsplit_val + .value + .as_int() + .and_then(ruff_python_ast::Int::as_usize) + { + value } else { return; } @@ -157,6 +165,7 @@ pub(crate) fn split_of_static_string( if let Some(ref replacement_expr) = split_replacement { // Construct replacement list let replacement = checker.generator().expr(replacement_expr); + // Unsafe because the fix does not preserve comments within implicit string concatenation diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( replacement, call.range(), diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap index f898dbcd2395a..40d9681464691 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/ruff/mod.rs --- -RUF035.py:6:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:6:1: RUF035 [*] Consider using a list instead of `str.split` | 5 | # positives 6 | / """ @@ -13,7 +13,7 @@ RUF035.py:6:1: RUF035 [*] Consider using a list instead of string split 11 | 12 | "a,b,c,d".split(",") | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 3 3 | no_sep = None @@ -29,7 +29,7 @@ RUF035.py:6:1: RUF035 [*] Consider using a list instead of string split 12 8 | "a,b,c,d".split(",") 13 9 | "a,b,c,d".split(None) -RUF035.py:12:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:12:1: RUF035 [*] Consider using a list instead of `str.split` | 10 | """.split() 11 | @@ -38,7 +38,7 @@ RUF035.py:12:1: RUF035 [*] Consider using a list instead of string split 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 9 9 | itemC @@ -50,7 +50,7 @@ RUF035.py:12:1: RUF035 [*] Consider using a list instead of string split 14 14 | "a,b,c,d".split(",", 1) 15 15 | "a,b,c,d".split(None, 1) -RUF035.py:13:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:13:1: RUF035 [*] Consider using a list instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) @@ -58,7 +58,7 @@ RUF035.py:13:1: RUF035 [*] Consider using a list instead of string split 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 10 10 | """.split() @@ -70,7 +70,7 @@ RUF035.py:13:1: RUF035 [*] Consider using a list instead of string split 15 15 | "a,b,c,d".split(None, 1) 16 16 | "a,b,c,d".split(sep=",") -RUF035.py:14:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:14:1: RUF035 [*] Consider using a list instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) @@ -79,7 +79,7 @@ RUF035.py:14:1: RUF035 [*] Consider using a list instead of string split 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 11 11 | @@ -91,7 +91,7 @@ RUF035.py:14:1: RUF035 [*] Consider using a list instead of string split 16 16 | "a,b,c,d".split(sep=",") 17 17 | "a,b,c,d".split(sep=None) -RUF035.py:15:1: RUF035 Consider using a list instead of string split +RUF035.py:15:1: RUF035 Consider using a list instead of `str.split` | 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) @@ -100,9 +100,9 @@ RUF035.py:15:1: RUF035 Consider using a list instead of string split 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:16:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:16:1: RUF035 [*] Consider using a list instead of `str.split` | 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) @@ -111,7 +111,7 @@ RUF035.py:16:1: RUF035 [*] Consider using a list instead of string split 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 13 13 | "a,b,c,d".split(None) @@ -123,7 +123,7 @@ RUF035.py:16:1: RUF035 [*] Consider using a list instead of string split 18 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) -RUF035.py:17:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:17:1: RUF035 [*] Consider using a list instead of `str.split` | 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") @@ -132,7 +132,7 @@ RUF035.py:17:1: RUF035 [*] Consider using a list instead of string split 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 14 14 | "a,b,c,d".split(",", 1) @@ -144,7 +144,7 @@ RUF035.py:17:1: RUF035 [*] Consider using a list instead of string split 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") -RUF035.py:18:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:18:1: RUF035 [*] Consider using a list instead of `str.split` | 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) @@ -153,7 +153,7 @@ RUF035.py:18:1: RUF035 [*] Consider using a list instead of string split 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 15 15 | "a,b,c,d".split(None, 1) @@ -165,7 +165,7 @@ RUF035.py:18:1: RUF035 [*] Consider using a list instead of string split 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 21 | "a,b,c,d".split(maxsplit=1, sep=None) -RUF035.py:19:1: RUF035 Consider using a list instead of string split +RUF035.py:19:1: RUF035 Consider using a list instead of `str.split` | 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) @@ -174,9 +174,9 @@ RUF035.py:19:1: RUF035 Consider using a list instead of string split 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:20:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:20:1: RUF035 [*] Consider using a list instead of `str.split` | 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) @@ -185,7 +185,7 @@ RUF035.py:20:1: RUF035 [*] Consider using a list instead of string split 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 17 17 | "a,b,c,d".split(sep=None) @@ -197,7 +197,7 @@ RUF035.py:20:1: RUF035 [*] Consider using a list instead of string split 22 22 | "a,b,c,d".split(",", maxsplit=1) 23 23 | "a,b,c,d".split(None, maxsplit=1) -RUF035.py:21:1: RUF035 Consider using a list instead of string split +RUF035.py:21:1: RUF035 Consider using a list instead of `str.split` | 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") @@ -206,9 +206,9 @@ RUF035.py:21:1: RUF035 Consider using a list instead of string split 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:22:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:22:1: RUF035 [*] Consider using a list instead of `str.split` | 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) @@ -217,7 +217,7 @@ RUF035.py:22:1: RUF035 [*] Consider using a list instead of string split 23 | "a,b,c,d".split(None, maxsplit=1) 24 | "a,b,c,d".split(maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) @@ -229,7 +229,7 @@ RUF035.py:22:1: RUF035 [*] Consider using a list instead of string split 24 24 | "a,b,c,d".split(maxsplit=1) 25 25 | "a,b,c,d".split(maxsplit=1.0) -RUF035.py:23:1: RUF035 Consider using a list instead of string split +RUF035.py:23:1: RUF035 Consider using a list instead of `str.split` | 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) @@ -238,9 +238,9 @@ RUF035.py:23:1: RUF035 Consider using a list instead of string split 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:24:1: RUF035 Consider using a list instead of string split +RUF035.py:24:1: RUF035 Consider using a list instead of `str.split` | 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) @@ -249,9 +249,9 @@ RUF035.py:24:1: RUF035 Consider using a list instead of string split 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:26:1: RUF035 Consider using a list instead of string split +RUF035.py:26:1: RUF035 Consider using a list instead of `str.split` | 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) @@ -260,9 +260,9 @@ RUF035.py:26:1: RUF035 Consider using a list instead of string split 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal -RUF035.py:27:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:27:1: RUF035 [*] Consider using a list instead of `str.split` | 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) @@ -271,7 +271,7 @@ RUF035.py:27:1: RUF035 [*] Consider using a list instead of string split 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 24 24 | "a,b,c,d".split(maxsplit=1) @@ -283,7 +283,7 @@ RUF035.py:27:1: RUF035 [*] Consider using a list instead of string split 29 29 | ' 1 2 3 '.split() 30 30 | '1<>2<>3<4'.split('<>') -RUF035.py:28:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:28:1: RUF035 [*] Consider using a list instead of `str.split` | 26 | "a,b,c,d".split(maxsplit=1) 27 | "a,b,c,d".split(maxsplit=0) @@ -292,7 +292,7 @@ RUF035.py:28:1: RUF035 [*] Consider using a list instead of string split 29 | ' 1 2 3 '.split() 30 | '1<>2<>3<4'.split('<>') | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 25 25 | "a,b,c,d".split(maxsplit=1.0) @@ -304,7 +304,7 @@ RUF035.py:28:1: RUF035 [*] Consider using a list instead of string split 30 30 | '1<>2<>3<4'.split('<>') 31 31 | -RUF035.py:29:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:29:1: RUF035 [*] Consider using a list instead of `str.split` | 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") @@ -312,7 +312,7 @@ RUF035.py:29:1: RUF035 [*] Consider using a list instead of string split | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 30 | '1<>2<>3<4'.split('<>') | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 26 26 | "a,b,c,d".split(maxsplit=1) @@ -322,18 +322,18 @@ RUF035.py:29:1: RUF035 [*] Consider using a list instead of string split 29 |+["1", "2", "3"] 30 30 | '1<>2<>3<4'.split('<>') 31 31 | -32 32 | # negatives +32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] -RUF035.py:30:1: RUF035 [*] Consider using a list instead of string split +RUF035.py:30:1: RUF035 [*] Consider using a list instead of `str.split` | 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() 30 | '1<>2<>3<4'.split('<>') | ^^^^^^^^^^^^^^^^^^^^^^^ RUF035 31 | -32 | # negatives +32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] | - = help: Replace string split with list literal + = help: Replace `str.split` with list literal ℹ Unsafe fix 27 27 | "a,b,c,d".split(maxsplit=0) @@ -342,5 +342,422 @@ RUF035.py:30:1: RUF035 [*] Consider using a list instead of string split 30 |-'1<>2<>3<4'.split('<>') 30 |+["1", "2", "3<4"] 31 31 | -32 32 | # negatives -33 33 | +32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] +33 33 | "".split() # [] + +RUF035.py:32:1: RUF035 [*] Consider using a list instead of `str.split` + | +30 | '1<>2<>3<4'.split('<>') +31 | +32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 +33 | "".split() # [] +34 | """ + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +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 '] +33 33 | "".split() # [] +34 34 | """ +35 35 | """.split() # [] + +RUF035.py:33:1: RUF035 [*] Consider using a list instead of `str.split` + | +32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] +33 | "".split() # [] + | ^^^^^^^^^^ RUF035 +34 | """ +35 | """.split() # [] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +30 30 | '1<>2<>3<4'.split('<>') +31 31 | +32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] +33 |-"".split() # [] + 33 |+[] # [] +34 34 | """ +35 35 | """.split() # [] +36 36 | " ".split() # [] + +RUF035.py:34:1: RUF035 [*] Consider using a list instead of `str.split` + | +32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] +33 | "".split() # [] +34 | / """ +35 | | """.split() # [] + | |___________^ RUF035 +36 | " ".split() # [] +37 | "/abc/".split() # ['/abc/'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +31 31 | +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/'] +38 37 | ("a,b,c" + +RUF035.py:36:1: RUF035 [*] Consider using a list instead of `str.split` + | +34 | """ +35 | """.split() # [] +36 | " ".split() # [] + | ^^^^^^^^^^^^^^^^^ RUF035 +37 | "/abc/".split() # ['/abc/'] +38 | ("a,b,c" + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +33 33 | "".split() # [] +34 34 | """ +35 35 | """.split() # [] +36 |-" ".split() # [] + 36 |+[] # [] +37 37 | "/abc/".split() # ['/abc/'] +38 38 | ("a,b,c" +39 39 | # comment + +RUF035.py:37:1: RUF035 [*] Consider using a list instead of `str.split` + | +35 | """.split() # [] +36 | " ".split() # [] +37 | "/abc/".split() # ['/abc/'] + | ^^^^^^^^^^^^^^^ RUF035 +38 | ("a,b,c" +39 | # comment + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +34 34 | """ +35 35 | """.split() # [] +36 36 | " ".split() # [] +37 |-"/abc/".split() # ['/abc/'] + 37 |+["/abc/"] # ['/abc/'] +38 38 | ("a,b,c" +39 39 | # comment +40 40 | .split() + +RUF035.py:38:2: RUF035 [*] Consider using a list instead of `str.split` + | +36 | " ".split() # [] +37 | "/abc/".split() # ['/abc/'] +38 | ("a,b,c" + | __^ +39 | | # comment +40 | | .split() + | |________^ RUF035 +41 | ) # ['a,b,c'] +42 | ("a,b,c" + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +35 35 | """.split() # [] +36 36 | " ".split() # [] +37 37 | "/abc/".split() # ['/abc/'] +38 |-("a,b,c" +39 |-# comment +40 |-.split() + 38 |+(["a,b,c"] +41 39 | ) # ['a,b,c'] +42 40 | ("a,b,c" +43 41 | # comment + +RUF035.py:42:2: RUF035 [*] Consider using a list instead of `str.split` + | +40 | .split() +41 | ) # ['a,b,c'] +42 | ("a,b,c" + | __^ +43 | | # comment +44 | | .split(",") + | |___________^ RUF035 +45 | ) # ['a', 'b', 'c'] +46 | ("a," + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +39 39 | # comment +40 40 | .split() +41 41 | ) # ['a,b,c'] +42 |-("a,b,c" +43 |-# comment +44 |-.split(",") + 42 |+(["a", "b", "c"] +45 43 | ) # ['a', 'b', 'c'] +46 44 | ("a," +47 45 | # comment + +RUF035.py:46:2: RUF035 [*] Consider using a list instead of `str.split` + | +44 | .split(",") +45 | ) # ['a', 'b', 'c'] +46 | ("a," + | __^ +47 | | # comment +48 | | "b," +49 | | "c" +50 | | .split(",") + | |___________^ RUF035 +51 | ) # ['a', 'b', 'c'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +43 43 | # comment +44 44 | .split(",") +45 45 | ) # ['a', 'b', 'c'] +46 |-("a," +47 |-# comment +48 |-"b," +49 |-"c" +50 |-.split(",") + 46 |+(["a", "b", "c"] +51 47 | ) # ['a', 'b', 'c'] +52 48 | +53 49 | "hello "\ + +RUF035.py:53:1: RUF035 [*] Consider using a list instead of `str.split` + | +51 | ) # ['a', 'b', 'c'] +52 | +53 | / "hello "\ +54 | | "world".split() + | |___________________^ RUF035 +55 | # ['hello', 'world'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +50 50 | .split(",") +51 51 | ) # ['a', 'b', 'c'] +52 52 | +53 |-"hello "\ +54 |- "world".split() + 53 |+["hello", "world"] +55 54 | # ['hello', 'world'] +56 55 | +57 56 | # prefixes and isc + +RUF035.py:58:1: RUF035 [*] Consider using a list instead of `str.split` + | +57 | # prefixes and isc +58 | u"a b".split() # ['a', 'b'] + | ^^^^^^^^^^^^^^ RUF035 +59 | r"a \n b".split() # ['a', '\\n', 'b'] +60 | ("a " "b").split() # ['a', 'b'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +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'] + +RUF035.py:59:1: RUF035 [*] Consider using a list instead of `str.split` + | +57 | # prefixes and isc +58 | u"a b".split() # ['a', 'b'] +59 | r"a \n b".split() # ['a', '\\n', 'b'] + | ^^^^^^^^^^^^^^^^^ RUF035 +60 | ("a " "b").split() # ['a', 'b'] +61 | "a " "b".split() # ['a', 'b'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:60:1: RUF035 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^ RUF035 +61 | "a " "b".split() # ['a', 'b'] +62 | u"a " "b".split() # ['a', 'b'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:61:1: RUF035 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^ RUF035 +62 | u"a " "b".split() # ['a', 'b'] +63 | "a " u"b".split() # ['a', 'b'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:62:1: RUF035 [*] Consider using a list instead of `str.split` + | +60 | ("a " "b").split() # ['a', 'b'] +61 | "a " "b".split() # ['a', 'b'] +62 | u"a " "b".split() # ['a', 'b'] + | ^^^^^^^^^^^^^^^^^ RUF035 +63 | "a " u"b".split() # ['a', 'b'] +64 | u"a " r"\n".split() # ['a', '\\n'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:63:1: RUF035 [*] Consider using a list instead of `str.split` + | +61 | "a " "b".split() # ['a', 'b'] +62 | u"a " "b".split() # ['a', 'b'] +63 | "a " u"b".split() # ['a', 'b'] + | ^^^^^^^^^^^^^^^^^ RUF035 +64 | u"a " r"\n".split() # ['a', '\\n'] +65 | r"\n " u"\n".split() # ['\\n'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:64:1: RUF035 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^^ RUF035 +65 | r"\n " u"\n".split() # ['\\n'] +66 | r"\n " "\n".split() # ['\\n'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] + +RUF035.py:65:1: RUF035 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^^^ RUF035 +66 | r"\n " "\n".split() # ['\\n'] +67 | "a " r"\n".split() # ['a', '\\n'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] +68 68 | + +RUF035.py:66:1: RUF035 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^^ RUF035 +67 | "a " r"\n".split() # ['a', '\\n'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] +68 68 | +69 69 | # negatives + +RUF035.py:67:1: RUF035 [*] Consider using a list instead of `str.split` + | +65 | r"\n " u"\n".split() # ['\\n'] +66 | r"\n " "\n".split() # ['\\n'] +67 | "a " r"\n".split() # ['a', '\\n'] + | ^^^^^^^^^^^^^^^^^^ RUF035 +68 | +69 | # negatives + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] +68 68 | +69 69 | # negatives +70 70 | From 157cb88de58c9e635c275901f3b9e2dc1eb2ac05 Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Thu, 31 Oct 2024 13:57:39 +0100 Subject: [PATCH 3/7] Moving over --- .../RUF035.py => flake8_simplify/SIM905.py} | 0 .../src/checkers/ast/analyze/expression.rs | 4 +- crates/ruff_linter/src/codes.rs | 2 +- .../src/rules/flake8_simplify/mod.rs | 5 +- .../src/rules/flake8_simplify/rules/mod.rs | 2 + .../rules/split_of_static_string.rs | 0 ...e8_simplify__tests__SIM905_SIM905.py.snap} | 154 +++++++++--------- crates/ruff_linter/src/rules/ruff/mod.rs | 1 - .../ruff_linter/src/rules/ruff/rules/mod.rs | 8 +- ruff.schema.json | 3 +- 10 files changed, 89 insertions(+), 90 deletions(-) rename crates/ruff_linter/resources/test/fixtures/{ruff/RUF035.py => flake8_simplify/SIM905.py} (100%) rename crates/ruff_linter/src/rules/{ruff => flake8_simplify}/rules/split_of_static_string.rs (100%) rename crates/ruff_linter/src/rules/{ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap => flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap} (82%) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py similarity index 100% rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py rename to crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index ebee47cd67359..1ab6bab63ff2e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -384,7 +384,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { Rule::StaticJoinToFString, // refurb Rule::HashlibDigestHex, - // ruff + // flake8-simplify Rule::SplitOfStaticString, ]) { if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { @@ -406,7 +406,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { } else if matches!(attr, "split" | "rsplit") { // "...".split(...) call if checker.enabled(Rule::SplitOfStaticString) { - ruff::rules::split_of_static_string( + flake8_simplify::rules::split_of_static_string( checker, attr, call, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 5789696b1654f..10d05e445b56f 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -480,6 +480,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Simplify, "223") => (RuleGroup::Stable, rules::flake8_simplify::rules::ExprAndFalse), (Flake8Simplify, "300") => (RuleGroup::Stable, rules::flake8_simplify::rules::YodaConditions), (Flake8Simplify, "401") => (RuleGroup::Stable, rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet), + (Flake8Simplify, "905") => (RuleGroup::Preview, rules::flake8_simplify::rules::SplitOfStaticString), (Flake8Simplify, "910") => (RuleGroup::Stable, rules::flake8_simplify::rules::DictGetWithNoneDefault), (Flake8Simplify, "911") => (RuleGroup::Stable, rules::flake8_simplify::rules::ZipDictKeysAndValues), @@ -963,7 +964,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Ruff, "032") => (RuleGroup::Preview, rules::ruff::rules::DecimalFromFloatLiteral), (Ruff, "033") => (RuleGroup::Preview, rules::ruff::rules::PostInitDefault), (Ruff, "034") => (RuleGroup::Preview, rules::ruff::rules::UselessIfElse), - (Ruff, "035") => (RuleGroup::Preview, rules::ruff::rules::SplitOfStaticString), (Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA), (Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA), diff --git a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs index e2cf5dee0f9df..d98fe895fa5bc 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs @@ -29,7 +29,9 @@ mod tests { #[test_case(Rule::ReimplementedBuiltin, Path::new("SIM111.py"))] #[test_case(Rule::UncapitalizedEnvironmentVariables, Path::new("SIM112.py"))] #[test_case(Rule::EnumerateForLoop, Path::new("SIM113.py"))] + #[test_case(Rule::IfWithSameArms, Path::new("SIM114.py"))] #[test_case(Rule::OpenFileWithContextHandler, Path::new("SIM115.py"))] + #[test_case(Rule::IfElseBlockInsteadOfDictLookup, Path::new("SIM116.py"))] #[test_case(Rule::MultipleWithStatements, Path::new("SIM117.py"))] #[test_case(Rule::InDictKeys, Path::new("SIM118.py"))] #[test_case(Rule::NegateEqualOp, Path::new("SIM201.py"))] @@ -44,9 +46,8 @@ mod tests { #[test_case(Rule::ExprAndFalse, Path::new("SIM223.py"))] #[test_case(Rule::YodaConditions, Path::new("SIM300.py"))] #[test_case(Rule::IfElseBlockInsteadOfDictGet, Path::new("SIM401.py"))] + #[test_case(Rule::SplitOfStaticString, Path::new("SIM905.py"))] #[test_case(Rule::DictGetWithNoneDefault, Path::new("SIM910.py"))] - #[test_case(Rule::IfElseBlockInsteadOfDictLookup, Path::new("SIM116.py"))] - #[test_case(Rule::IfWithSameArms, Path::new("SIM114.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs index b2aa7d5259732..80a68d2bd0796 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs @@ -14,6 +14,7 @@ pub(crate) use needless_bool::*; pub(crate) use open_file_with_context_handler::*; pub(crate) use reimplemented_builtin::*; pub(crate) use return_in_try_except_finally::*; +pub(crate) use split_of_static_string::*; pub(crate) use suppressible_exception::*; pub(crate) use yoda_conditions::*; pub(crate) use zip_dict_keys_and_values::*; @@ -35,6 +36,7 @@ mod needless_bool; mod open_file_with_context_handler; mod reimplemented_builtin; mod return_in_try_except_finally; +mod split_of_static_string; mod suppressible_exception; mod yoda_conditions; mod zip_dict_keys_and_values; diff --git a/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_of_static_string.rs similarity index 100% rename from crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs rename to crates/ruff_linter/src/rules/flake8_simplify/rules/split_of_static_string.rs diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap similarity index 82% rename from crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap rename to crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap index 40d9681464691..1dcb37a136b75 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF035_RUF035.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap @@ -1,7 +1,7 @@ --- -source: crates/ruff_linter/src/rules/ruff/mod.rs +source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs --- -RUF035.py:6:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:6:1: SIM905 [*] Consider using a list instead of `str.split` | 5 | # positives 6 | / """ @@ -9,7 +9,7 @@ RUF035.py:6:1: RUF035 [*] Consider using a list instead of `str.split` 8 | | itemB 9 | | itemC 10 | | """.split() - | |___________^ RUF035 + | |___________^ SIM905 11 | 12 | "a,b,c,d".split(",") | @@ -29,12 +29,12 @@ RUF035.py:6:1: RUF035 [*] Consider using a list instead of `str.split` 12 8 | "a,b,c,d".split(",") 13 9 | "a,b,c,d".split(None) -RUF035.py:12:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:12:1: SIM905 [*] Consider using a list instead of `str.split` | 10 | """.split() 11 | 12 | "a,b,c,d".split(",") - | ^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^ SIM905 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) | @@ -50,11 +50,11 @@ RUF035.py:12:1: RUF035 [*] Consider using a list instead of `str.split` 14 14 | "a,b,c,d".split(",", 1) 15 15 | "a,b,c,d".split(None, 1) -RUF035.py:13:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:13:1: SIM905 [*] Consider using a list instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) - | ^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^ SIM905 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) | @@ -70,12 +70,12 @@ RUF035.py:13:1: RUF035 [*] Consider using a list instead of `str.split` 15 15 | "a,b,c,d".split(None, 1) 16 16 | "a,b,c,d".split(sep=",") -RUF035.py:14:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:14:1: SIM905 [*] Consider using a list instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) - | ^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^ SIM905 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") | @@ -91,23 +91,23 @@ RUF035.py:14:1: RUF035 [*] Consider using a list instead of `str.split` 16 16 | "a,b,c,d".split(sep=",") 17 17 | "a,b,c,d".split(sep=None) -RUF035.py:15:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:15:1: SIM905 Consider using a list instead of `str.split` | 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) | = help: Replace `str.split` with list literal -RUF035.py:16:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` | 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") - | ^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) | @@ -123,12 +123,12 @@ RUF035.py:16:1: RUF035 [*] Consider using a list instead of `str.split` 18 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) -RUF035.py:17:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:17:1: SIM905 [*] Consider using a list instead of `str.split` | 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) | @@ -144,12 +144,12 @@ RUF035.py:17:1: RUF035 [*] Consider using a list instead of `str.split` 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") -RUF035.py:18:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:18:1: SIM905 [*] Consider using a list instead of `str.split` | 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") | @@ -165,23 +165,23 @@ RUF035.py:18:1: RUF035 [*] Consider using a list instead of `str.split` 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 21 | "a,b,c,d".split(maxsplit=1, sep=None) -RUF035.py:19:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:19:1: SIM905 Consider using a list instead of `str.split` | 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) | = help: Replace `str.split` with list literal -RUF035.py:20:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` | 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) | @@ -197,23 +197,23 @@ RUF035.py:20:1: RUF035 [*] Consider using a list instead of `str.split` 22 22 | "a,b,c,d".split(",", maxsplit=1) 23 23 | "a,b,c,d".split(None, maxsplit=1) -RUF035.py:21:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:21:1: SIM905 Consider using a list instead of `str.split` | 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) | = help: Replace `str.split` with list literal -RUF035.py:22:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` | 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 23 | "a,b,c,d".split(None, maxsplit=1) 24 | "a,b,c,d".split(maxsplit=1) | @@ -229,45 +229,45 @@ RUF035.py:22:1: RUF035 [*] Consider using a list instead of `str.split` 24 24 | "a,b,c,d".split(maxsplit=1) 25 25 | "a,b,c,d".split(maxsplit=1.0) -RUF035.py:23:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:23:1: SIM905 Consider using a list instead of `str.split` | 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) | = help: Replace `str.split` with list literal -RUF035.py:24:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:24:1: SIM905 Consider using a list instead of `str.split` | 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) 24 | "a,b,c,d".split(maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) | = help: Replace `str.split` with list literal -RUF035.py:26:1: RUF035 Consider using a list instead of `str.split` +SIM905.py:26:1: SIM905 Consider using a list instead of `str.split` | 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") | = help: Replace `str.split` with list literal -RUF035.py:27:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` | 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) 27 | "a,b,c,d".split(maxsplit=0) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() | @@ -283,12 +283,12 @@ RUF035.py:27:1: RUF035 [*] Consider using a list instead of `str.split` 29 29 | ' 1 2 3 '.split() 30 30 | '1<>2<>3<4'.split('<>') -RUF035.py:28:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:28:1: SIM905 [*] Consider using a list instead of `str.split` | 26 | "a,b,c,d".split(maxsplit=1) 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 29 | ' 1 2 3 '.split() 30 | '1<>2<>3<4'.split('<>') | @@ -304,12 +304,12 @@ RUF035.py:28:1: RUF035 [*] Consider using a list instead of `str.split` 30 30 | '1<>2<>3<4'.split('<>') 31 31 | -RUF035.py:29:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:29:1: SIM905 [*] Consider using a list instead of `str.split` | 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() - | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 30 | '1<>2<>3<4'.split('<>') | = help: Replace `str.split` with list literal @@ -324,12 +324,12 @@ RUF035.py:29:1: RUF035 [*] Consider using a list instead of `str.split` 31 31 | 32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] -RUF035.py:30:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:30:1: SIM905 [*] Consider using a list instead of `str.split` | 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() 30 | '1<>2<>3<4'.split('<>') - | ^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^ SIM905 31 | 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] | @@ -345,12 +345,12 @@ RUF035.py:30:1: RUF035 [*] Consider using a list instead of `str.split` 32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] 33 33 | "".split() # [] -RUF035.py:32:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:32:1: SIM905 [*] Consider using a list instead of `str.split` | 30 | '1<>2<>3<4'.split('<>') 31 | 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 33 | "".split() # [] 34 | """ | @@ -366,11 +366,11 @@ RUF035.py:32:1: RUF035 [*] Consider using a list instead of `str.split` 34 34 | """ 35 35 | """.split() # [] -RUF035.py:33:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:33:1: SIM905 [*] Consider using a list instead of `str.split` | 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] 33 | "".split() # [] - | ^^^^^^^^^^ RUF035 + | ^^^^^^^^^^ SIM905 34 | """ 35 | """.split() # [] | @@ -386,13 +386,13 @@ RUF035.py:33:1: RUF035 [*] Consider using a list instead of `str.split` 35 35 | """.split() # [] 36 36 | " ".split() # [] -RUF035.py:34:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:34:1: SIM905 [*] Consider using a list instead of `str.split` | 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] 33 | "".split() # [] 34 | / """ 35 | | """.split() # [] - | |___________^ RUF035 + | |___________^ SIM905 36 | " ".split() # [] 37 | "/abc/".split() # ['/abc/'] | @@ -409,12 +409,12 @@ RUF035.py:34:1: RUF035 [*] Consider using a list instead of `str.split` 37 36 | "/abc/".split() # ['/abc/'] 38 37 | ("a,b,c" -RUF035.py:36:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:36:1: SIM905 [*] Consider using a list instead of `str.split` | 34 | """ 35 | """.split() # [] 36 | " ".split() # [] - | ^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^ SIM905 37 | "/abc/".split() # ['/abc/'] 38 | ("a,b,c" | @@ -430,12 +430,12 @@ RUF035.py:36:1: RUF035 [*] Consider using a list instead of `str.split` 38 38 | ("a,b,c" 39 39 | # comment -RUF035.py:37:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:37:1: SIM905 [*] Consider using a list instead of `str.split` | 35 | """.split() # [] 36 | " ".split() # [] 37 | "/abc/".split() # ['/abc/'] - | ^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^ SIM905 38 | ("a,b,c" 39 | # comment | @@ -451,7 +451,7 @@ RUF035.py:37:1: RUF035 [*] Consider using a list instead of `str.split` 39 39 | # comment 40 40 | .split() -RUF035.py:38:2: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:38:2: SIM905 [*] Consider using a list instead of `str.split` | 36 | " ".split() # [] 37 | "/abc/".split() # ['/abc/'] @@ -459,7 +459,7 @@ RUF035.py:38:2: RUF035 [*] Consider using a list instead of `str.split` | __^ 39 | | # comment 40 | | .split() - | |________^ RUF035 + | |________^ SIM905 41 | ) # ['a,b,c'] 42 | ("a,b,c" | @@ -477,7 +477,7 @@ RUF035.py:38:2: RUF035 [*] Consider using a list instead of `str.split` 42 40 | ("a,b,c" 43 41 | # comment -RUF035.py:42:2: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:42:2: SIM905 [*] Consider using a list instead of `str.split` | 40 | .split() 41 | ) # ['a,b,c'] @@ -485,7 +485,7 @@ RUF035.py:42:2: RUF035 [*] Consider using a list instead of `str.split` | __^ 43 | | # comment 44 | | .split(",") - | |___________^ RUF035 + | |___________^ SIM905 45 | ) # ['a', 'b', 'c'] 46 | ("a," | @@ -503,7 +503,7 @@ RUF035.py:42:2: RUF035 [*] Consider using a list instead of `str.split` 46 44 | ("a," 47 45 | # comment -RUF035.py:46:2: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:46:2: SIM905 [*] Consider using a list instead of `str.split` | 44 | .split(",") 45 | ) # ['a', 'b', 'c'] @@ -513,7 +513,7 @@ RUF035.py:46:2: RUF035 [*] Consider using a list instead of `str.split` 48 | | "b," 49 | | "c" 50 | | .split(",") - | |___________^ RUF035 + | |___________^ SIM905 51 | ) # ['a', 'b', 'c'] | = help: Replace `str.split` with list literal @@ -532,13 +532,13 @@ RUF035.py:46:2: RUF035 [*] Consider using a list instead of `str.split` 52 48 | 53 49 | "hello "\ -RUF035.py:53:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:53:1: SIM905 [*] Consider using a list instead of `str.split` | 51 | ) # ['a', 'b', 'c'] 52 | 53 | / "hello "\ 54 | | "world".split() - | |___________________^ RUF035 + | |___________________^ SIM905 55 | # ['hello', 'world'] | = help: Replace `str.split` with list literal @@ -554,11 +554,11 @@ RUF035.py:53:1: RUF035 [*] Consider using a list instead of `str.split` 56 55 | 57 56 | # prefixes and isc -RUF035.py:58:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:58:1: SIM905 [*] Consider using a list instead of `str.split` | 57 | # prefixes and isc 58 | u"a b".split() # ['a', 'b'] - | ^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^ SIM905 59 | r"a \n b".split() # ['a', '\\n', 'b'] 60 | ("a " "b").split() # ['a', 'b'] | @@ -574,12 +574,12 @@ RUF035.py:58:1: RUF035 [*] Consider using a list instead of `str.split` 60 60 | ("a " "b").split() # ['a', 'b'] 61 61 | "a " "b".split() # ['a', 'b'] -RUF035.py:59:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:59:1: SIM905 [*] Consider using a list instead of `str.split` | 57 | # prefixes and isc 58 | u"a b".split() # ['a', 'b'] 59 | r"a \n b".split() # ['a', '\\n', 'b'] - | ^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^ SIM905 60 | ("a " "b").split() # ['a', 'b'] 61 | "a " "b".split() # ['a', 'b'] | @@ -595,12 +595,12 @@ RUF035.py:59:1: RUF035 [*] Consider using a list instead of `str.split` 61 61 | "a " "b".split() # ['a', 'b'] 62 62 | u"a " "b".split() # ['a', 'b'] -RUF035.py:60:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:60:1: SIM905 [*] Consider using a list 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'] - | ^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^ SIM905 61 | "a " "b".split() # ['a', 'b'] 62 | u"a " "b".split() # ['a', 'b'] | @@ -616,12 +616,12 @@ RUF035.py:60:1: RUF035 [*] Consider using a list instead of `str.split` 62 62 | u"a " "b".split() # ['a', 'b'] 63 63 | "a " u"b".split() # ['a', 'b'] -RUF035.py:61:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:61:1: SIM905 [*] Consider using a list 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'] - | ^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^ SIM905 62 | u"a " "b".split() # ['a', 'b'] 63 | "a " u"b".split() # ['a', 'b'] | @@ -637,12 +637,12 @@ RUF035.py:61:1: RUF035 [*] Consider using a list instead of `str.split` 63 63 | "a " u"b".split() # ['a', 'b'] 64 64 | u"a " r"\n".split() # ['a', '\\n'] -RUF035.py:62:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:62:1: SIM905 [*] Consider using a list instead of `str.split` | 60 | ("a " "b").split() # ['a', 'b'] 61 | "a " "b".split() # ['a', 'b'] 62 | u"a " "b".split() # ['a', 'b'] - | ^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^ SIM905 63 | "a " u"b".split() # ['a', 'b'] 64 | u"a " r"\n".split() # ['a', '\\n'] | @@ -658,12 +658,12 @@ RUF035.py:62:1: RUF035 [*] Consider using a list instead of `str.split` 64 64 | u"a " r"\n".split() # ['a', '\\n'] 65 65 | r"\n " u"\n".split() # ['\\n'] -RUF035.py:63:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:63:1: SIM905 [*] Consider using a list instead of `str.split` | 61 | "a " "b".split() # ['a', 'b'] 62 | u"a " "b".split() # ['a', 'b'] 63 | "a " u"b".split() # ['a', 'b'] - | ^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^ SIM905 64 | u"a " r"\n".split() # ['a', '\\n'] 65 | r"\n " u"\n".split() # ['\\n'] | @@ -679,12 +679,12 @@ RUF035.py:63:1: RUF035 [*] Consider using a list instead of `str.split` 65 65 | r"\n " u"\n".split() # ['\\n'] 66 66 | r"\n " "\n".split() # ['\\n'] -RUF035.py:64:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:64:1: SIM905 [*] Consider using a list 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'] - | ^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^ SIM905 65 | r"\n " u"\n".split() # ['\\n'] 66 | r"\n " "\n".split() # ['\\n'] | @@ -700,12 +700,12 @@ RUF035.py:64:1: RUF035 [*] Consider using a list instead of `str.split` 66 66 | r"\n " "\n".split() # ['\\n'] 67 67 | "a " r"\n".split() # ['a', '\\n'] -RUF035.py:65:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:65:1: SIM905 [*] Consider using a list 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'] - | ^^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^^ SIM905 66 | r"\n " "\n".split() # ['\\n'] 67 | "a " r"\n".split() # ['a', '\\n'] | @@ -721,12 +721,12 @@ RUF035.py:65:1: RUF035 [*] Consider using a list instead of `str.split` 67 67 | "a " r"\n".split() # ['a', '\\n'] 68 68 | -RUF035.py:66:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:66:1: SIM905 [*] Consider using a list 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'] - | ^^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^^ SIM905 67 | "a " r"\n".split() # ['a', '\\n'] | = help: Replace `str.split` with list literal @@ -741,12 +741,12 @@ RUF035.py:66:1: RUF035 [*] Consider using a list instead of `str.split` 68 68 | 69 69 | # negatives -RUF035.py:67:1: RUF035 [*] Consider using a list instead of `str.split` +SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` | 65 | r"\n " u"\n".split() # ['\\n'] 66 | r"\n " "\n".split() # ['\\n'] 67 | "a " r"\n".split() # ['a', '\\n'] - | ^^^^^^^^^^^^^^^^^^ RUF035 + | ^^^^^^^^^^^^^^^^^^ SIM905 68 | 69 | # negatives | diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 77241802c8cd3..84b7fd0d8ff7d 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -61,7 +61,6 @@ mod tests { #[test_case(Rule::UselessIfElse, Path::new("RUF034.py"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101.py"))] #[test_case(Rule::PostInitDefault, Path::new("RUF033.py"))] - #[test_case(Rule::SplitOfStaticString, Path::new("RUF035.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/ruff/rules/mod.rs b/crates/ruff_linter/src/rules/ruff/rules/mod.rs index b5466c456070f..d386c3c7c6d8c 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/mod.rs @@ -18,6 +18,7 @@ pub(crate) use mutable_dataclass_default::*; pub(crate) use mutable_fromkeys_value::*; pub(crate) use never_union::*; pub(crate) use parenthesize_logical_operators::*; +pub(crate) use post_init_default::*; pub(crate) use quadratic_list_summation::*; pub(crate) use redirected_noqa::*; pub(crate) use sort_dunder_all::*; @@ -54,6 +55,7 @@ mod mutable_dataclass_default; mod mutable_fromkeys_value; mod never_union; mod parenthesize_logical_operators; +mod post_init_default; mod quadratic_list_summation; mod redirected_noqa; mod sequence_sorting; @@ -76,9 +78,3 @@ pub(crate) enum Context { Docstring, Comment, } -pub(crate) use post_init_default::*; - -mod post_init_default; -pub(crate) use split_of_static_string::*; - -mod split_of_static_string; diff --git a/ruff.schema.json b/ruff.schema.json index 345fbefa3b523..cf370f8123fd9 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3815,7 +3815,6 @@ "RUF032", "RUF033", "RUF034", - "RUF035", "RUF1", "RUF10", "RUF100", @@ -3954,6 +3953,8 @@ "SIM40", "SIM401", "SIM9", + "SIM90", + "SIM905", "SIM91", "SIM910", "SIM911", From 8d0ead5db4f8051ef13c6189d5e6033876d2a80c Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Thu, 31 Oct 2024 19:41:32 +0100 Subject: [PATCH 4/7] Rename rule and tweaks --- .../src/checkers/ast/analyze/expression.rs | 6 +++--- crates/ruff_linter/src/codes.rs | 2 +- crates/ruff_linter/src/rules/flake8_simplify/mod.rs | 2 +- .../src/rules/flake8_simplify/rules/mod.rs | 4 ++-- ...it_of_static_string.rs => split_static_string.rs} | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) rename crates/ruff_linter/src/rules/flake8_simplify/rules/{split_of_static_string.rs => split_static_string.rs} (95%) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 1ab6bab63ff2e..b2cb74d6ce2e5 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -385,7 +385,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { // refurb Rule::HashlibDigestHex, // flake8-simplify - Rule::SplitOfStaticString, + Rule::SplitStaticString, ]) { if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() { let attr = attr.as_str(); @@ -405,8 +405,8 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { } } else if matches!(attr, "split" | "rsplit") { // "...".split(...) call - if checker.enabled(Rule::SplitOfStaticString) { - flake8_simplify::rules::split_of_static_string( + if checker.enabled(Rule::SplitStaticString) { + flake8_simplify::rules::split_static_string( checker, attr, call, diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 10d05e445b56f..f8ec3696ca16e 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -480,7 +480,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Simplify, "223") => (RuleGroup::Stable, rules::flake8_simplify::rules::ExprAndFalse), (Flake8Simplify, "300") => (RuleGroup::Stable, rules::flake8_simplify::rules::YodaConditions), (Flake8Simplify, "401") => (RuleGroup::Stable, rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet), - (Flake8Simplify, "905") => (RuleGroup::Preview, rules::flake8_simplify::rules::SplitOfStaticString), + (Flake8Simplify, "905") => (RuleGroup::Preview, rules::flake8_simplify::rules::SplitStaticString), (Flake8Simplify, "910") => (RuleGroup::Stable, rules::flake8_simplify::rules::DictGetWithNoneDefault), (Flake8Simplify, "911") => (RuleGroup::Stable, rules::flake8_simplify::rules::ZipDictKeysAndValues), diff --git a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs index d98fe895fa5bc..6fb706df1709e 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/mod.rs @@ -46,7 +46,7 @@ mod tests { #[test_case(Rule::ExprAndFalse, Path::new("SIM223.py"))] #[test_case(Rule::YodaConditions, Path::new("SIM300.py"))] #[test_case(Rule::IfElseBlockInsteadOfDictGet, Path::new("SIM401.py"))] - #[test_case(Rule::SplitOfStaticString, Path::new("SIM905.py"))] + #[test_case(Rule::SplitStaticString, Path::new("SIM905.py"))] #[test_case(Rule::DictGetWithNoneDefault, Path::new("SIM910.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs index 80a68d2bd0796..1a28711cf805b 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/mod.rs @@ -14,7 +14,7 @@ pub(crate) use needless_bool::*; pub(crate) use open_file_with_context_handler::*; pub(crate) use reimplemented_builtin::*; pub(crate) use return_in_try_except_finally::*; -pub(crate) use split_of_static_string::*; +pub(crate) use split_static_string::*; pub(crate) use suppressible_exception::*; pub(crate) use yoda_conditions::*; pub(crate) use zip_dict_keys_and_values::*; @@ -36,7 +36,7 @@ mod needless_bool; mod open_file_with_context_handler; mod reimplemented_builtin; mod return_in_try_except_finally; -mod split_of_static_string; +mod split_static_string; mod suppressible_exception; mod yoda_conditions; mod zip_dict_keys_and_values; diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_of_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs similarity index 95% rename from crates/ruff_linter/src/rules/flake8_simplify/rules/split_of_static_string.rs rename to crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs index 5619908c2138a..a37907da77da2 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_of_static_string.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs @@ -9,7 +9,7 @@ use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for str.split calls that can be replaced with a `list` literal. +/// Checks for `str.split` calls that can be replaced with a list literal. /// /// ## Why is this bad? /// List literals are more readable and do not require the overhead of calling `str.split`. @@ -30,9 +30,9 @@ use crate::checkers::ast::Checker; /// /// ``` #[violation] -pub struct SplitOfStaticString; +pub struct SplitStaticString; -impl Violation for SplitOfStaticString { +impl Violation for SplitStaticString { const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; #[derive_message_formats] @@ -97,8 +97,8 @@ fn split_sep(str_value: &str, sep_value: &str, max_split: usize, direction_left: construct_replacement(&list_items) } -/// RUF035 -pub(crate) fn split_of_static_string( +/// SIM905 +pub(crate) fn split_static_string( checker: &mut Checker, attr: &str, call: &ExprCall, @@ -161,7 +161,7 @@ pub(crate) fn split_of_static_string( split_default(str_value, maxsplit_value) }; - let mut diagnostic = Diagnostic::new(SplitOfStaticString, call.range()); + let mut diagnostic = Diagnostic::new(SplitStaticString, call.range()); if let Some(ref replacement_expr) = split_replacement { // Construct replacement list let replacement = checker.generator().expr(replacement_expr); From d2d4095698e0a63c224ffe681bdd63de9fcf5655 Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Sat, 2 Nov 2024 00:20:42 +0100 Subject: [PATCH 5/7] Zero and minus zero test cases --- .../test/fixtures/flake8_simplify/SIM905.py | 5 + .../rules/split_static_string.rs | 115 +++++++++++------- ...ke8_simplify__tests__SIM905_SIM905.py.snap | 90 +++++++++++++- 3 files changed, 160 insertions(+), 50 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py index 696da476bbc45..f2851513d78ad 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py @@ -66,6 +66,11 @@ r"\n " "\n".split() # ['\\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'] + # negatives # invalid values should not cause panic diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs index a37907da77da2..409d12aca6cdc 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs @@ -1,3 +1,5 @@ +use std::cmp::Ordering; + use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{ @@ -65,7 +67,7 @@ fn construct_replacement(list_items: &[&str]) -> Expr { }) } -fn split_default(str_value: &str, max_split: usize) -> Option { +fn split_default(str_value: &str, max_split: i32) -> Option { // 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 @@ -73,30 +75,76 @@ fn split_default(str_value: &str, max_split: usize) -> Option { // > Consequently, splitting an empty string or a string consisting of just whitespace with // > a None separator returns []. // https://docs.python.org/3/library/stdtypes.html#str.split - if max_split == 0 { - let list_items: Vec<&str> = str_value.split_whitespace().collect(); - Some(construct_replacement(&list_items)) - } else { - // Autofix for maxsplit without separator not yet implemented - // split_whitespace().remainder() is still experimental: - // https://doc.rust-lang.org/std/str/struct.SplitWhitespace.html#method.remainder - None + match max_split.cmp(&0) { + Ordering::Greater => { + // Autofix for maxsplit without separator not yet implemented + // split_whitespace().remainder() is still experimental: + // https://doc.rust-lang.org/std/str/struct.SplitWhitespace.html#method.remainder + None + } + Ordering::Equal => { + let list_items: Vec<&str> = vec![str_value]; + Some(construct_replacement(&list_items)) + } + Ordering::Less => { + let list_items: Vec<&str> = str_value.split_whitespace().collect(); + Some(construct_replacement(&list_items)) + } } } -fn split_sep(str_value: &str, sep_value: &str, max_split: usize, direction_left: bool) -> Expr { - let list_items: Vec<&str> = if direction_left && max_split > 0 { - str_value.splitn(max_split + 1, sep_value).collect() - } else if !direction_left && max_split > 0 { - str_value.rsplitn(max_split + 1, sep_value).collect() - } else if direction_left && max_split == 0 { - str_value.split(sep_value).collect() +fn split_sep(str_value: &str, sep_value: &str, max_split: i32, direction_left: bool) -> Expr { + let list_items: Vec<&str> = if let Ok(split_n) = usize::try_from(max_split) { + if direction_left { + str_value.splitn(split_n + 1, sep_value).collect() + } else { + str_value.rsplitn(split_n + 1, sep_value).collect() + } } else { - str_value.rsplit(sep_value).collect() + if direction_left { + str_value.split(sep_value).collect() + } else { + str_value.rsplit(sep_value).collect() + } }; + construct_replacement(&list_items) } +fn get_maxsplit_value(maxsplit_arg: Option<&Expr>) -> Option { + let maxsplit_value = if let Some(maxsplit) = maxsplit_arg { + match maxsplit { + // Negative number + Expr::UnaryOp(ExprUnaryOp { + op: UnaryOp::USub, + operand, + .. + }) => { + match &**operand { + Expr::NumberLiteral(maxsplit_val) => maxsplit_val + .value + .as_int() + .and_then(ruff_python_ast::Int::as_i32) + .map(|f| -f), + // Ignore when `maxsplit` is not a numeric value + _ => None, + } + } + // Positive number + Expr::NumberLiteral(maxsplit_val) => maxsplit_val + .value + .as_int() + .and_then(ruff_python_ast::Int::as_i32), + // Ignore when `maxsplit` is not a numeric value + _ => None, + } + } else { + // Default value is -1 (no splits) + Some(-1) + }; + maxsplit_value +} + /// SIM905 pub(crate) fn split_static_string( checker: &mut Checker, @@ -106,40 +154,15 @@ pub(crate) fn split_static_string( ) { let ExprCall { arguments, .. } = call; - let sep_arg = arguments.find_argument("sep", 0); let maxsplit_arg = arguments.find_argument("maxsplit", 1); + let Some(maxsplit_value) = get_maxsplit_value(maxsplit_arg) else { + return; + }; // `split` vs `rsplit` let direction_left = attr == "split"; - let maxsplit_value = if let Some(maxsplit) = maxsplit_arg { - match maxsplit { - // Python allows maxsplit to be set to -1 - Expr::UnaryOp(ExprUnaryOp { - op: UnaryOp::USub, - operand, - .. - }) if matches!(**operand, Expr::NumberLiteral { .. }) => 0, - Expr::NumberLiteral(maxsplit_val) => { - if let Some(value) = maxsplit_val - .value - .as_int() - .and_then(ruff_python_ast::Int::as_usize) - { - value - } else { - return; - } - } - // Ignore when `maxsplit` is not a numeric value - _ => { - return; - } - } - } else { - 0 - }; - + let sep_arg = arguments.find_argument("sep", 0); let split_replacement = if let Some(sep) = sep_arg { match sep { Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value), diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap index 1dcb37a136b75..485e323295912 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap @@ -739,7 +739,7 @@ SIM905.py:66:1: SIM905 [*] Consider using a list instead of `str.split` 66 |+["\\n"] # ['\\n'] 67 67 | "a " r"\n".split() # ['a', '\\n'] 68 68 | -69 69 | # negatives +69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` | @@ -748,7 +748,7 @@ SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` 67 | "a " r"\n".split() # ['a', '\\n'] | ^^^^^^^^^^^^^^^^^^ SIM905 68 | -69 | # negatives +69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] | = help: Replace `str.split` with list literal @@ -759,5 +759,87 @@ SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` 67 |-"a " r"\n".split() # ['a', '\\n'] 67 |+["a", "\\n"] # ['a', '\\n'] 68 68 | -69 69 | # negatives -70 70 | +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 instead of `str.split` + | +67 | "a " r"\n".split() # ['a', '\\n'] +68 | +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'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +66 66 | r"\n " "\n".split() # ['\\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'] + +SIM905.py:70:1: SIM905 [*] Consider using a list instead of `str.split` + | +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'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe fix +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'] +73 73 | + +SIM905.py:71:1: SIM905 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c'] + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] +73 73 | +74 74 | # negatives + +SIM905.py:72:1: SIM905 [*] Consider using a list 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'] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +73 | +74 | # negatives + | + = help: Replace `str.split` with list literal + +ℹ Unsafe 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'] +73 73 | +74 74 | # negatives +75 75 | From 56047ffa53ffd0fb96737b977fcd0612c5103721 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 2 Nov 2024 13:02:41 -0400 Subject: [PATCH 6/7] Nits --- .../rules/split_static_string.rs | 162 +++++++++--------- ...ke8_simplify__tests__SIM905_SIM905.py.snap | 84 ++++----- 2 files changed, 127 insertions(+), 119 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs index 409d12aca6cdc..67431f3779c4c 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs @@ -11,7 +11,7 @@ use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for `str.split` calls that can be replaced with a list literal. +/// Checks for static `str.split` calls that can be replaced with list literals. /// /// ## Why is this bad? /// List literals are more readable and do not require the overhead of calling `str.split`. @@ -26,10 +26,12 @@ use crate::checkers::ast::Checker; /// ["a", "b", "c", "d"] /// ``` /// -/// ## References +/// ## Fix safety +/// This rule's fix is marked as unsafe as it may not preserve comments within implicit string +/// concatenations. /// +/// ## References /// - [Python documentation: `str.split`](https://docs.python.org/3/library/stdtypes.html#str.split) -/// /// ``` #[violation] pub struct SplitStaticString; @@ -43,18 +45,72 @@ impl Violation for SplitStaticString { } fn fix_title(&self) -> Option { - Some(format!("Replace `str.split` with list literal")) + Some("Replace with list literal".to_string()) } } -fn construct_replacement(list_items: &[&str]) -> Expr { +/// SIM905 +pub(crate) fn split_static_string( + checker: &mut Checker, + attr: &str, + call: &ExprCall, + str_value: &str, +) { + let ExprCall { arguments, .. } = call; + + let maxsplit_arg = arguments.find_argument("maxsplit", 1); + let Some(maxsplit_value) = get_maxsplit_value(maxsplit_arg) else { + return; + }; + + // `split` vs `rsplit`. + let direction = if attr == "split" { + Direction::Left + } else { + Direction::Right + }; + + let sep_arg = arguments.find_argument("sep", 0); + let split_replacement = if let Some(sep) = sep_arg { + match sep { + Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value), + Expr::StringLiteral(sep_value) => { + let sep_value_str = sep_value.value.to_str(); + Some(split_sep( + str_value, + sep_value_str, + maxsplit_value, + direction, + )) + } + // Ignore names until type inference is available + _ => { + return; + } + } + } else { + split_default(str_value, maxsplit_value) + }; + + let mut diagnostic = Diagnostic::new(SplitStaticString, call.range()); + if let Some(ref replacement_expr) = split_replacement { + // Unsafe because the fix does not preserve comments within implicit string concatenation + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( + checker.generator().expr(replacement_expr), + call.range(), + ))); + } + checker.diagnostics.push(diagnostic); +} + +fn construct_replacement(elts: &[&str]) -> Expr { Expr::List(ExprList { - elts: list_items + elts: elts .iter() - .map(|list_item| { + .map(|elt| { Expr::StringLiteral(ExprStringLiteral { value: StringLiteralValue::single(StringLiteral { - value: (*list_item).to_string().into_boxed_str(), + value: (*elt).to_string().into_boxed_str(), range: TextRange::default(), flags: StringLiteralFlags::default(), }), @@ -77,8 +133,8 @@ fn split_default(str_value: &str, max_split: i32) -> Option { // https://docs.python.org/3/library/stdtypes.html#str.split match max_split.cmp(&0) { Ordering::Greater => { - // Autofix for maxsplit without separator not yet implemented - // split_whitespace().remainder() is still experimental: + // Autofix for `maxsplit` without separator not yet implemented, as + // `split_whitespace().remainder()` is not stable: // https://doc.rust-lang.org/std/str/struct.SplitWhitespace.html#method.remainder None } @@ -93,28 +149,27 @@ fn split_default(str_value: &str, max_split: i32) -> Option { } } -fn split_sep(str_value: &str, sep_value: &str, max_split: i32, direction_left: bool) -> Expr { +fn split_sep(str_value: &str, sep_value: &str, max_split: i32, direction: Direction) -> Expr { let list_items: Vec<&str> = if let Ok(split_n) = usize::try_from(max_split) { - if direction_left { - str_value.splitn(split_n + 1, sep_value).collect() - } else { - str_value.rsplitn(split_n + 1, sep_value).collect() + match direction { + Direction::Left => str_value.splitn(split_n + 1, sep_value).collect(), + Direction::Right => str_value.rsplitn(split_n + 1, sep_value).collect(), } } else { - if direction_left { - str_value.split(sep_value).collect() - } else { - str_value.rsplit(sep_value).collect() + match direction { + Direction::Left => str_value.split(sep_value).collect(), + Direction::Right => str_value.rsplit(sep_value).collect(), } }; construct_replacement(&list_items) } -fn get_maxsplit_value(maxsplit_arg: Option<&Expr>) -> Option { - let maxsplit_value = if let Some(maxsplit) = maxsplit_arg { +/// Returns the value of the `maxsplit` argument as an `i32`, if it is a numeric value. +fn get_maxsplit_value(arg: Option<&Expr>) -> Option { + if let Some(maxsplit) = arg { match maxsplit { - // Negative number + // Negative number. Expr::UnaryOp(ExprUnaryOp { op: UnaryOp::USub, operand, @@ -126,7 +181,7 @@ fn get_maxsplit_value(maxsplit_arg: Option<&Expr>) -> Option { .as_int() .and_then(ruff_python_ast::Int::as_i32) .map(|f| -f), - // Ignore when `maxsplit` is not a numeric value + // Ignore when `maxsplit` is not a numeric value. _ => None, } } @@ -135,64 +190,17 @@ fn get_maxsplit_value(maxsplit_arg: Option<&Expr>) -> Option { .value .as_int() .and_then(ruff_python_ast::Int::as_i32), - // Ignore when `maxsplit` is not a numeric value + // Ignore when `maxsplit` is not a numeric value. _ => None, } } else { - // Default value is -1 (no splits) + // Default value is -1 (no splits). Some(-1) - }; - maxsplit_value + } } -/// SIM905 -pub(crate) fn split_static_string( - checker: &mut Checker, - attr: &str, - call: &ExprCall, - str_value: &str, -) { - let ExprCall { arguments, .. } = call; - - let maxsplit_arg = arguments.find_argument("maxsplit", 1); - let Some(maxsplit_value) = get_maxsplit_value(maxsplit_arg) else { - return; - }; - - // `split` vs `rsplit` - let direction_left = attr == "split"; - - let sep_arg = arguments.find_argument("sep", 0); - let split_replacement = if let Some(sep) = sep_arg { - match sep { - Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value), - Expr::StringLiteral(sep_value) => { - let sep_value_str = sep_value.value.to_str(); - Some(split_sep( - str_value, - sep_value_str, - maxsplit_value, - direction_left, - )) - } - // Ignore names until type inference is available - _ => { - return; - } - } - } else { - split_default(str_value, maxsplit_value) - }; - - let mut diagnostic = Diagnostic::new(SplitStaticString, call.range()); - if let Some(ref replacement_expr) = split_replacement { - // Construct replacement list - let replacement = checker.generator().expr(replacement_expr); - // Unsafe because the fix does not preserve comments within implicit string concatenation - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - replacement, - call.range(), - ))); - } - checker.diagnostics.push(diagnostic); +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Direction { + Left, + Right, } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap index 485e323295912..07c4884172386 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap @@ -13,7 +13,7 @@ SIM905.py:6:1: SIM905 [*] Consider using a list instead of `str.split` 11 | 12 | "a,b,c,d".split(",") | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 3 3 | no_sep = None @@ -38,7 +38,7 @@ SIM905.py:12:1: SIM905 [*] Consider using a list instead of `str.split` 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 9 9 | itemC @@ -58,7 +58,7 @@ SIM905.py:13:1: SIM905 [*] Consider using a list instead of `str.split` 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 10 10 | """.split() @@ -79,7 +79,7 @@ SIM905.py:14:1: SIM905 [*] Consider using a list instead of `str.split` 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 11 11 | @@ -100,7 +100,7 @@ SIM905.py:15:1: SIM905 Consider using a list instead of `str.split` 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` | @@ -111,7 +111,7 @@ SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 13 13 | "a,b,c,d".split(None) @@ -132,7 +132,7 @@ SIM905.py:17:1: SIM905 [*] Consider using a list instead of `str.split` 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 14 14 | "a,b,c,d".split(",", 1) @@ -153,7 +153,7 @@ SIM905.py:18:1: SIM905 [*] Consider using a list instead of `str.split` 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 15 15 | "a,b,c,d".split(None, 1) @@ -174,7 +174,7 @@ SIM905.py:19:1: SIM905 Consider using a list instead of `str.split` 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` | @@ -185,7 +185,7 @@ SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 17 17 | "a,b,c,d".split(sep=None) @@ -206,7 +206,7 @@ SIM905.py:21:1: SIM905 Consider using a list instead of `str.split` 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` | @@ -217,7 +217,7 @@ SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` 23 | "a,b,c,d".split(None, maxsplit=1) 24 | "a,b,c,d".split(maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) @@ -238,7 +238,7 @@ SIM905.py:23:1: SIM905 Consider using a list instead of `str.split` 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:24:1: SIM905 Consider using a list instead of `str.split` | @@ -249,7 +249,7 @@ SIM905.py:24:1: SIM905 Consider using a list instead of `str.split` 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:26:1: SIM905 Consider using a list instead of `str.split` | @@ -260,7 +260,7 @@ SIM905.py:26:1: SIM905 Consider using a list instead of `str.split` 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") | - = help: Replace `str.split` with list literal + = help: Replace with list literal SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` | @@ -271,7 +271,7 @@ SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 24 24 | "a,b,c,d".split(maxsplit=1) @@ -292,7 +292,7 @@ SIM905.py:28:1: SIM905 [*] Consider using a list instead of `str.split` 29 | ' 1 2 3 '.split() 30 | '1<>2<>3<4'.split('<>') | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 25 25 | "a,b,c,d".split(maxsplit=1.0) @@ -312,7 +312,7 @@ SIM905.py:29:1: SIM905 [*] Consider using a list instead of `str.split` | ^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 30 | '1<>2<>3<4'.split('<>') | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 26 26 | "a,b,c,d".split(maxsplit=1) @@ -333,7 +333,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list instead of `str.split` 31 | 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 27 27 | "a,b,c,d".split(maxsplit=0) @@ -354,7 +354,7 @@ SIM905.py:32:1: SIM905 [*] Consider using a list instead of `str.split` 33 | "".split() # [] 34 | """ | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 29 29 | ' 1 2 3 '.split() @@ -374,7 +374,7 @@ SIM905.py:33:1: SIM905 [*] Consider using a list instead of `str.split` 34 | """ 35 | """.split() # [] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 30 30 | '1<>2<>3<4'.split('<>') @@ -396,7 +396,7 @@ SIM905.py:34:1: SIM905 [*] Consider using a list instead of `str.split` 36 | " ".split() # [] 37 | "/abc/".split() # ['/abc/'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 31 31 | @@ -418,7 +418,7 @@ SIM905.py:36:1: SIM905 [*] Consider using a list instead of `str.split` 37 | "/abc/".split() # ['/abc/'] 38 | ("a,b,c" | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 33 33 | "".split() # [] @@ -439,7 +439,7 @@ SIM905.py:37:1: SIM905 [*] Consider using a list instead of `str.split` 38 | ("a,b,c" 39 | # comment | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 34 34 | """ @@ -463,7 +463,7 @@ SIM905.py:38:2: SIM905 [*] Consider using a list instead of `str.split` 41 | ) # ['a,b,c'] 42 | ("a,b,c" | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 35 35 | """.split() # [] @@ -489,7 +489,7 @@ SIM905.py:42:2: SIM905 [*] Consider using a list instead of `str.split` 45 | ) # ['a', 'b', 'c'] 46 | ("a," | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 39 39 | # comment @@ -516,7 +516,7 @@ SIM905.py:46:2: SIM905 [*] Consider using a list instead of `str.split` | |___________^ SIM905 51 | ) # ['a', 'b', 'c'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 43 43 | # comment @@ -541,7 +541,7 @@ SIM905.py:53:1: SIM905 [*] Consider using a list instead of `str.split` | |___________________^ SIM905 55 | # ['hello', 'world'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 50 50 | .split(",") @@ -562,7 +562,7 @@ SIM905.py:58:1: SIM905 [*] Consider using a list instead of `str.split` 59 | r"a \n b".split() # ['a', '\\n', 'b'] 60 | ("a " "b").split() # ['a', 'b'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 55 55 | # ['hello', 'world'] @@ -583,7 +583,7 @@ SIM905.py:59:1: SIM905 [*] Consider using a list instead of `str.split` 60 | ("a " "b").split() # ['a', 'b'] 61 | "a " "b".split() # ['a', 'b'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 56 56 | @@ -604,7 +604,7 @@ SIM905.py:60:1: SIM905 [*] Consider using a list instead of `str.split` 61 | "a " "b".split() # ['a', 'b'] 62 | u"a " "b".split() # ['a', 'b'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 57 57 | # prefixes and isc @@ -625,7 +625,7 @@ SIM905.py:61:1: SIM905 [*] Consider using a list instead of `str.split` 62 | u"a " "b".split() # ['a', 'b'] 63 | "a " u"b".split() # ['a', 'b'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 58 58 | u"a b".split() # ['a', 'b'] @@ -646,7 +646,7 @@ SIM905.py:62:1: SIM905 [*] Consider using a list instead of `str.split` 63 | "a " u"b".split() # ['a', 'b'] 64 | u"a " r"\n".split() # ['a', '\\n'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 59 59 | r"a \n b".split() # ['a', '\\n', 'b'] @@ -667,7 +667,7 @@ SIM905.py:63:1: SIM905 [*] Consider using a list instead of `str.split` 64 | u"a " r"\n".split() # ['a', '\\n'] 65 | r"\n " u"\n".split() # ['\\n'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 60 60 | ("a " "b").split() # ['a', 'b'] @@ -688,7 +688,7 @@ SIM905.py:64:1: SIM905 [*] Consider using a list instead of `str.split` 65 | r"\n " u"\n".split() # ['\\n'] 66 | r"\n " "\n".split() # ['\\n'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 61 61 | "a " "b".split() # ['a', 'b'] @@ -709,7 +709,7 @@ SIM905.py:65:1: SIM905 [*] Consider using a list instead of `str.split` 66 | r"\n " "\n".split() # ['\\n'] 67 | "a " r"\n".split() # ['a', '\\n'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 62 62 | u"a " "b".split() # ['a', 'b'] @@ -729,7 +729,7 @@ SIM905.py:66:1: SIM905 [*] Consider using a list instead of `str.split` | ^^^^^^^^^^^^^^^^^^^ SIM905 67 | "a " r"\n".split() # ['a', '\\n'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 63 63 | "a " u"b".split() # ['a', 'b'] @@ -750,7 +750,7 @@ SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` 68 | 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 64 64 | u"a " r"\n".split() # ['a', '\\n'] @@ -771,7 +771,7 @@ SIM905.py:69:1: SIM905 [*] Consider using a list instead of `str.split` 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c'] 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 66 66 | r"\n " "\n".split() # ['\\n'] @@ -791,7 +791,7 @@ SIM905.py:70:1: SIM905 [*] Consider using a list instead of `str.split` 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c'] 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 67 67 | "a " r"\n".split() # ['a', '\\n'] @@ -811,7 +811,7 @@ SIM905.py:71:1: SIM905 [*] Consider using a list instead of `str.split` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c'] | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 68 68 | @@ -832,7 +832,7 @@ SIM905.py:72:1: SIM905 [*] Consider using a list instead of `str.split` 73 | 74 | # negatives | - = help: Replace `str.split` with list literal + = help: Replace with list literal ℹ Unsafe fix 69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] From f099b0d371e25f4c87ae881309bf853931b18fc1 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 2 Nov 2024 13:10:14 -0400 Subject: [PATCH 7/7] Make safe --- .../test/fixtures/flake8_simplify/SIM905.py | 2 +- .../rules/split_static_string.rs | 33 ++-- ...ke8_simplify__tests__SIM905_SIM905.py.snap | 158 +++++++++--------- 3 files changed, 103 insertions(+), 90 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py index f2851513d78ad..e050ece6231c7 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py @@ -40,7 +40,7 @@ .split() ) # ['a,b,c'] ("a,b,c" -# comment +# comment1 .split(",") ) # ['a', 'b', 'c'] ("a," diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs index 67431f3779c4c..0966004a605a6 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{ Expr, ExprCall, ExprContext, ExprList, ExprStringLiteral, ExprUnaryOp, StringLiteral, @@ -27,8 +27,17 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Fix safety -/// This rule's fix is marked as unsafe as it may not preserve comments within implicit string -/// concatenations. +/// This rule's fix is marked as unsafe for implicit string concatenations with comments interleaved +/// between segments, as comments may be removed. +/// +/// For example, the fix would be marked as unsafe in the following case: +/// ```python +/// ( +/// "a" # comment +/// "," # comment +/// "b" # comment +/// ).split(",") +/// ``` /// /// ## References /// - [Python documentation: `str.split`](https://docs.python.org/3/library/stdtypes.html#str.split) @@ -41,7 +50,7 @@ impl Violation for SplitStaticString { #[derive_message_formats] fn message(&self) -> String { - format!("Consider using a list instead of `str.split`") + format!("Consider using a list literal instead of `str.split`") } fn fix_title(&self) -> Option { @@ -83,7 +92,7 @@ pub(crate) fn split_static_string( direction, )) } - // Ignore names until type inference is available + // Ignore names until type inference is available. _ => { return; } @@ -94,11 +103,15 @@ pub(crate) fn split_static_string( let mut diagnostic = Diagnostic::new(SplitStaticString, call.range()); if let Some(ref replacement_expr) = split_replacement { - // Unsafe because the fix does not preserve comments within implicit string concatenation - diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( - checker.generator().expr(replacement_expr), - call.range(), - ))); + diagnostic.set_fix(Fix::applicable_edit( + Edit::range_replacement(checker.generator().expr(replacement_expr), call.range()), + // The fix does not preserve comments within implicit string concatenations. + if checker.comment_ranges().intersects(call.range()) { + Applicability::Unsafe + } else { + Applicability::Safe + }, + )); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap index 07c4884172386..d0b5183467cfb 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs --- -SIM905.py:6:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:6:1: SIM905 [*] Consider using a list literal instead of `str.split` | 5 | # positives 6 | / """ @@ -15,7 +15,7 @@ SIM905.py:6:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 3 3 | no_sep = None 4 4 | 5 5 | # positives @@ -29,7 +29,7 @@ SIM905.py:6:1: SIM905 [*] Consider using a list instead of `str.split` 12 8 | "a,b,c,d".split(",") 13 9 | "a,b,c,d".split(None) -SIM905.py:12:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:12:1: SIM905 [*] Consider using a list literal instead of `str.split` | 10 | """.split() 11 | @@ -40,7 +40,7 @@ SIM905.py:12:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 9 9 | itemC 10 10 | """.split() 11 11 | @@ -50,7 +50,7 @@ SIM905.py:12:1: SIM905 [*] Consider using a list instead of `str.split` 14 14 | "a,b,c,d".split(",", 1) 15 15 | "a,b,c,d".split(None, 1) -SIM905.py:13:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:13:1: SIM905 [*] Consider using a list literal instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) @@ -60,7 +60,7 @@ SIM905.py:13:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 10 10 | """.split() 11 11 | 12 12 | "a,b,c,d".split(",") @@ -70,7 +70,7 @@ SIM905.py:13:1: SIM905 [*] Consider using a list instead of `str.split` 15 15 | "a,b,c,d".split(None, 1) 16 16 | "a,b,c,d".split(sep=",") -SIM905.py:14:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:14:1: SIM905 [*] Consider using a list literal instead of `str.split` | 12 | "a,b,c,d".split(",") 13 | "a,b,c,d".split(None) @@ -81,7 +81,7 @@ SIM905.py:14:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 11 11 | 12 12 | "a,b,c,d".split(",") 13 13 | "a,b,c,d".split(None) @@ -91,7 +91,7 @@ SIM905.py:14:1: SIM905 [*] Consider using a list instead of `str.split` 16 16 | "a,b,c,d".split(sep=",") 17 17 | "a,b,c,d".split(sep=None) -SIM905.py:15:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:15:1: SIM905 Consider using a list literal instead of `str.split` | 13 | "a,b,c,d".split(None) 14 | "a,b,c,d".split(",", 1) @@ -102,7 +102,7 @@ SIM905.py:15:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:16:1: SIM905 [*] Consider using a list literal instead of `str.split` | 14 | "a,b,c,d".split(",", 1) 15 | "a,b,c,d".split(None, 1) @@ -113,7 +113,7 @@ SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 13 13 | "a,b,c,d".split(None) 14 14 | "a,b,c,d".split(",", 1) 15 15 | "a,b,c,d".split(None, 1) @@ -123,7 +123,7 @@ SIM905.py:16:1: SIM905 [*] Consider using a list instead of `str.split` 18 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) -SIM905.py:17:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:17:1: SIM905 [*] Consider using a list literal instead of `str.split` | 15 | "a,b,c,d".split(None, 1) 16 | "a,b,c,d".split(sep=",") @@ -134,7 +134,7 @@ SIM905.py:17:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 14 14 | "a,b,c,d".split(",", 1) 15 15 | "a,b,c,d".split(None, 1) 16 16 | "a,b,c,d".split(sep=",") @@ -144,7 +144,7 @@ SIM905.py:17:1: SIM905 [*] Consider using a list instead of `str.split` 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") -SIM905.py:18:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:18:1: SIM905 [*] Consider using a list literal instead of `str.split` | 16 | "a,b,c,d".split(sep=",") 17 | "a,b,c,d".split(sep=None) @@ -155,7 +155,7 @@ SIM905.py:18:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 15 15 | "a,b,c,d".split(None, 1) 16 16 | "a,b,c,d".split(sep=",") 17 17 | "a,b,c,d".split(sep=None) @@ -165,7 +165,7 @@ SIM905.py:18:1: SIM905 [*] Consider using a list instead of `str.split` 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 21 | "a,b,c,d".split(maxsplit=1, sep=None) -SIM905.py:19:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:19:1: SIM905 Consider using a list literal instead of `str.split` | 17 | "a,b,c,d".split(sep=None) 18 | "a,b,c,d".split(sep=",", maxsplit=1) @@ -176,7 +176,7 @@ SIM905.py:19:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:20:1: SIM905 [*] Consider using a list literal instead of `str.split` | 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 | "a,b,c,d".split(sep=None, maxsplit=1) @@ -187,7 +187,7 @@ SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 17 17 | "a,b,c,d".split(sep=None) 18 18 | "a,b,c,d".split(sep=",", maxsplit=1) 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) @@ -197,7 +197,7 @@ SIM905.py:20:1: SIM905 [*] Consider using a list instead of `str.split` 22 22 | "a,b,c,d".split(",", maxsplit=1) 23 23 | "a,b,c,d".split(None, maxsplit=1) -SIM905.py:21:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:21:1: SIM905 Consider using a list literal instead of `str.split` | 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 | "a,b,c,d".split(maxsplit=1, sep=",") @@ -208,7 +208,7 @@ SIM905.py:21:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:22:1: SIM905 [*] Consider using a list literal instead of `str.split` | 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 | "a,b,c,d".split(maxsplit=1, sep=None) @@ -219,7 +219,7 @@ SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 19 19 | "a,b,c,d".split(sep=None, maxsplit=1) 20 20 | "a,b,c,d".split(maxsplit=1, sep=",") 21 21 | "a,b,c,d".split(maxsplit=1, sep=None) @@ -229,7 +229,7 @@ SIM905.py:22:1: SIM905 [*] Consider using a list instead of `str.split` 24 24 | "a,b,c,d".split(maxsplit=1) 25 25 | "a,b,c,d".split(maxsplit=1.0) -SIM905.py:23:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:23:1: SIM905 Consider using a list literal instead of `str.split` | 21 | "a,b,c,d".split(maxsplit=1, sep=None) 22 | "a,b,c,d".split(",", maxsplit=1) @@ -240,7 +240,7 @@ SIM905.py:23:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:24:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:24:1: SIM905 Consider using a list literal instead of `str.split` | 22 | "a,b,c,d".split(",", maxsplit=1) 23 | "a,b,c,d".split(None, maxsplit=1) @@ -251,7 +251,7 @@ SIM905.py:24:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:26:1: SIM905 Consider using a list instead of `str.split` +SIM905.py:26:1: SIM905 Consider using a list literal instead of `str.split` | 24 | "a,b,c,d".split(maxsplit=1) 25 | "a,b,c,d".split(maxsplit=1.0) @@ -262,7 +262,7 @@ SIM905.py:26:1: SIM905 Consider using a list instead of `str.split` | = help: Replace with list literal -SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:27:1: SIM905 [*] Consider using a list literal instead of `str.split` | 25 | "a,b,c,d".split(maxsplit=1.0) 26 | "a,b,c,d".split(maxsplit=1) @@ -273,7 +273,7 @@ SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 24 24 | "a,b,c,d".split(maxsplit=1) 25 25 | "a,b,c,d".split(maxsplit=1.0) 26 26 | "a,b,c,d".split(maxsplit=1) @@ -283,7 +283,7 @@ SIM905.py:27:1: SIM905 [*] Consider using a list instead of `str.split` 29 29 | ' 1 2 3 '.split() 30 30 | '1<>2<>3<4'.split('<>') -SIM905.py:28:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:28:1: SIM905 [*] Consider using a list literal instead of `str.split` | 26 | "a,b,c,d".split(maxsplit=1) 27 | "a,b,c,d".split(maxsplit=0) @@ -294,7 +294,7 @@ SIM905.py:28:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 25 25 | "a,b,c,d".split(maxsplit=1.0) 26 26 | "a,b,c,d".split(maxsplit=1) 27 27 | "a,b,c,d".split(maxsplit=0) @@ -304,7 +304,7 @@ SIM905.py:28:1: SIM905 [*] Consider using a list instead of `str.split` 30 30 | '1<>2<>3<4'.split('<>') 31 31 | -SIM905.py:29:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:29:1: SIM905 [*] Consider using a list literal instead of `str.split` | 27 | "a,b,c,d".split(maxsplit=0) 28 | "VERB AUX PRON ADP DET".split(" ") @@ -314,7 +314,7 @@ SIM905.py:29:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 26 26 | "a,b,c,d".split(maxsplit=1) 27 27 | "a,b,c,d".split(maxsplit=0) 28 28 | "VERB AUX PRON ADP DET".split(" ") @@ -324,7 +324,7 @@ SIM905.py:29:1: SIM905 [*] Consider using a list instead of `str.split` 31 31 | 32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] -SIM905.py:30:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:30:1: SIM905 [*] Consider using a list literal instead of `str.split` | 28 | "VERB AUX PRON ADP DET".split(" ") 29 | ' 1 2 3 '.split() @@ -335,7 +335,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 27 27 | "a,b,c,d".split(maxsplit=0) 28 28 | "VERB AUX PRON ADP DET".split(" ") 29 29 | ' 1 2 3 '.split() @@ -345,7 +345,7 @@ SIM905.py:30:1: SIM905 [*] Consider using a list instead of `str.split` 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 instead of `str.split` +SIM905.py:32:1: SIM905 [*] Consider using a list literal instead of `str.split` | 30 | '1<>2<>3<4'.split('<>') 31 | @@ -356,7 +356,7 @@ SIM905.py:32:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 29 29 | ' 1 2 3 '.split() 30 30 | '1<>2<>3<4'.split('<>') 31 31 | @@ -366,7 +366,7 @@ SIM905.py:32:1: SIM905 [*] Consider using a list instead of `str.split` 34 34 | """ 35 35 | """.split() # [] -SIM905.py:33:1: SIM905 [*] Consider using a list 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 '] 33 | "".split() # [] @@ -376,7 +376,7 @@ SIM905.py:33:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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 '] @@ -386,7 +386,7 @@ SIM905.py:33:1: SIM905 [*] Consider using a list instead of `str.split` 35 35 | """.split() # [] 36 36 | " ".split() # [] -SIM905.py:34:1: SIM905 [*] Consider using a list 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 '] 33 | "".split() # [] @@ -398,7 +398,7 @@ SIM905.py:34:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 31 31 | 32 32 | " a*a a*a a ".split("*", -1) # [' a', 'a a', 'a a '] 33 33 | "".split() # [] @@ -409,7 +409,7 @@ SIM905.py:34:1: SIM905 [*] Consider using a list instead of `str.split` 37 36 | "/abc/".split() # ['/abc/'] 38 37 | ("a,b,c" -SIM905.py:36:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:36:1: SIM905 [*] Consider using a list literal instead of `str.split` | 34 | """ 35 | """.split() # [] @@ -420,7 +420,7 @@ SIM905.py:36:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 33 33 | "".split() # [] 34 34 | """ 35 35 | """.split() # [] @@ -430,7 +430,7 @@ SIM905.py:36:1: SIM905 [*] Consider using a list instead of `str.split` 38 38 | ("a,b,c" 39 39 | # comment -SIM905.py:37:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:37:1: SIM905 [*] Consider using a list literal instead of `str.split` | 35 | """.split() # [] 36 | " ".split() # [] @@ -441,7 +441,7 @@ SIM905.py:37:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 34 34 | """ 35 35 | """.split() # [] 36 36 | " ".split() # [] @@ -451,7 +451,7 @@ SIM905.py:37:1: SIM905 [*] Consider using a list instead of `str.split` 39 39 | # comment 40 40 | .split() -SIM905.py:38:2: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:38:2: SIM905 [*] Consider using a list literal instead of `str.split` | 36 | " ".split() # [] 37 | "/abc/".split() # ['/abc/'] @@ -475,15 +475,15 @@ SIM905.py:38:2: SIM905 [*] Consider using a list instead of `str.split` 38 |+(["a,b,c"] 41 39 | ) # ['a,b,c'] 42 40 | ("a,b,c" -43 41 | # comment +43 41 | # comment1 -SIM905.py:42:2: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:42:2: SIM905 [*] Consider using a list literal instead of `str.split` | 40 | .split() 41 | ) # ['a,b,c'] 42 | ("a,b,c" | __^ -43 | | # comment +43 | | # comment1 44 | | .split(",") | |___________^ SIM905 45 | ) # ['a', 'b', 'c'] @@ -496,14 +496,14 @@ SIM905.py:42:2: SIM905 [*] Consider using a list instead of `str.split` 40 40 | .split() 41 41 | ) # ['a,b,c'] 42 |-("a,b,c" -43 |-# comment +43 |-# comment1 44 |-.split(",") 42 |+(["a", "b", "c"] 45 43 | ) # ['a', 'b', 'c'] 46 44 | ("a," 47 45 | # comment -SIM905.py:46:2: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:46:2: SIM905 [*] Consider using a list literal instead of `str.split` | 44 | .split(",") 45 | ) # ['a', 'b', 'c'] @@ -519,7 +519,7 @@ SIM905.py:46:2: SIM905 [*] Consider using a list instead of `str.split` = help: Replace with list literal ℹ Unsafe fix -43 43 | # comment +43 43 | # comment1 44 44 | .split(",") 45 45 | ) # ['a', 'b', 'c'] 46 |-("a," @@ -532,7 +532,7 @@ SIM905.py:46:2: SIM905 [*] Consider using a list instead of `str.split` 52 48 | 53 49 | "hello "\ -SIM905.py:53:1: SIM905 [*] Consider using a list instead of `str.split` +SIM905.py:53:1: SIM905 [*] Consider using a list literal instead of `str.split` | 51 | ) # ['a', 'b', 'c'] 52 | @@ -543,7 +543,7 @@ SIM905.py:53:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 50 50 | .split(",") 51 51 | ) # ['a', 'b', 'c'] 52 52 | @@ -554,7 +554,7 @@ SIM905.py:53:1: SIM905 [*] Consider using a list instead of `str.split` 56 55 | 57 56 | # prefixes and isc -SIM905.py:58:1: SIM905 [*] Consider using a list instead of `str.split` +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'] @@ -564,7 +564,7 @@ SIM905.py:58:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 55 55 | # ['hello', 'world'] 56 56 | 57 57 | # prefixes and isc @@ -574,7 +574,7 @@ SIM905.py:58:1: SIM905 [*] Consider using a list instead of `str.split` 60 60 | ("a " "b").split() # ['a', 'b'] 61 61 | "a " "b".split() # ['a', 'b'] -SIM905.py:59:1: SIM905 [*] Consider using a list instead of `str.split` +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'] @@ -585,7 +585,7 @@ SIM905.py:59:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 56 56 | 57 57 | # prefixes and isc 58 58 | u"a b".split() # ['a', 'b'] @@ -595,7 +595,7 @@ SIM905.py:59:1: SIM905 [*] Consider using a list instead of `str.split` 61 61 | "a " "b".split() # ['a', 'b'] 62 62 | u"a " "b".split() # ['a', 'b'] -SIM905.py:60:1: SIM905 [*] Consider using a list 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'] 59 | r"a \n b".split() # ['a', '\\n', 'b'] @@ -606,7 +606,7 @@ SIM905.py:60:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -616,7 +616,7 @@ SIM905.py:60:1: SIM905 [*] Consider using a list instead of `str.split` 62 62 | u"a " "b".split() # ['a', 'b'] 63 63 | "a " u"b".split() # ['a', 'b'] -SIM905.py:61:1: SIM905 [*] Consider using a list 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'] 60 | ("a " "b").split() # ['a', 'b'] @@ -627,7 +627,7 @@ SIM905.py:61:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -637,7 +637,7 @@ SIM905.py:61:1: SIM905 [*] Consider using a list instead of `str.split` 63 63 | "a " u"b".split() # ['a', 'b'] 64 64 | u"a " r"\n".split() # ['a', '\\n'] -SIM905.py:62:1: SIM905 [*] Consider using a list instead of `str.split` +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'] @@ -648,7 +648,7 @@ SIM905.py:62:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -658,7 +658,7 @@ SIM905.py:62:1: SIM905 [*] Consider using a list instead of `str.split` 64 64 | u"a " r"\n".split() # ['a', '\\n'] 65 65 | r"\n " u"\n".split() # ['\\n'] -SIM905.py:63:1: SIM905 [*] Consider using a list instead of `str.split` +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'] @@ -669,7 +669,7 @@ SIM905.py:63:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 60 60 | ("a " "b").split() # ['a', 'b'] 61 61 | "a " "b".split() # ['a', 'b'] 62 62 | u"a " "b".split() # ['a', 'b'] @@ -679,7 +679,7 @@ SIM905.py:63:1: SIM905 [*] Consider using a list instead of `str.split` 65 65 | r"\n " u"\n".split() # ['\\n'] 66 66 | r"\n " "\n".split() # ['\\n'] -SIM905.py:64:1: SIM905 [*] Consider using a list 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'] 63 | "a " u"b".split() # ['a', 'b'] @@ -690,7 +690,7 @@ SIM905.py:64:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -700,7 +700,7 @@ SIM905.py:64:1: SIM905 [*] Consider using a list instead of `str.split` 66 66 | r"\n " "\n".split() # ['\\n'] 67 67 | "a " r"\n".split() # ['a', '\\n'] -SIM905.py:65:1: SIM905 [*] Consider using a list 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'] 64 | u"a " r"\n".split() # ['a', '\\n'] @@ -711,7 +711,7 @@ SIM905.py:65:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -721,7 +721,7 @@ SIM905.py:65:1: SIM905 [*] Consider using a list instead of `str.split` 67 67 | "a " r"\n".split() # ['a', '\\n'] 68 68 | -SIM905.py:66:1: SIM905 [*] Consider using a list 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'] 65 | r"\n " u"\n".split() # ['\\n'] @@ -731,7 +731,7 @@ SIM905.py:66:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -741,7 +741,7 @@ SIM905.py:66:1: SIM905 [*] Consider using a list instead of `str.split` 68 68 | 69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] -SIM905.py:67:1: SIM905 [*] Consider using a list 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'] 66 | r"\n " "\n".split() # ['\\n'] @@ -752,7 +752,7 @@ SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -762,7 +762,7 @@ SIM905.py:67:1: SIM905 [*] Consider using a list instead of `str.split` 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 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'] 68 | @@ -773,7 +773,7 @@ SIM905.py:69:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 66 66 | r"\n " "\n".split() # ['\\n'] 67 67 | "a " r"\n".split() # ['a', '\\n'] 68 68 | @@ -783,7 +783,7 @@ SIM905.py:69:1: SIM905 [*] Consider using a list instead of `str.split` 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 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'] 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c'] @@ -793,7 +793,7 @@ SIM905.py:70:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ Safe fix 67 67 | "a " r"\n".split() # ['a', '\\n'] 68 68 | 69 69 | "a,b,c".split(',', maxsplit=0) # ['a,b,c'] @@ -803,7 +803,7 @@ SIM905.py:70:1: SIM905 [*] Consider using a list instead of `str.split` 72 72 | "a,b,c".split(',', maxsplit=-0) # ['a,b,c'] 73 73 | -SIM905.py:71:1: SIM905 [*] Consider using a list 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'] 70 | "a,b,c".split(',', maxsplit=-1) # ['a', 'b', 'c'] @@ -813,7 +813,7 @@ SIM905.py:71:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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'] @@ -823,7 +823,7 @@ SIM905.py:71:1: SIM905 [*] Consider using a list instead of `str.split` 73 73 | 74 74 | # negatives -SIM905.py:72:1: SIM905 [*] Consider using a list 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'] 71 | "a,b,c".split(',', maxsplit=-2) # ['a', 'b', 'c'] @@ -834,7 +834,7 @@ SIM905.py:72:1: SIM905 [*] Consider using a list instead of `str.split` | = help: Replace with list literal -ℹ Unsafe fix +ℹ 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']