From 4454fbf7e58c8fcd52e3dae45539f9e890a30dfb Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Thu, 12 Oct 2023 10:56:39 +0530 Subject: [PATCH] Fix `E251` false positive inside f-strings (#7894) ## Summary This PR fixes the bug where the rule `E251` was being triggered on a equal token inside a f-string which was used in the context of debug expressions. For example, the following was being flagged before the fix: ```python print(f"{foo = }") ``` But, now it is not. This leads to false negatives such as: ```python print(f"{foo(a = 1)}") ``` One solution would be to know if the opened parentheses was inside a f-string or not. If it was then we can continue flagging until it's closed. If not, then we should not flag it. ## Test Plan Add new test cases and check that they don't raise any false positives. fixes: #7882 --- .../ruff_linter/resources/test/fixtures/pycodestyle/E25.py | 5 +++++ .../whitespace_around_named_parameter_equals.rs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py index 7c13205ae1..9d8bddac42 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E25.py @@ -54,3 +54,8 @@ f"{a=}" f"{a:=1}" f"{foo(a=1)}" f"normal {f"{a=}"} normal" + +# Okay as the `=` is used inside a f-string... +print(f"{foo = }") +# ...but then it creates false negatives for now +print(f"{foo(a = 1)}") diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs index 7f5984c33f..35002a642e 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/logical_lines/whitespace_around_named_parameter_equals.rs @@ -94,6 +94,7 @@ pub(crate) fn whitespace_around_named_parameter_equals( context: &mut LogicalLinesContext, ) { let mut parens = 0u32; + let mut fstrings = 0u32; let mut annotated_func_arg = false; let mut prev_end = TextSize::default(); @@ -108,6 +109,8 @@ pub(crate) fn whitespace_around_named_parameter_equals( } match kind { + TokenKind::FStringStart => fstrings += 1, + TokenKind::FStringEnd => fstrings = fstrings.saturating_sub(1), TokenKind::Lpar | TokenKind::Lsqb => { parens = parens.saturating_add(1); } @@ -124,7 +127,7 @@ pub(crate) fn whitespace_around_named_parameter_equals( TokenKind::Comma if parens == 1 => { annotated_func_arg = false; } - TokenKind::Equal if parens > 0 => { + TokenKind::Equal if parens > 0 && fstrings == 0 => { if annotated_func_arg && parens == 1 { let start = token.start(); if start == prev_end && prev_end != TextSize::new(0) {