From 9ba17fbf92e3ac644d873e2f4815e3ef8fc1975b Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 31 Dec 2022 13:41:21 -0500 Subject: [PATCH] Avoid flagging nested f-strings (#1516) --- resources/test/fixtures/pyflakes/F541.py | 14 ++++++++++ src/checkers/ast.rs | 13 +++++++++- .../ruff__pyflakes__tests__F541_F541.py.snap | 26 +++++++++---------- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/resources/test/fixtures/pyflakes/F541.py b/resources/test/fixtures/pyflakes/F541.py index 7d50deae46..977c7fe636 100644 --- a/resources/test/fixtures/pyflakes/F541.py +++ b/resources/test/fixtures/pyflakes/F541.py @@ -1,6 +1,8 @@ +# OK a = "abc" b = f"ghi{'jkl'}" +# Errors c = f"def" d = f"def" + "ghi" e = ( @@ -8,5 +10,17 @@ e = ( "ghi" ) +# OK g = f"ghi{123:{45}}" + +# Error h = "x" "y" f"z" + +v = 23.234234 + +# OK +f"{v:0.2f}" + +# OK (false negatives) +f"{v:{f'0.2f'}}" +f"{f''}" diff --git a/src/checkers/ast.rs b/src/checkers/ast.rs index 8629bae850..bc2cfd409f 100644 --- a/src/checkers/ast.rs +++ b/src/checkers/ast.rs @@ -91,6 +91,7 @@ pub struct Checker<'a> { in_type_definition: bool, in_deferred_string_type_definition: bool, in_deferred_type_definition: bool, + in_f_string: bool, in_literal: bool, in_subscript: bool, seen_import_boundary: bool, @@ -147,6 +148,7 @@ impl<'a> Checker<'a> { in_type_definition: false, in_deferred_string_type_definition: false, in_deferred_type_definition: false, + in_f_string: false, in_literal: false, in_subscript: false, seen_import_boundary: false, @@ -1466,6 +1468,7 @@ where self.push_expr(expr); + let prev_in_f_string = self.in_f_string; let prev_in_literal = self.in_literal; let prev_in_type_definition = self.in_type_definition; @@ -2151,7 +2154,9 @@ where } } ExprKind::JoinedStr { values } => { - if self.settings.enabled.contains(&CheckCode::F541) { + // Conversion flags are parsed as f-strings without placeholders, so skip + // nested f-strings, which would lead to false positives. + if !self.in_f_string && self.settings.enabled.contains(&CheckCode::F541) { if !values .iter() .any(|value| matches!(value.node, ExprKind::FormattedValue { .. })) @@ -2654,6 +2659,11 @@ where } self.in_subscript = prev_in_subscript; } + ExprKind::JoinedStr { .. } => { + self.in_f_string = true; + visitor::walk_expr(self, expr); + self.in_f_string = prev_in_f_string; + } _ => visitor::walk_expr(self, expr), } @@ -2671,6 +2681,7 @@ where self.in_type_definition = prev_in_type_definition; self.in_literal = prev_in_literal; + self.in_f_string = prev_in_f_string; self.pop_expr(); } diff --git a/src/pyflakes/snapshots/ruff__pyflakes__tests__F541_F541.py.snap b/src/pyflakes/snapshots/ruff__pyflakes__tests__F541_F541.py.snap index 28277100e3..6331262ce5 100644 --- a/src/pyflakes/snapshots/ruff__pyflakes__tests__F541_F541.py.snap +++ b/src/pyflakes/snapshots/ruff__pyflakes__tests__F541_F541.py.snap @@ -4,19 +4,10 @@ expression: checks --- - kind: FStringMissingPlaceholders location: - row: 4 + row: 6 column: 4 end_location: - row: 4 - column: 10 - fix: ~ - parent: ~ -- kind: FStringMissingPlaceholders - location: - row: 5 - column: 4 - end_location: - row: 5 + row: 6 column: 10 fix: ~ parent: ~ @@ -31,10 +22,19 @@ expression: checks parent: ~ - kind: FStringMissingPlaceholders location: - row: 12 + row: 9 column: 4 end_location: - row: 12 + row: 9 + column: 10 + fix: ~ + parent: ~ +- kind: FStringMissingPlaceholders + location: + row: 17 + column: 4 + end_location: + row: 17 column: 16 fix: ~ parent: ~