From 59791aae3af34bdf0bdb30cbaaa1879cf6385361 Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 16 Nov 2023 08:55:59 -0600 Subject: [PATCH] Fix bug --- .../src/rules/pyupgrade/helpers.rs | 13 +++++++++ .../src/rules/pyupgrade/rules/f_strings.rs | 10 ++++--- ...__rules__pyupgrade__tests__UP032_0.py.snap | 29 ++++++++++--------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyupgrade/helpers.rs b/crates/ruff_linter/src/rules/pyupgrade/helpers.rs index 03f48d877aa0d..07196a9127332 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/helpers.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/helpers.rs @@ -19,3 +19,16 @@ pub(super) fn curly_escape(text: &str) -> Cow<'_, str> { } }) } + +static DOUBLE_CURLY_BRACES: Lazy = Lazy::new(|| Regex::new(r"((\{\{)|(\}\}))").unwrap()); + +pub(super) fn curly_unescape(text: &str) -> Cow<'_, str> { + // Match all double curly braces and replace with a single + DOUBLE_CURLY_BRACES.replace_all(text, |caps: &Captures| { + if &caps[1] == "{{" { + "{".to_string() + } else { + "}".to_string() + } + }) +} diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs index 0ce52785c4139..e7cefb982f898 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs @@ -18,7 +18,7 @@ use crate::checkers::ast::Checker; use crate::fix::edits::fits_or_shrinks; use crate::rules::pyflakes::format::FormatSummary; -use crate::rules::pyupgrade::helpers::curly_escape; +use crate::rules::pyupgrade::helpers::{curly_escape, curly_unescape}; /// ## What it does /// Checks for `str.format` calls that can be replaced with f-strings. @@ -357,9 +357,11 @@ pub(crate) fn f_strings( Some((Tok::String { .. }, range)) => { match try_convert_to_f_string(range, &mut summary, checker.locator()) { Ok(Some(fstring)) => patches.push((range, fstring)), - // Skip any strings that don't require conversion (e.g., literal segments of an - // implicit concatenation). - Ok(None) => continue, + // Convert escaped curly brackets e.g. `{{` to `{` in literal string parts + Ok(None) => patches.push(( + range, + curly_unescape(checker.locator().slice(range)).to_string(), + )), // If any of the segments fail to convert, then we can't convert the entire // expression. Err(_) => return, diff --git a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP032_0.py.snap b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP032_0.py.snap index 7cf99c42418d1..83e87da819fd2 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP032_0.py.snap +++ b/crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP032_0.py.snap @@ -995,10 +995,11 @@ UP032_0.py:212:18: UP032 [*] Use f-string instead of `format` call 211 211 | # When fixing, trim the trailing empty string. 212 |-raise ValueError("Conflicting configuration dicts: {!r} {!r}" 213 |- "".format(new_dict, d)) - 212 |+raise ValueError(f"Conflicting configuration dicts: {new_dict!r} {d!r}") -214 213 | -215 214 | # When fixing, trim the trailing empty string. -216 215 | raise ValueError("Conflicting configuration dicts: {!r} {!r}" + 212 |+raise ValueError(f"Conflicting configuration dicts: {new_dict!r} {d!r}" + 213 |+ "") +214 214 | +215 215 | # When fixing, trim the trailing empty string. +216 216 | raise ValueError("Conflicting configuration dicts: {!r} {!r}" UP032_0.py:216:18: UP032 [*] Use f-string instead of `format` call | @@ -1041,9 +1042,10 @@ UP032_0.py:220:5: UP032 [*] Use f-string instead of `format` call 220 |- "Conflicting configuration dicts: {!r} {!r}" 221 |- "".format(new_dict, d) 220 |+ f"Conflicting configuration dicts: {new_dict!r} {d!r}" -222 221 | ) -223 222 | -224 223 | raise ValueError( + 221 |+ "" +222 222 | ) +223 223 | +224 224 | raise ValueError( UP032_0.py:225:5: UP032 [*] Use f-string instead of `format` call | @@ -1064,9 +1066,10 @@ UP032_0.py:225:5: UP032 [*] Use f-string instead of `format` call 225 |- "Conflicting configuration dicts: {!r} {!r}" 226 |- "".format(new_dict, d) 225 |+ f"Conflicting configuration dicts: {new_dict!r} {d!r}" -227 226 | -228 227 | ) -229 228 | + 226 |+ "" +227 227 | +228 228 | ) +229 229 | UP032_0.py:231:1: UP032 [*] Use f-string instead of `format` call | @@ -1085,9 +1088,9 @@ UP032_0.py:231:1: UP032 [*] Use f-string instead of `format` call 229 229 | 230 230 | # The first string will be converted to an f-string and the curly braces in the second should be converted to be unescaped 231 231 | ( -232 |- "{}" 232 |+ f"{a}" -233 233 | "{{}}" +232 233 | "{}" +233 |- "{{}}" 234 |-).format(a) 234 |+) 235 235 | @@ -1108,7 +1111,7 @@ UP032_0.py:236:1: UP032 [*] Use f-string instead of `format` call 234 234 | ).format(a) 235 235 | 236 |-("{}" "{{}}").format(a) - 236 |+(f"{a}" "{{}}") + 236 |+(f"{a}" "{}") 237 237 | 238 238 | 239 239 | # Both strings will be converted to an f-string and the curly braces in the second should left escaped