From 721fd96460ed44faffaf0e4816a07ae0f40b41cb Mon Sep 17 00:00:00 2001 From: Simon Brugman Date: Wed, 30 Oct 2024 20:37:05 +0100 Subject: [PATCH] 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 | 165 +++++++++ ..._rules__ruff__tests__RUF035_RUF035.py.snap | 346 ++++++++++++++++++ ruff.schema.json | 1 + 8 files changed, 585 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 00000000000000..db361640811e6e --- /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 99deb3b9949980..1a2af6713c5ab6 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 caa4af3312fcc2..5789696b1654f5 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 84b7fd0d8ff7d9..77241802c8cd3a 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 49b40b0b7900dc..b5466c456070f5 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 00000000000000..66fb3f0efaa153 --- /dev/null +++ b/crates/ruff_linter/src/rules/ruff/rules/split_of_static_string.rs @@ -0,0 +1,165 @@ +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 00000000000000..f898dbcd2395aa --- /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 7412f47258ddaf..345fbefa3b5231 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3815,6 +3815,7 @@ "RUF032", "RUF033", "RUF034", + "RUF035", "RUF1", "RUF10", "RUF100",