diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py index f38ca1e8737ab..99f97215624db 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C401.py @@ -6,6 +6,16 @@ _ = '{}'.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 + + +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") + + def set(*args, **kwargs): return None diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py index 20db252700f48..d5b428331a5f1 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C402.py @@ -5,3 +5,11 @@ 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') + +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..f6f7d160ebaca 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C403.py @@ -2,3 +2,11 @@ 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'])}" diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py index 29134023b4424..3524c5920f0dc 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C404.py @@ -1,2 +1,10 @@ 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'])}" diff --git a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py index 936e5e2622e61..83578e7432893 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C405.py @@ -16,3 +16,6 @@ set( [1,] ) +f"{set([1,2,3])}" +f"{set(['a', 'b'])}" +f'{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..75a22adc0ed43 100644 --- a/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py +++ b/crates/ruff/resources/test/fixtures/flake8_comprehensions/C408.py @@ -10,3 +10,7 @@ def list(): a = list() + +f"{dict(x='y')}" +f'{dict(x="y")}' +f"{dict()}" diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 2ed17be53475f..604b028212647 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -138,30 +138,35 @@ 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(context: &Context, locator: &Locator, indexer: &Indexer) -> Option { - if !context.in_f_string() { - return None; - } - - // Find the quote character used to start the containing f-string. - let expr = context.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.ctx, 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 context = &self.ctx; + if !context.in_f_string() { + return None; + } + + // Find the quote character used to start the containing f-string. + let expr = context.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, + } + } } impl<'a, 'b> Visitor<'b> for Checker<'a> diff --git a/crates/ruff/src/rules/flake8_comprehensions/fixes.rs b/crates/ruff/src/rules/flake8_comprehensions/fixes.rs index 24deb88e1eb92..53d2405410129 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/fixes.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/fixes.rs @@ -12,6 +12,7 @@ use rustpython_parser::ast::Ranged; use ruff_diagnostics::{Edit, Fix}; use ruff_python_ast::source_code::{Locator, Stylist}; +use crate::checkers::ast::Checker; use crate::cst::matchers::{match_expr, match_module}; fn match_call<'a, 'b>(expr: &'a mut Expr<'b>) -> Result<&'a mut Call<'b>> { @@ -193,10 +194,11 @@ pub(crate) fn fix_unnecessary_generator_dict( /// (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()); @@ -229,16 +231,21 @@ pub(crate) fn fix_unnecessary_list_comprehension_set( }; tree.codegen(&mut state); - Ok(Edit::range_replacement(state.to_string(), expr.range())) + Ok(Edit::range_replacement( + wrap_code_in_spaces(&state, checker.ctx.in_f_string()), + expr.range(), + )) } /// (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_module(module_text)?; let mut body = match_expr(&mut tree)?; @@ -254,16 +261,15 @@ pub(crate) fn fix_unnecessary_list_comprehension_dict( }; let [Element::Simple { - value: key, - comma: Some(comma), + value: key, .. }, Element::Simple { value, .. }] = &tuple.elements[..] else { bail!("Expected tuple with two elements"); }; body.value = 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(), }, @@ -281,7 +287,10 @@ pub(crate) fn fix_unnecessary_list_comprehension_dict( }; tree.codegen(&mut state); - Ok(Edit::range_replacement(state.to_string(), expr.range())) + Ok(Edit::range_replacement( + wrap_code_in_spaces(&state, checker.ctx.in_f_string()), + expr.range(), + )) } /// Drop a trailing comma from a list of tuple elements. @@ -329,10 +338,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_module(module_text)?; @@ -371,7 +382,10 @@ pub(crate) fn fix_unnecessary_literal_set( }; tree.codegen(&mut state); - Ok(Edit::range_replacement(state.to_string(), expr.range())) + Ok(Edit::range_replacement( + wrap_code_in_spaces(&state, checker.ctx.in_f_string()), + expr.range(), + )) } /// (C406) Convert `dict([(1, 2)])` to `{1: 2}`. @@ -445,10 +459,12 @@ pub(crate) fn fix_unnecessary_literal_dict( /// (C408) pub(crate) fn fix_unnecessary_collection_call( - locator: &Locator, - stylist: &Stylist, + checker: &Checker, expr: &rustpython_parser::ast::Expr, ) -> Result { + 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_module(module_text)?; @@ -457,6 +473,7 @@ pub(crate) fn fix_unnecessary_collection_call( let Expression::Name(name) = &call.func.as_ref() else { bail!("Expected Expression::Name"); }; + let mut wrap_in_spaces = false; // Arena allocator used to create formatted strings of sufficient lifetime, // below. @@ -480,6 +497,10 @@ pub(crate) fn fix_unnecessary_collection_call( })); } "dict" => { + let in_f_string = checker.ctx.in_f_string(); + if in_f_string { + wrap_in_spaces = true; + } if call.args.is_empty() { body.value = Expression::Dict(Box::new(Dict { elements: vec![], @@ -489,16 +510,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); } @@ -552,7 +575,19 @@ pub(crate) fn fix_unnecessary_collection_call( }; tree.codegen(&mut state); - Ok(Edit::range_replacement(state.to_string(), expr.range())) + Ok(Edit::range_replacement( + wrap_code_in_spaces(&state, wrap_in_spaces), + expr.range(), + )) +} + +/// Adds spaces around the code generated from `state` if `wrap_in_spaces` is true. +fn wrap_code_in_spaces(state: &CodegenState, wrap_in_spaces: bool) -> String { + if wrap_in_spaces { + format!(" {state} ") + } else { + state.to_string() + } } /// (C409) Convert `tuple([1, 2])` to `tuple(1, 2)` 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 1789608900d13..f9fb0e9493816 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_list_comprehension_dict.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_dict.rs index 12e9ee790c8a9..7fdfbcb8e4971 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 @@ -65,7 +65,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 49076501f453e..8a7000bf24f35 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_set.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_literal_set.rs index 2d58455da0199..7a70a446c86e0 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 @@ -73,9 +73,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..c51fd52c9544b 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 @@ -80,18 +80,16 @@ C401.py:6:17: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) 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): +9 9 | 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') - | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 -10 | -11 | def set(*args, **kwargs): - | - = help: 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') + | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 + | + = help: Rewrite as a `set` comprehension ℹ Suggested fix 4 4 | ) @@ -100,7 +98,64 @@ C401.py:7:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) 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 +9 9 | +10 10 | def f(x): + +C401.py:14:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +14 | print(f'Hello {set(a for a in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^ C401 +15 | print(f"Hello {set(a for a in 'abc')} World") +16 | print(f"Hello {set(f(a) for a in 'abc')} World") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +11 11 | return x +12 12 | +13 13 | +14 |-print(f'Hello {set(a for a in "abc")} World') + 14 |+print(f'Hello { {a for a in "abc"} } World') +15 15 | print(f"Hello {set(a for a in 'abc')} World") +16 16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 17 | + +C401.py:15:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +15 | print(f'Hello {set(a for a in "abc")} World') +16 | print(f"Hello {set(a for a in 'abc')} World") + | ^^^^^^^^^^^^^^^^^^^^^ C401 +17 | print(f"Hello {set(f(a) for a in 'abc')} World") + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +12 12 | +13 13 | +14 14 | print(f'Hello {set(a for a in "abc")} World') +15 |-print(f"Hello {set(a for a in 'abc')} World") + 15 |+print(f"Hello { {a for a in 'abc'} } World") +16 16 | print(f"Hello {set(f(a) for a in 'abc')} World") +17 17 | +18 18 | + +C401.py:16:16: C401 [*] Unnecessary generator (rewrite as a `set` comprehension) + | +16 | print(f'Hello {set(a for a in "abc")} World') +17 | print(f"Hello {set(a for a in 'abc')} World") +18 | print(f"Hello {set(f(a) for a in 'abc')} World") + | ^^^^^^^^^^^^^^^^^^^^^^^^ C401 + | + = help: Rewrite as a `set` comprehension + +ℹ Suggested fix +13 13 | +14 14 | print(f'Hello {set(a for a in "abc")} World') +15 15 | print(f"Hello {set(a for a in 'abc')} World") +16 |-print(f"Hello {set(f(a) for a in 'abc')} World") + 16 |+print(f"Hello { {f(a) for a in 'abc'} } World") +17 17 | +18 18 | +19 19 | def set(*args, **kwargs): 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..e7120f9b79c24 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,86 @@ 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 | def f(x): + +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 | def f(x): + | + = 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 | def f(x): +13 13 | return x + +C402.py:15:16: C402 [*] Unnecessary generator (rewrite as a `dict` comprehension) + | +15 | return x +16 | +17 | print(f'Hello {dict((x,f(x)) for x in "abc")} World') + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C402 + | + = help: Rewrite as a `dict` comprehension + +ℹ Suggested fix +12 12 | def f(x): +13 13 | return x +14 14 | +15 |-print(f'Hello {dict((x,f(x)) for x in "abc")} World') + 15 |+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..2bb73a3d37e55 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,64 @@ 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 + | + = 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'} }" 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..cec29f59c8d0b 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,81 @@ 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'])}" + +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'])}" + +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 + | + = 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'} }" 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..c6d26928ef8bc 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,62 @@ 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"])}' + +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"])}' + +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 + | + = 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"} }' 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..bfffd64a36ef7 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,57 @@ 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()}" + +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()}" + | + = 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()}" + +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 + | + = 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"{ {} }" + 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..9c53d2ec7c457 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,20 @@ 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 + | + = 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"{ {} }" +