diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF010.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF010.py index af7e596dbf..38502ef224 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF010.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF010.py @@ -52,3 +52,7 @@ f"{repr(lambda: 1)}" f"{repr(x := 2)}" f"{str(object=3)}" + +f"{str(x for x in [])}" + +f"{str((x for x in []))}" diff --git a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index e3af51eee2..56dcdb6930 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -149,8 +149,7 @@ fn convert_call_to_conversion_flag( formatted_string_expression.whitespace_before_expression = space(); } - formatted_string_expression.expression = if needs_paren(OperatorPrecedence::from_expr(arg)) - { + formatted_string_expression.expression = if needs_paren_expr(arg) { call.args[0] .value .clone() @@ -178,6 +177,16 @@ fn needs_paren(precedence: OperatorPrecedence) -> bool { precedence <= OperatorPrecedence::Lambda } +fn needs_paren_expr(arg: &Expr) -> bool { + // Generator expressions need to be parenthesized in f-string expressions + if let Some(generator) = arg.as_generator_expr() { + return !generator.parenthesized; + } + + // Check precedence for other expressions + needs_paren(OperatorPrecedence::from_expr(arg)) +} + /// Represents the three built-in Python conversion functions that can be replaced /// with f-string conversion flags. #[derive(Copy, Clone)] diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF010_RUF010.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF010_RUF010.py.snap index 7c3cdf80a6..64f777d1cb 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF010_RUF010.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF010_RUF010.py.snap @@ -359,6 +359,7 @@ RUF010.py:52:4: RUF010 [*] Use explicit conversion flag 52 |+f"{(x := 2)!r}" 53 53 | 54 54 | f"{str(object=3)}" +55 55 | RUF010.py:54:4: RUF010 [*] Use explicit conversion flag | @@ -366,6 +367,8 @@ RUF010.py:54:4: RUF010 [*] Use explicit conversion flag 53 | 54 | f"{str(object=3)}" | ^^^^^^^^^^^^^ RUF010 +55 | +56 | f"{str(x for x in [])}" | = help: Replace with conversion flag @@ -375,3 +378,42 @@ RUF010.py:54:4: RUF010 [*] Use explicit conversion flag 53 53 | 54 |-f"{str(object=3)}" 54 |+f"{3!s}" +55 55 | +56 56 | f"{str(x for x in [])}" +57 57 | + +RUF010.py:56:4: RUF010 [*] Use explicit conversion flag + | +54 | f"{str(object=3)}" +55 | +56 | f"{str(x for x in [])}" + | ^^^^^^^^^^^^^^^^^^ RUF010 +57 | +58 | f"{str((x for x in []))}" + | + = help: Replace with conversion flag + +ℹ Safe fix +53 53 | +54 54 | f"{str(object=3)}" +55 55 | +56 |-f"{str(x for x in [])}" + 56 |+f"{(x for x in [])!s}" +57 57 | +58 58 | f"{str((x for x in []))}" + +RUF010.py:58:4: RUF010 [*] Use explicit conversion flag + | +56 | f"{str(x for x in [])}" +57 | +58 | f"{str((x for x in []))}" + | ^^^^^^^^^^^^^^^^^^^^ RUF010 + | + = help: Replace with conversion flag + +ℹ Safe fix +55 55 | +56 56 | f"{str(x for x in [])}" +57 57 | +58 |-f"{str((x for x in []))}" + 58 |+f"{(x for x in [])!s}"