diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py index f38ca1e8737ab..fa1cdc0e51c3e 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py @@ -1,13 +1,20 @@ x = set(x for x in range(3)) -x = set( - x for x in range(3) -) -y = f'{set(a if a < 6 else 0 for a in range(3))}' -_ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) -print(f'Hello {set(a for a in range(3))} World') +x = set(x for x in range(3)) +y = f"{set(a if a < 6 else 0 for a in range(3))}" +_ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +print(f"Hello {set(a for a in range(3))} World") + + +def f(x): + return x -def set(*args, **kwargs): - return None +print(f'Hello {set(a for a in "abc")} World') +print(f"Hello {set(a for a in 'abc')} World") +print(f"Hello {set(f(a) for a in 'abc')} World") +print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") -set(x for x in range(3)) +# The fix generated for this diagnostic is incorrect, as we add additional space +# around the set comprehension. +print(f"{ {set(a for a in 'abc')} }") diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py index 20db252700f48..736bdaff0c8b9 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py @@ -5,3 +5,14 @@ dict(((x, x) for x in range(3)), z=3) y = f'{dict((x, x) for x in range(3))}' print(f'Hello {dict((x, x) for x in range(3))} World') +print(f"Hello {dict((x, x) for x in 'abc')} World") +print(f'Hello {dict((x, x) for x in "abc")} World') +print(f'Hello {dict((x,x) for x in "abc")} World') + +f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + +def f(x): + return x + +print(f'Hello {dict((x,f(x)) for x in "abc")} World') diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py index 51e8179d8c6ed..993c31e32f8a2 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py @@ -2,3 +2,14 @@ s = set( [x for x in range(3)] ) + +s = f"{set([x for x in 'ab'])}" +s = f'{set([x for x in "ab"])}' + +def f(x): + return x + +s = f"{set([f(x) for x in 'ab'])}" + +s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py index 29134023b4424..a4a6d67bc96f7 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py @@ -1,2 +1,13 @@ dict([(i, i) for i in range(3)]) dict([(i, i) for i in range(3)], z=4) + +def f(x): + return x + +f'{dict([(s,s) for s in "ab"])}' +f"{dict([(s,s) for s in 'ab'])}" +f"{dict([(s, s) for s in 'ab'])}" +f"{dict([(s,f(s)) for s in 'ab'])}" + +f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py index 936e5e2622e61..9c250811b0044 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py @@ -16,3 +16,11 @@ set( [1,] ) +f"{set([1,2,3])}" +f"{set(['a', 'b'])}" +f'{set(["a", "b"])}' + +f"{set(['a', 'b']) - set(['a'])}" +f"{ set(['a', 'b']) - set(['a']) }" +f"a {set(['a', 'b']) - set(['a'])} b" +f"a { set(['a', 'b']) - set(['a']) } b" diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py index 6df251dfff444..81540af3654f5 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py @@ -10,3 +10,13 @@ def list(): a = list() + +f"{dict(x='y')}" +f'{dict(x="y")}' +f"{dict()}" +f"a {dict()} b" + +f"{dict(x='y') | dict(y='z')}" +f"{ dict(x='y') | dict(y='z') }" +f"a {dict(x='y') | dict(y='z')} b" +f"a { dict(x='y') | dict(y='z') } b" diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index bcbc31f92394c..200ea8171e89d 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -136,36 +136,36 @@ impl<'a> Checker<'a> { /// Create a [`Generator`] to generate source code based on the current AST state. pub(crate) fn generator(&self) -> Generator { - fn quote_style( - model: &SemanticModel, - locator: &Locator, - indexer: &Indexer, - ) -> Option { - if !model.in_f_string() { - return None; - } - - // Find the quote character used to start the containing f-string. - let expr = model.expr()?; - let string_range = indexer.f_string_range(expr.start())?; - let trailing_quote = trailing_quote(locator.slice(string_range))?; - - // Invert the quote character, if it's a single quote. - match *trailing_quote { - "'" => Some(Quote::Double), - "\"" => Some(Quote::Single), - _ => None, - } - } - Generator::new( self.stylist.indentation(), - quote_style(&self.semantic_model, self.locator, self.indexer) - .unwrap_or(self.stylist.quote()), + self.f_string_quote_style().unwrap_or(self.stylist.quote()), self.stylist.line_ending(), ) } + /// Returns the appropriate quoting for f-string by reversing the one used outside of + /// the f-string. + /// + /// If the current expression in the context is not an f-string, returns ``None``. + pub(crate) fn f_string_quote_style(&self) -> Option { + let model = &self.semantic_model; + if !model.in_f_string() { + return None; + } + + // Find the quote character used to start the containing f-string. + let expr = model.expr()?; + let string_range = self.indexer.f_string_range(expr.start())?; + let trailing_quote = trailing_quote(self.locator.slice(string_range))?; + + // Invert the quote character, if it's a single quote. + match *trailing_quote { + "'" => Some(Quote::Double), + "\"" => Some(Quote::Single), + _ => None, + } + } + /// Returns the [`IsolationLevel`] for fixes in the current context. /// /// The primary use-case for fix isolation is to ensure that we don't delete all statements @@ -2729,22 +2729,12 @@ where } if self.enabled(Rule::UnnecessaryGeneratorSet) { flake8_comprehensions::rules::unnecessary_generator_set( - self, - expr, - self.semantic_model.expr_parent(), - func, - args, - keywords, + self, expr, func, args, keywords, ); } if self.enabled(Rule::UnnecessaryGeneratorDict) { flake8_comprehensions::rules::unnecessary_generator_dict( - self, - expr, - self.semantic_model.expr_parent(), - func, - args, - keywords, + self, expr, func, args, keywords, ); } if self.enabled(Rule::UnnecessaryListComprehensionSet) { diff --git a/crates/ruff/src/rules/flake8_comprehensions/fixes.rs b/crates/ruff/src/rules/flake8_comprehensions/fixes.rs index b10156a39ae52..ed2ba3ada3a8c 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/fixes.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/fixes.rs @@ -7,15 +7,19 @@ use libcst_native::{ RightParen, RightSquareBracket, Set, SetComp, SimpleString, SimpleWhitespace, TrailingWhitespace, Tuple, }; +use ruff_text_size::TextRange; use rustpython_parser::ast::Ranged; -use crate::autofix::codemods::CodegenStylist; use ruff_diagnostics::{Edit, Fix}; use ruff_python_ast::source_code::{Locator, Stylist}; -use crate::cst::matchers::{ - match_arg, match_call, match_call_mut, match_expression, match_generator_exp, match_lambda, - match_list_comp, match_name, match_tuple, +use crate::autofix::codemods::CodegenStylist; +use crate::{ + checkers::ast::Checker, + cst::matchers::{ + match_arg, match_call, match_call_mut, match_expression, match_generator_exp, match_lambda, + match_list_comp, match_name, match_tuple, + }, }; /// (C400) Convert `list(x for x in y)` to `[x for x in y]`. @@ -53,11 +57,12 @@ pub(crate) fn fix_unnecessary_generator_list( /// (C401) Convert `set(x for x in y)` to `{x for x in y}`. pub(crate) fn fix_unnecessary_generator_set( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, - parent: Option<&rustpython_parser::ast::Expr>, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; + // Expr(Call(GeneratorExp)))) -> Expr(SetComp))) let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; @@ -79,25 +84,23 @@ pub(crate) fn fix_unnecessary_generator_set( rpar: generator_exp.rpar.clone(), })); - let mut content = tree.codegen_stylist(stylist); - - // If the expression is embedded in an f-string, surround it with spaces to avoid - // syntax errors. - if let Some(rustpython_parser::ast::Expr::FormattedValue(_)) = parent { - content = format!(" {content} "); - } + let content = tree.codegen_stylist(stylist); - Ok(Edit::range_replacement(content, expr.range())) + Ok(Edit::range_replacement( + pad_expression(content, expr.range(), checker), + expr.range(), + )) } /// (C402) Convert `dict((x, x) for x in range(3))` to `{x: x for x in /// range(3)}`. pub(crate) fn fix_unnecessary_generator_dict( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, - parent: Option<&rustpython_parser::ast::Expr>, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; + let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; let call = match_call_mut(&mut tree)?; @@ -126,23 +129,19 @@ pub(crate) fn fix_unnecessary_generator_dict( whitespace_after_colon: ParenthesizableWhitespace::SimpleWhitespace(SimpleWhitespace(" ")), })); - let mut content = tree.codegen_stylist(stylist); - - // If the expression is embedded in an f-string, surround it with spaces to avoid - // syntax errors. - if let Some(rustpython_parser::ast::Expr::FormattedValue(_)) = parent { - content = format!(" {content} "); - } - - Ok(Edit::range_replacement(content, expr.range())) + Ok(Edit::range_replacement( + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker), + expr.range(), + )) } /// (C403) Convert `set([x for x in y])` to `{x for x in y}`. pub(crate) fn fix_unnecessary_list_comprehension_set( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; // Expr(Call(ListComp)))) -> // Expr(SetComp))) let module_text = locator.slice(expr.range()); @@ -166,7 +165,7 @@ pub(crate) fn fix_unnecessary_list_comprehension_set( })); Ok(Edit::range_replacement( - tree.codegen_stylist(stylist), + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker), expr.range(), )) } @@ -174,10 +173,12 @@ pub(crate) fn fix_unnecessary_list_comprehension_set( /// (C404) Convert `dict([(i, i) for i in range(3)])` to `{i: i for i in /// range(3)}`. pub(crate) fn fix_unnecessary_list_comprehension_dict( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; + let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; let call = match_call_mut(&mut tree)?; @@ -188,16 +189,15 @@ pub(crate) fn fix_unnecessary_list_comprehension_dict( let tuple = match_tuple(&list_comp.elt)?; let [Element::Simple { - value: key, - comma: Some(comma), + value: key, .. }, Element::Simple { value, .. }] = &tuple.elements[..] else { bail!("Expected tuple with two elements"); }; tree = Expression::DictComp(Box::new(DictComp { key: Box::new(key.clone()), value: Box::new(value.clone()), for_in: list_comp.for_in.clone(), - whitespace_before_colon: comma.whitespace_before.clone(), - whitespace_after_colon: comma.whitespace_after.clone(), + whitespace_before_colon: ParenthesizableWhitespace::default(), + whitespace_after_colon: ParenthesizableWhitespace::SimpleWhitespace(SimpleWhitespace(" ")), lbrace: LeftCurlyBrace { whitespace_after: call.whitespace_before_args.clone(), }, @@ -209,7 +209,7 @@ pub(crate) fn fix_unnecessary_list_comprehension_dict( })); Ok(Edit::range_replacement( - tree.codegen_stylist(stylist), + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker), expr.range(), )) } @@ -259,10 +259,12 @@ fn drop_trailing_comma<'a>( /// (C405) Convert `set((1, 2))` to `{1, 2}`. pub(crate) fn fix_unnecessary_literal_set( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; + // Expr(Call(List|Tuple)))) -> Expr(Set))) let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; @@ -294,17 +296,19 @@ pub(crate) fn fix_unnecessary_literal_set( } Ok(Edit::range_replacement( - tree.codegen_stylist(stylist), + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker), expr.range(), )) } /// (C406) Convert `dict([(1, 2)])` to `{1: 2}`. pub(crate) fn fix_unnecessary_literal_dict( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + let locator = checker.locator; + let stylist = checker.stylist; + // Expr(Call(List|Tuple)))) -> Expr(Dict))) let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; @@ -358,36 +362,50 @@ pub(crate) fn fix_unnecessary_literal_dict( })); Ok(Edit::range_replacement( - tree.codegen_stylist(stylist), + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker), expr.range(), )) } /// (C408) pub(crate) fn fix_unnecessary_collection_call( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + enum Collection { + Tuple, + List, + Dict, + } + + let locator = checker.locator; + let stylist = checker.stylist; + // Expr(Call("list" | "tuple" | "dict")))) -> Expr(List|Tuple|Dict) let module_text = locator.slice(expr.range()); let mut tree = match_expression(module_text)?; - let call = match_call_mut(&mut tree)?; + let call = match_call(&tree)?; let name = match_name(&call.func)?; + let collection = match name.value { + "tuple" => Collection::Tuple, + "list" => Collection::List, + "dict" => Collection::Dict, + _ => bail!("Expected 'tuple', 'list', or 'dict'"), + }; // Arena allocator used to create formatted strings of sufficient lifetime, // below. let mut arena: Vec = vec![]; - match name.value { - "tuple" => { + match collection { + Collection::Tuple => { tree = Expression::Tuple(Box::new(Tuple { elements: vec![], lpar: vec![LeftParen::default()], rpar: vec![RightParen::default()], })); } - "list" => { + Collection::List => { tree = Expression::List(Box::new(List { elements: vec![], lbracket: LeftSquareBracket::default(), @@ -396,7 +414,7 @@ pub(crate) fn fix_unnecessary_collection_call( rpar: vec![], })); } - "dict" => { + Collection::Dict => { if call.args.is_empty() { tree = Expression::Dict(Box::new(Dict { elements: vec![], @@ -406,16 +424,18 @@ pub(crate) fn fix_unnecessary_collection_call( rpar: vec![], })); } else { + let quote = checker.f_string_quote_style().unwrap_or(stylist.quote()); + // Quote each argument. for arg in &call.args { let quoted = format!( "{}{}{}", - stylist.quote(), + quote, arg.keyword .as_ref() .expect("Expected dictionary argument to be kwarg") .value, - stylist.quote(), + quote, ); arena.push(quoted); } @@ -457,17 +477,56 @@ pub(crate) fn fix_unnecessary_collection_call( })); } } - _ => { - bail!("Expected function name to be one of: 'tuple', 'list', 'dict'"); - } }; Ok(Edit::range_replacement( - tree.codegen_stylist(stylist), + if matches!(collection, Collection::Dict) { + pad_expression(tree.codegen_stylist(stylist), expr.range(), checker) + } else { + tree.codegen_stylist(stylist) + }, expr.range(), )) } +/// Re-formats the given expression for use within a formatted string. +/// +/// For example, when converting a `dict` call to a dictionary literal within +/// a formatted string, we might naively generate the following code: +/// +/// ```python +/// f"{{'a': 1, 'b': 2}}" +/// ``` +/// +/// However, this is a syntax error under the f-string grammar. As such, +/// this method will pad the start and end of an expression as needed to +/// avoid producing invalid syntax. +fn pad_expression(content: String, range: TextRange, checker: &Checker) -> String { + if !checker.semantic_model().in_f_string() { + return content; + } + + // If the expression is immediately preceded by an opening brace, then + // we need to add a space before the expression. + let prefix = checker.locator.up_to(range.start()); + let left_pad = matches!(prefix.chars().rev().next(), Some('{')); + + // If the expression is immediately preceded by an opening brace, then + // we need to add a space before the expression. + let suffix = checker.locator.after(range.end()); + let right_pad = matches!(suffix.chars().next(), Some('}')); + + if left_pad && right_pad { + format!(" {content} ") + } else if left_pad { + format!(" {content}") + } else if right_pad { + format!("{content} ") + } else { + content + } +} + /// (C409) Convert `tuple([1, 2])` to `tuple(1, 2)` pub(crate) fn fix_unnecessary_literal_within_tuple_call( locator: &Locator, diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs index e559d50bb3a56..23ca342702bc8 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_collection_call.rs @@ -90,9 +90,7 @@ pub(crate) fn unnecessary_collection_call( ); if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] - diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_collection_call(checker.locator, checker.stylist, expr) - }); + diagnostic.try_set_fix_from_edit(|| fixes::fix_unnecessary_collection_call(checker, expr)); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs index 9b337ea8fd325..030eff86d30fd 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_dict.rs @@ -45,7 +45,6 @@ impl AlwaysAutofixableViolation for UnnecessaryGeneratorDict { pub(crate) fn unnecessary_generator_dict( checker: &mut Checker, expr: &Expr, - parent: Option<&Expr>, func: &Expr, args: &[Expr], keywords: &[Keyword], @@ -60,12 +59,7 @@ pub(crate) fn unnecessary_generator_dict( if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_generator_dict( - checker.locator, - checker.stylist, - expr, - parent, - ) + fixes::fix_unnecessary_generator_dict(checker, expr) }); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs index 7f7cf83be2453..345a6c0f91e6e 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_generator_set.rs @@ -45,7 +45,6 @@ impl AlwaysAutofixableViolation for UnnecessaryGeneratorSet { pub(crate) fn unnecessary_generator_set( checker: &mut Checker, expr: &Expr, - parent: Option<&Expr>, func: &Expr, args: &[Expr], keywords: &[Keyword], @@ -60,9 +59,8 @@ pub(crate) fn unnecessary_generator_set( let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range()); if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] - diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_generator_set(checker.locator, checker.stylist, expr, parent) - }); + diagnostic + .try_set_fix_from_edit(|| fixes::fix_unnecessary_generator_set(checker, expr)); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs index 9c6f87873bb4b..e30434bbe3874 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs @@ -66,7 +66,7 @@ pub(crate) fn unnecessary_list_comprehension_dict( if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_list_comprehension_dict(checker.locator, checker.stylist, expr) + fixes::fix_unnecessary_list_comprehension_dict(checker, expr) }); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs index b6dc24823ca19..8506e71249500 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs @@ -58,11 +58,7 @@ pub(crate) fn unnecessary_list_comprehension_set( if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_list_comprehension_set( - checker.locator, - checker.stylist, - expr, - ) + fixes::fix_unnecessary_list_comprehension_set(checker, expr) }); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs index 5ba588870b423..370bedf38fe70 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_dict.rs @@ -80,9 +80,7 @@ pub(crate) fn unnecessary_literal_dict( ); if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] - diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_literal_dict(checker.locator, checker.stylist, expr) - }); + diagnostic.try_set_fix_from_edit(|| fixes::fix_unnecessary_literal_dict(checker, expr)); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs index 86c126dd5a7b2..9519109ac95f7 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs @@ -74,9 +74,7 @@ pub(crate) fn unnecessary_literal_set( ); if checker.patch(diagnostic.kind.rule()) { #[allow(deprecated)] - diagnostic.try_set_fix_from_edit(|| { - fixes::fix_unnecessary_literal_set(checker.locator, checker.stylist, expr) - }); + diagnostic.try_set_fix_from_edit(|| fixes::fix_unnecessary_literal_set(checker, expr)); } checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C401_C401.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C401_C401.py.snap index 57831d19dee14..4ff2ea47a2958 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C401_C401.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C401_C401.py.snap @@ -5,102 +5,251 @@ C401.py:1:5: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) | 1 | x = set(x for x in range(3)) | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 -2 | x = set( -3 | x for x in range(3) +2 | x = set(x for x in range(3)) +3 | y = f"{set(a if a < 6 else 0 for a in range(3))}" | = help: Rewrite as a `set` comprehension ℹ Suggested fix 1 |-x = set(x for x in range(3)) 1 |+x = {x for x in range(3)} -2 2 | x = set( -3 3 | x for x in range(3) -4 4 | ) +2 2 | x = set(x for x in range(3)) +3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +4 4 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) C401.py:2:5: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) | -2 | x = set(x for x in range(3)) -3 | x = set( - | _____^ -4 | | x for x in range(3) -5 | | ) - | |_^ C401 -6 | y = f'{set(a if a < 6 else 0 for a in range(3))}' -7 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) +2 | x = set(x for x in range(3)) +3 | x = set(x for x in range(3)) + | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 +4 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +5 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) | = help: Rewrite as a `set` comprehension ℹ Suggested fix 1 1 | x = set(x for x in range(3)) -2 |-x = set( - 2 |+x = { -3 3 | x for x in range(3) -4 |-) - 4 |+} -5 5 | y = f'{set(a if a < 6 else 0 for a in range(3))}' -6 6 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) -7 7 | print(f'Hello {set(a for a in range(3))} World') - -C401.py:5:8: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) +2 |-x = set(x for x in range(3)) + 2 |+x = {x for x in range(3)} +3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +4 4 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +5 5 | print(f"Hello {set(a for a in range(3))} World") + +C401.py:3:8: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) | -5 | x for x in range(3) -6 | ) -7 | y = f'{set(a if a < 6 else 0 for a in range(3))}' +3 | x = set(x for x in range(3)) +4 | x = set(x for x in range(3)) +5 | y = f"{set(a if a < 6 else 0 for a in range(3))}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C401 -8 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) -9 | print(f'Hello {set(a for a in range(3))} World') +6 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +7 | print(f"Hello {set(a for a in range(3))} World") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +1 1 | x = set(x for x in range(3)) +2 2 | x = set(x for x in range(3)) +3 |-y = f"{set(a if a < 6 else 0 for a in range(3))}" + 3 |+y = f"{ {a if a < 6 else 0 for a in range(3)} }" +4 4 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +5 5 | print(f"Hello {set(a for a in range(3))} World") +6 6 | + +C401.py:4:17: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +4 | x = set(x for x in range(3)) +5 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +6 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C401 +7 | print(f"Hello {set(a for a in range(3))} World") | = help: Rewrite as a `set` comprehension ℹ Suggested fix -2 2 | x = set( -3 3 | x for x in range(3) -4 4 | ) -5 |-y = f'{set(a if a < 6 else 0 for a in range(3))}' - 5 |+y = f'{ {a if a < 6 else 0 for a in range(3)} }' -6 6 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) -7 7 | print(f'Hello {set(a for a in range(3))} World') -8 8 | - -C401.py:6:17: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) +1 1 | x = set(x for x in range(3)) +2 2 | x = set(x for x in range(3)) +3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +4 |-_ = "{}".format(set(a if a < 6 else 0 for a in range(3))) + 4 |+_ = "{}".format({a if a < 6 else 0 for a in range(3)}) +5 5 | print(f"Hello {set(a for a in range(3))} World") +6 6 | +7 7 | + +C401.py:5:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) | -6 | ) -7 | y = f'{set(a if a < 6 else 0 for a in range(3))}' -8 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C401 -9 | print(f'Hello {set(a for a in range(3))} World') +5 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +6 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +7 | print(f"Hello {set(a for a in range(3))} World") + | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 | = help: Rewrite as a `set` comprehension ℹ Suggested fix -3 3 | x for x in range(3) -4 4 | ) -5 5 | y = f'{set(a if a < 6 else 0 for a in range(3))}' -6 |-_ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) - 6 |+_ = '{}'.format({a if a < 6 else 0 for a in range(3)}) -7 7 | print(f'Hello {set(a for a in range(3))} World') -8 8 | -9 9 | def set(*args, **kwargs): - -C401.py:7:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) - | - 7 | y = f'{set(a if a < 6 else 0 for a in range(3))}' - 8 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) - 9 | print(f'Hello {set(a for a in range(3))} World') +2 2 | x = set(x for x in range(3)) +3 3 | y = f"{set(a if a < 6 else 0 for a in range(3))}" +4 4 | _ = "{}".format(set(a if a < 6 else 0 for a in range(3))) +5 |-print(f"Hello {set(a for a in range(3))} World") + 5 |+print(f"Hello { {a for a in range(3)} } World") +6 6 | +7 7 | +8 8 | def f(x): + +C401.py:12:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +12 | print(f'Hello {set(a for a in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^ C401 +13 | print(f"Hello {set(a for a in 'abc')} World") +14 | print(f"Hello {set(f(a) for a in 'abc')} World") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +9 9 | return x +10 10 | +11 11 | +12 |-print(f'Hello {set(a for a in "abc")} World') + 12 |+print(f'Hello { {a for a in "abc"} } World') +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + +C401.py:13:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +13 | print(f'Hello {set(a for a in "abc")} World') +14 | print(f"Hello {set(a for a in 'abc')} World") + | ^^^^^^^^^^^^^^^^^^^^^ C401 +15 | print(f"Hello {set(f(a) for a in 'abc')} World") +16 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +10 10 | +11 11 | +12 12 | print(f'Hello {set(a for a in "abc")} World') +13 |-print(f"Hello {set(a for a in 'abc')} World") + 13 |+print(f"Hello { {a for a in 'abc'} } World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +16 16 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + +C401.py:14:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +14 | print(f'Hello {set(a for a in "abc")} World') +15 | print(f"Hello {set(a for a in 'abc')} World") +16 | print(f"Hello {set(f(a) for a in 'abc')} World") | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 -10 | -11 | def set(*args, **kwargs): +17 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +18 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +11 11 | +12 12 | print(f'Hello {set(a for a in "abc")} World') +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 |-print(f"Hello {set(f(a) for a in 'abc')} World") + 14 |+print(f"Hello { {f(a) for a in 'abc'} } World") +15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +16 16 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") +17 17 | + +C401.py:15:10: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +15 | print(f"Hello {set(a for a in 'abc')} World") +16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + | ^^^^^^^^^^^^^^^^^^^^^ C401 +18 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +12 12 | print(f'Hello {set(a for a in "abc")} World') +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 |-print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + 15 |+print(f"{ {a for a in 'abc'} - set(a for a in 'ab')}") +16 16 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") +17 17 | +18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space + +C401.py:15:34: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +15 | print(f"Hello {set(a for a in 'abc')} World") +16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + | ^^^^^^^^^^^^^^^^^^^^ C401 +18 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +12 12 | print(f'Hello {set(a for a in "abc")} World') +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 |-print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") + 15 |+print(f"{set(a for a in 'abc') - {a for a in 'ab'} }") +16 16 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") +17 17 | +18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space + +C401.py:16:11: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +18 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + | ^^^^^^^^^^^^^^^^^^^^^ C401 +19 | +20 | # The fix generated for this diagnostic is incorrect, as we add additional space + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +16 |-print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + 16 |+print(f"{ {a for a in 'abc'} - set(a for a in 'ab') }") +17 17 | +18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space +19 19 | # around the set comprehension. + +C401.py:16:35: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +18 | print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + | ^^^^^^^^^^^^^^^^^^^^ C401 +19 | +20 | # The fix generated for this diagnostic is incorrect, as we add additional space + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +13 13 | print(f"Hello {set(a for a in 'abc')} World") +14 14 | print(f"Hello {set(f(a) for a in 'abc')} World") +15 15 | print(f"{set(a for a in 'abc') - set(a for a in 'ab')}") +16 |-print(f"{ set(a for a in 'abc') - set(a for a in 'ab') }") + 16 |+print(f"{ set(a for a in 'abc') - {a for a in 'ab'} }") +17 17 | +18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space +19 19 | # around the set comprehension. + +C401.py:20:12: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +20 | # The fix generated for this diagnostic is incorrect, as we add additional space +21 | # around the set comprehension. +22 | print(f"{ {set(a for a in 'abc')} }") + | ^^^^^^^^^^^^^^^^^^^^^ C401 | = help: Rewrite as a `set` comprehension ℹ Suggested fix -4 4 | ) -5 5 | y = f'{set(a if a < 6 else 0 for a in range(3))}' -6 6 | _ = '{}'.format(set(a if a < 6 else 0 for a in range(3))) -7 |-print(f'Hello {set(a for a in range(3))} World') - 7 |+print(f'Hello { {a for a in range(3)} } World') -8 8 | -9 9 | def set(*args, **kwargs): -10 10 | return None +17 17 | +18 18 | # The fix generated for this diagnostic is incorrect, as we add additional space +19 19 | # around the set comprehension. +20 |-print(f"{ {set(a for a in 'abc')} }") + 20 |+print(f"{ { {a for a in 'abc'} } }") diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C402_C402.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C402_C402.py.snap index 4f128f605f67a..55df5669495bb 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C402_C402.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C402_C402.py.snap @@ -42,14 +42,15 @@ C402.py:2:1: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) 7 7 | print(f'Hello {dict((x, x) for x in range(3))} World') C402.py:6:8: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) - | -6 | ) -7 | dict(((x, x) for x in range(3)), z=3) -8 | y = f'{dict((x, x) for x in range(3))}' - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 -9 | print(f'Hello {dict((x, x) for x in range(3))} World') - | - = help: Rewrite as a `dict` comprehension + | + 6 | ) + 7 | dict(((x, x) for x in range(3)), z=3) + 8 | y = f'{dict((x, x) for x in range(3))}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 + 9 | print(f'Hello {dict((x, x) for x in range(3))} World') +10 | print(f"Hello {dict((x, x) for x in 'abc')} World") + | + = help: Rewrite as a `dict` comprehension ℹ Suggested fix 3 3 | (x, x) for x in range(3) @@ -58,15 +59,19 @@ C402.py:6:8: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) 6 |-y = f'{dict((x, x) for x in range(3))}' 6 |+y = f'{ {x: x for x in range(3)} }' 7 7 | print(f'Hello {dict((x, x) for x in range(3))} World') +8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World") +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') C402.py:7:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) - | -7 | dict(((x, x) for x in range(3)), z=3) -8 | y = f'{dict((x, x) for x in range(3))}' -9 | print(f'Hello {dict((x, x) for x in range(3))} World') - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 - | - = help: Rewrite as a `dict` comprehension + | + 7 | dict(((x, x) for x in range(3)), z=3) + 8 | y = f'{dict((x, x) for x in range(3))}' + 9 | print(f'Hello {dict((x, x) for x in range(3))} World') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +10 | print(f"Hello {dict((x, x) for x in 'abc')} World") +11 | print(f'Hello {dict((x, x) for x in "abc")} World') + | + = help: Rewrite as a `dict` comprehension ℹ Suggested fix 4 4 | ) @@ -74,5 +79,166 @@ C402.py:7:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) 6 6 | y = f'{dict((x, x) for x in range(3))}' 7 |-print(f'Hello {dict((x, x) for x in range(3))} World') 7 |+print(f'Hello { {x: x for x in range(3)} } World') +8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World") +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') + +C402.py:8:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | + 8 | y = f'{dict((x, x) for x in range(3))}' + 9 | print(f'Hello {dict((x, x) for x in range(3))} World') +10 | print(f"Hello {dict((x, x) for x in 'abc')} World") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +11 | print(f'Hello {dict((x, x) for x in "abc")} World') +12 | print(f'Hello {dict((x,x) for x in "abc")} World') + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +5 5 | dict(((x, x) for x in range(3)), z=3) +6 6 | y = f'{dict((x, x) for x in range(3))}' +7 7 | print(f'Hello {dict((x, x) for x in range(3))} World') +8 |-print(f"Hello {dict((x, x) for x in 'abc')} World") + 8 |+print(f"Hello { {x: x for x in 'abc'} } World") +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | + +C402.py:9:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | + 9 | print(f'Hello {dict((x, x) for x in range(3))} World') +10 | print(f"Hello {dict((x, x) for x in 'abc')} World") +11 | print(f'Hello {dict((x, x) for x in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +12 | print(f'Hello {dict((x,x) for x in "abc")} World') + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +6 6 | y = f'{dict((x, x) for x in range(3))}' +7 7 | print(f'Hello {dict((x, x) for x in range(3))} World') +8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World") +9 |-print(f'Hello {dict((x, x) for x in "abc")} World') + 9 |+print(f'Hello { {x: x for x in "abc"} } World') +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | +12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + +C402.py:10:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +10 | print(f"Hello {dict((x, x) for x in 'abc')} World") +11 | print(f'Hello {dict((x, x) for x in "abc")} World') +12 | print(f'Hello {dict((x,x) for x in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +13 | +14 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +7 7 | print(f'Hello {dict((x, x) for x in range(3))} World') +8 8 | print(f"Hello {dict((x, x) for x in 'abc')} World") +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') +10 |-print(f'Hello {dict((x,x) for x in "abc")} World') + 10 |+print(f'Hello { {x: x for x in "abc"} } World') +11 11 | +12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +13 13 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + +C402.py:12:4: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +12 | print(f'Hello {dict((x,x) for x in "abc")} World') +13 | +14 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +15 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | +12 |-f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + 12 |+f'{ {x: x for x in range(3)} | dict((x, x) for x in range(3))}' +13 13 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' +14 14 | +15 15 | def f(x): + +C402.py:12:37: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +12 | print(f'Hello {dict((x,x) for x in "abc")} World') +13 | +14 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +15 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +9 9 | print(f'Hello {dict((x, x) for x in "abc")} World') +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | +12 |-f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' + 12 |+f'{dict((x, x) for x in range(3)) | {x: x for x in range(3)} }' +13 13 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' +14 14 | +15 15 | def f(x): + +C402.py:13:5: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +13 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +14 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +15 | +16 | def f(x): + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | +12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +13 |-f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + 13 |+f'{ {x: x for x in range(3)} | dict((x, x) for x in range(3)) }' +14 14 | +15 15 | def f(x): +16 16 | return x + +C402.py:13:38: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +13 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +14 | f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 +15 | +16 | def f(x): + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +10 10 | print(f'Hello {dict((x,x) for x in "abc")} World') +11 11 | +12 12 | f'{dict((x, x) for x in range(3)) | dict((x, x) for x in range(3))}' +13 |-f'{ dict((x, x) for x in range(3)) | dict((x, x) for x in range(3)) }' + 13 |+f'{ dict((x, x) for x in range(3)) | {x: x for x in range(3)} }' +14 14 | +15 15 | def f(x): +16 16 | return x + +C402.py:18:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +18 | return x +19 | +20 | print(f'Hello {dict((x,f(x)) for x in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +15 15 | def f(x): +16 16 | return x +17 17 | +18 |-print(f'Hello {dict((x,f(x)) for x in "abc")} World') + 18 |+print(f'Hello { {x: f(x) for x in "abc"} } World') diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C403_C403.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C403_C403.py.snap index 67c813847412b..5dc14f4289ec1 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C403_C403.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C403_C403.py.snap @@ -25,6 +25,8 @@ C403.py:2:5: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr 4 | | [x for x in range(3)] 5 | | ) | |_^ C403 +6 | +7 | s = f"{set([x for x in 'ab'])}" | = help: Rewrite as a `set` comprehension @@ -36,5 +38,135 @@ C403.py:2:5: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` compr 2 |+s = { 3 |+ x for x in range(3) 4 |+} +5 5 | +6 6 | s = f"{set([x for x in 'ab'])}" +7 7 | s = f'{set([x for x in "ab"])}' + +C403.py:6:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +6 | ) +7 | +8 | s = f"{set([x for x in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^ C403 +9 | s = f'{set([x for x in "ab"])}' + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +3 3 | [x for x in range(3)] +4 4 | ) +5 5 | +6 |-s = f"{set([x for x in 'ab'])}" + 6 |+s = f"{ {x for x in 'ab'} }" +7 7 | s = f'{set([x for x in "ab"])}' +8 8 | +9 9 | def f(x): + +C403.py:7:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | + 7 | s = f"{set([x for x in 'ab'])}" + 8 | s = f'{set([x for x in "ab"])}' + | ^^^^^^^^^^^^^^^^^^^^^^ C403 + 9 | +10 | def f(x): + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +4 4 | ) +5 5 | +6 6 | s = f"{set([x for x in 'ab'])}" +7 |-s = f'{set([x for x in "ab"])}' + 7 |+s = f'{ {x for x in "ab"} }' +8 8 | +9 9 | def f(x): +10 10 | return x + +C403.py:12:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +12 | return x +13 | +14 | s = f"{set([f(x) for x in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^ C403 +15 | +16 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +9 9 | def f(x): +10 10 | return x +11 11 | +12 |-s = f"{set([f(x) for x in 'ab'])}" + 12 |+s = f"{ {f(x) for x in 'ab'} }" +13 13 | +14 14 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +15 15 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + +C403.py:14:9: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +14 | s = f"{set([f(x) for x in 'ab'])}" +15 | +16 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" + | ^^^^^^^^^^^^^^^^^^^^^^ C403 +17 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +11 11 | +12 12 | s = f"{set([f(x) for x in 'ab'])}" +13 13 | +14 |-s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" + 14 |+s = f"{ {x for x in 'ab'} | set([x for x in 'ab']) }" +15 15 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + +C403.py:14:34: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +14 | s = f"{set([f(x) for x in 'ab'])}" +15 | +16 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" + | ^^^^^^^^^^^^^^^^^^^^^^ C403 +17 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +11 11 | +12 12 | s = f"{set([f(x) for x in 'ab'])}" +13 13 | +14 |-s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" + 14 |+s = f"{ set([x for x in 'ab']) | {x for x in 'ab'} }" +15 15 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + +C403.py:15:8: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +15 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +16 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^ C403 + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +12 12 | s = f"{set([f(x) for x in 'ab'])}" +13 13 | +14 14 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +15 |-s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + 15 |+s = f"{ {x for x in 'ab'} | set([x for x in 'ab'])}" + +C403.py:15:33: C403 [*] Unnecessary `list` comprehension (rewrite as a `set` comprehension) + | +15 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +16 | s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^ C403 + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +12 12 | s = f"{set([f(x) for x in 'ab'])}" +13 13 | +14 14 | s = f"{ set([x for x in 'ab']) | set([x for x in 'ab']) }" +15 |-s = f"{set([x for x in 'ab']) | set([x for x in 'ab'])}" + 15 |+s = f"{set([x for x in 'ab']) | {x for x in 'ab'} }" diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C404_C404.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C404_C404.py.snap index c8a543333bde8..08b060fec96ad 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C404_C404.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C404_C404.py.snap @@ -13,5 +13,155 @@ C404.py:1:1: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comp 1 |-dict([(i, i) for i in range(3)]) 1 |+{i: i for i in range(3)} 2 2 | dict([(i, i) for i in range(3)], z=4) +3 3 | +4 4 | def f(x): + +C404.py:7:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | + 7 | return x + 8 | + 9 | f'{dict([(s,s) for s in "ab"])}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +10 | f"{dict([(s,s) for s in 'ab'])}" +11 | f"{dict([(s, s) for s in 'ab'])}" + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +4 4 | def f(x): +5 5 | return x +6 6 | +7 |-f'{dict([(s,s) for s in "ab"])}' + 7 |+f'{ {s: s for s in "ab"} }' +8 8 | f"{dict([(s,s) for s in 'ab'])}" +9 9 | f"{dict([(s, s) for s in 'ab'])}" +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" + +C404.py:8:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | + 8 | f'{dict([(s,s) for s in "ab"])}' + 9 | f"{dict([(s,s) for s in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +10 | f"{dict([(s, s) for s in 'ab'])}" +11 | f"{dict([(s,f(s)) for s in 'ab'])}" + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +5 5 | return x +6 6 | +7 7 | f'{dict([(s,s) for s in "ab"])}' +8 |-f"{dict([(s,s) for s in 'ab'])}" + 8 |+f"{ {s: s for s in 'ab'} }" +9 9 | f"{dict([(s, s) for s in 'ab'])}" +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | + +C404.py:9:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | + 9 | f'{dict([(s,s) for s in "ab"])}' +10 | f"{dict([(s,s) for s in 'ab'])}" +11 | f"{dict([(s, s) for s in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +12 | f"{dict([(s,f(s)) for s in 'ab'])}" + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +6 6 | +7 7 | f'{dict([(s,s) for s in "ab"])}' +8 8 | f"{dict([(s,s) for s in 'ab'])}" +9 |-f"{dict([(s, s) for s in 'ab'])}" + 9 |+f"{ {s: s for s in 'ab'} }" +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | +12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + +C404.py:10:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | +10 | f"{dict([(s,s) for s in 'ab'])}" +11 | f"{dict([(s, s) for s in 'ab'])}" +12 | f"{dict([(s,f(s)) for s in 'ab'])}" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +13 | +14 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +7 7 | f'{dict([(s,s) for s in "ab"])}' +8 8 | f"{dict([(s,s) for s in 'ab'])}" +9 9 | f"{dict([(s, s) for s in 'ab'])}" +10 |-f"{dict([(s,f(s)) for s in 'ab'])}" + 10 |+f"{ {s: f(s) for s in 'ab'} }" +11 11 | +12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +13 13 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + +C404.py:12:4: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | +12 | f"{dict([(s,f(s)) for s in 'ab'])}" +13 | +14 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +15 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +9 9 | f"{dict([(s, s) for s in 'ab'])}" +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | +12 |-f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + 12 |+f'{ {s: s for s in "ab"} | dict([(s,s) for s in "ab"])}' +13 13 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + +C404.py:12:34: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | +12 | f"{dict([(s,f(s)) for s in 'ab'])}" +13 | +14 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 +15 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +9 9 | f"{dict([(s, s) for s in 'ab'])}" +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | +12 |-f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' + 12 |+f'{dict([(s,s) for s in "ab"]) | {s: s for s in "ab"} }' +13 13 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + +C404.py:13:5: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | +13 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +14 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | +12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +13 |-f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + 13 |+f'{ {s: s for s in "ab"} | dict([(s,s) for s in "ab"]) }' + +C404.py:13:35: C404 [*] Unnecessary `list` comprehension (rewrite as a `dict` comprehension) + | +13 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +14 | f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C404 + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +10 10 | f"{dict([(s,f(s)) for s in 'ab'])}" +11 11 | +12 12 | f'{dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"])}' +13 |-f'{ dict([(s,s) for s in "ab"]) | dict([(s,s) for s in "ab"]) }' + 13 |+f'{ dict([(s,s) for s in "ab"]) | {s: s for s in "ab"} }' diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C405_C405.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C405_C405.py.snap index e418bb820e599..8878b7e47c6d4 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C405_C405.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C405_C405.py.snap @@ -183,6 +183,8 @@ C405.py:16:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) 19 | | [1,] 20 | | ) | |_^ C405 +21 | f"{set([1,2,3])}" +22 | f"{set(['a', 'b'])}" | = help: Rewrite as a `set` literal @@ -194,5 +196,218 @@ C405.py:16:1: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) 17 |- [1,] 18 |-) 16 |+{1,} +19 17 | f"{set([1,2,3])}" +20 18 | f"{set(['a', 'b'])}" +21 19 | f'{set(["a", "b"])}' + +C405.py:19:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +19 | [1,] +20 | ) +21 | f"{set([1,2,3])}" + | ^^^^^^^^^^^^ C405 +22 | f"{set(['a', 'b'])}" +23 | f'{set(["a", "b"])}' + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +16 16 | set( +17 17 | [1,] +18 18 | ) +19 |-f"{set([1,2,3])}" + 19 |+f"{ {1,2,3} }" +20 20 | f"{set(['a', 'b'])}" +21 21 | f'{set(["a", "b"])}' +22 22 | + +C405.py:20:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +20 | ) +21 | f"{set([1,2,3])}" +22 | f"{set(['a', 'b'])}" + | ^^^^^^^^^^^^^^^ C405 +23 | f'{set(["a", "b"])}' + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +17 17 | [1,] +18 18 | ) +19 19 | f"{set([1,2,3])}" +20 |-f"{set(['a', 'b'])}" + 20 |+f"{ {'a', 'b'} }" +21 21 | f'{set(["a", "b"])}' +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" + +C405.py:21:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +21 | f"{set([1,2,3])}" +22 | f"{set(['a', 'b'])}" +23 | f'{set(["a", "b"])}' + | ^^^^^^^^^^^^^^^ C405 +24 | +25 | f"{set(['a', 'b']) - set(['a'])}" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +18 18 | ) +19 19 | f"{set([1,2,3])}" +20 20 | f"{set(['a', 'b'])}" +21 |-f'{set(["a", "b"])}' + 21 |+f'{ {"a", "b"} }' +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" + +C405.py:23:4: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +23 | f'{set(["a", "b"])}' +24 | +25 | f"{set(['a', 'b']) - set(['a'])}" + | ^^^^^^^^^^^^^^^ C405 +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +20 20 | f"{set(['a', 'b'])}" +21 21 | f'{set(["a", "b"])}' +22 22 | +23 |-f"{set(['a', 'b']) - set(['a'])}" + 23 |+f"{ {'a', 'b'} - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:23:22: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +23 | f'{set(["a", "b"])}' +24 | +25 | f"{set(['a', 'b']) - set(['a'])}" + | ^^^^^^^^^^ C405 +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +20 20 | f"{set(['a', 'b'])}" +21 21 | f'{set(["a", "b"])}' +22 22 | +23 |-f"{set(['a', 'b']) - set(['a'])}" + 23 |+f"{set(['a', 'b']) - {'a'} }" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:24:5: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +24 | f"{set(['a', 'b']) - set(['a'])}" +25 | f"{ set(['a', 'b']) - set(['a']) }" + | ^^^^^^^^^^^^^^^ C405 +26 | f"a {set(['a', 'b']) - set(['a'])} b" +27 | f"a { set(['a', 'b']) - set(['a']) } b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +21 21 | f'{set(["a", "b"])}' +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 |-f"{ set(['a', 'b']) - set(['a']) }" + 24 |+f"{ {'a', 'b'} - set(['a']) }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:24:23: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +24 | f"{set(['a', 'b']) - set(['a'])}" +25 | f"{ set(['a', 'b']) - set(['a']) }" + | ^^^^^^^^^^ C405 +26 | f"a {set(['a', 'b']) - set(['a'])} b" +27 | f"a { set(['a', 'b']) - set(['a']) } b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +21 21 | f'{set(["a", "b"])}' +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 |-f"{ set(['a', 'b']) - set(['a']) }" + 24 |+f"{ set(['a', 'b']) - {'a'} }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:25:6: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +25 | f"{set(['a', 'b']) - set(['a'])}" +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" + | ^^^^^^^^^^^^^^^ C405 +28 | f"a { set(['a', 'b']) - set(['a']) } b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 |-f"a {set(['a', 'b']) - set(['a'])} b" + 25 |+f"a { {'a', 'b'} - set(['a'])} b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:25:24: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +25 | f"{set(['a', 'b']) - set(['a'])}" +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" + | ^^^^^^^^^^ C405 +28 | f"a { set(['a', 'b']) - set(['a']) } b" + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +22 22 | +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 |-f"a {set(['a', 'b']) - set(['a'])} b" + 25 |+f"a {set(['a', 'b']) - {'a'} } b" +26 26 | f"a { set(['a', 'b']) - set(['a']) } b" + +C405.py:26:7: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" +28 | f"a { set(['a', 'b']) - set(['a']) } b" + | ^^^^^^^^^^^^^^^ C405 + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 |-f"a { set(['a', 'b']) - set(['a']) } b" + 26 |+f"a { {'a', 'b'} - set(['a']) } b" + +C405.py:26:25: C405 [*] Unnecessary `list` literal (rewrite as a `set` literal) + | +26 | f"{ set(['a', 'b']) - set(['a']) }" +27 | f"a {set(['a', 'b']) - set(['a'])} b" +28 | f"a { set(['a', 'b']) - set(['a']) } b" + | ^^^^^^^^^^ C405 + | + = help: Rewrite as a `set` literal + +ℹ Suggested fix +23 23 | f"{set(['a', 'b']) - set(['a'])}" +24 24 | f"{ set(['a', 'b']) - set(['a']) }" +25 25 | f"a {set(['a', 'b']) - set(['a'])} b" +26 |-f"a { set(['a', 'b']) - set(['a']) } b" + 26 |+f"a { set(['a', 'b']) - {'a'} } b" diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py.snap index 178c4fef394ac..e4153847c0ab8 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py.snap @@ -75,4 +75,234 @@ C408.py:4:6: C408 [*] Unnecessary `dict` call (rewrite as a literal) 6 6 | 7 7 | +C408.py:14:4: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +14 | a = list() +15 | +16 | f"{dict(x='y')}" + | ^^^^^^^^^^^ C408 +17 | f'{dict(x="y")}' +18 | f"{dict()}" + | + = help: Rewrite as a literal + +ℹ Suggested fix +11 11 | +12 12 | a = list() +13 13 | +14 |-f"{dict(x='y')}" + 14 |+f"{ {'x': 'y'} }" +15 15 | f'{dict(x="y")}' +16 16 | f"{dict()}" +17 17 | f"a {dict()} b" + +C408.py:15:4: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +15 | f"{dict(x='y')}" +16 | f'{dict(x="y")}' + | ^^^^^^^^^^^ C408 +17 | f"{dict()}" +18 | f"a {dict()} b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +12 12 | a = list() +13 13 | +14 14 | f"{dict(x='y')}" +15 |-f'{dict(x="y")}' + 15 |+f'{ {"x": "y"} }' +16 16 | f"{dict()}" +17 17 | f"a {dict()} b" +18 18 | + +C408.py:16:4: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +16 | f"{dict(x='y')}" +17 | f'{dict(x="y")}' +18 | f"{dict()}" + | ^^^^^^ C408 +19 | f"a {dict()} b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +13 13 | +14 14 | f"{dict(x='y')}" +15 15 | f'{dict(x="y")}' +16 |-f"{dict()}" + 16 |+f"{ {} }" +17 17 | f"a {dict()} b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" + +C408.py:17:6: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +17 | f'{dict(x="y")}' +18 | f"{dict()}" +19 | f"a {dict()} b" + | ^^^^^^ C408 +20 | +21 | f"{dict(x='y') | dict(y='z')}" + | + = help: Rewrite as a literal + +ℹ Suggested fix +14 14 | f"{dict(x='y')}" +15 15 | f'{dict(x="y")}' +16 16 | f"{dict()}" +17 |-f"a {dict()} b" + 17 |+f"a { {} } b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" + +C408.py:19:4: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +19 | f"a {dict()} b" +20 | +21 | f"{dict(x='y') | dict(y='z')}" + | ^^^^^^^^^^^ C408 +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +16 16 | f"{dict()}" +17 17 | f"a {dict()} b" +18 18 | +19 |-f"{dict(x='y') | dict(y='z')}" + 19 |+f"{ {'x': 'y'} | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:19:18: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +19 | f"a {dict()} b" +20 | +21 | f"{dict(x='y') | dict(y='z')}" + | ^^^^^^^^^^^ C408 +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +16 16 | f"{dict()}" +17 17 | f"a {dict()} b" +18 18 | +19 |-f"{dict(x='y') | dict(y='z')}" + 19 |+f"{dict(x='y') | {'y': 'z'} }" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:20:5: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +20 | f"{dict(x='y') | dict(y='z')}" +21 | f"{ dict(x='y') | dict(y='z') }" + | ^^^^^^^^^^^ C408 +22 | f"a {dict(x='y') | dict(y='z')} b" +23 | f"a { dict(x='y') | dict(y='z') } b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +17 17 | f"a {dict()} b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 |-f"{ dict(x='y') | dict(y='z') }" + 20 |+f"{ {'x': 'y'} | dict(y='z') }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:20:19: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +20 | f"{dict(x='y') | dict(y='z')}" +21 | f"{ dict(x='y') | dict(y='z') }" + | ^^^^^^^^^^^ C408 +22 | f"a {dict(x='y') | dict(y='z')} b" +23 | f"a { dict(x='y') | dict(y='z') } b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +17 17 | f"a {dict()} b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 |-f"{ dict(x='y') | dict(y='z') }" + 20 |+f"{ dict(x='y') | {'y': 'z'} }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:21:6: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +21 | f"{dict(x='y') | dict(y='z')}" +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" + | ^^^^^^^^^^^ C408 +24 | f"a { dict(x='y') | dict(y='z') } b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 |-f"a {dict(x='y') | dict(y='z')} b" + 21 |+f"a { {'x': 'y'} | dict(y='z')} b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:21:20: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +21 | f"{dict(x='y') | dict(y='z')}" +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" + | ^^^^^^^^^^^ C408 +24 | f"a { dict(x='y') | dict(y='z') } b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 |-f"a {dict(x='y') | dict(y='z')} b" + 21 |+f"a {dict(x='y') | {'y': 'z'} } b" +22 22 | f"a { dict(x='y') | dict(y='z') } b" + +C408.py:22:7: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" +24 | f"a { dict(x='y') | dict(y='z') } b" + | ^^^^^^^^^^^ C408 + | + = help: Rewrite as a literal + +ℹ Suggested fix +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 |-f"a { dict(x='y') | dict(y='z') } b" + 22 |+f"a { {'x': 'y'} | dict(y='z') } b" + +C408.py:22:21: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +22 | f"{ dict(x='y') | dict(y='z') }" +23 | f"a {dict(x='y') | dict(y='z')} b" +24 | f"a { dict(x='y') | dict(y='z') } b" + | ^^^^^^^^^^^ C408 + | + = help: Rewrite as a literal + +ℹ Suggested fix +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" +21 21 | f"a {dict(x='y') | dict(y='z')} b" +22 |-f"a { dict(x='y') | dict(y='z') } b" + 22 |+f"a { dict(x='y') | {'y': 'z'} } b" + diff --git a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py_allow_dict_calls_with_keyword_arguments.snap b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py_allow_dict_calls_with_keyword_arguments.snap index 561f619280f99..5f48163af86d1 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py_allow_dict_calls_with_keyword_arguments.snap +++ b/crates/ruff/src/rules/flake8_comprehensions/snapshots/ruff__rules__flake8_comprehensions__tests__C408_C408.py_allow_dict_calls_with_keyword_arguments.snap @@ -55,4 +55,45 @@ C408.py:3:6: C408 [*] Unnecessary `dict` call (rewrite as a literal) 5 5 | d3 = dict(**d2) 6 6 | +C408.py:16:4: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +16 | f"{dict(x='y')}" +17 | f'{dict(x="y")}' +18 | f"{dict()}" + | ^^^^^^ C408 +19 | f"a {dict()} b" + | + = help: Rewrite as a literal + +ℹ Suggested fix +13 13 | +14 14 | f"{dict(x='y')}" +15 15 | f'{dict(x="y")}' +16 |-f"{dict()}" + 16 |+f"{ {} }" +17 17 | f"a {dict()} b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" + +C408.py:17:6: C408 [*] Unnecessary `dict` call (rewrite as a literal) + | +17 | f'{dict(x="y")}' +18 | f"{dict()}" +19 | f"a {dict()} b" + | ^^^^^^ C408 +20 | +21 | f"{dict(x='y') | dict(y='z')}" + | + = help: Rewrite as a literal + +ℹ Suggested fix +14 14 | f"{dict(x='y')}" +15 15 | f'{dict(x="y")}' +16 16 | f"{dict()}" +17 |-f"a {dict()} b" + 17 |+f"a { {} } b" +18 18 | +19 19 | f"{dict(x='y') | dict(y='z')}" +20 20 | f"{ dict(x='y') | dict(y='z') }" + diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 949a461f21996..96d0628c9ace1 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -783,6 +783,7 @@ impl<'a> SemanticModel<'a> { /// Return `true` if the context is in an f-string. pub const fn in_f_string(&self) -> bool { self.flags.contains(SemanticModelFlags::F_STRING) + || self.flags.contains(SemanticModelFlags::NESTED_F_STRING) } /// Return `true` if the context is in a nested f-string. diff --git a/fuzz/init-fuzzer.sh b/fuzz/init-fuzzer.sh old mode 100755 new mode 100644 diff --git a/fuzz/reinit-fuzzer.sh b/fuzz/reinit-fuzzer.sh old mode 100755 new mode 100644