diff --git a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py index 0ba30683b92ae..19868afac3284 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py +++ b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py @@ -207,3 +207,22 @@ async def c(): # The fixed string will exceed the line length, but it's still smaller than the # existing line length, so it's fine. "".format(self.internal_ids, self.external_ids, self.properties, self.tags, self.others) + +# When fixing, trim the trailing empty string. +raise ValueError("Conflicting configuration dicts: {!r} {!r}" + "".format(new_dict, d)) + +# When fixing, trim the trailing empty string. +raise ValueError("Conflicting configuration dicts: {!r} {!r}" + .format(new_dict, d)) + +raise ValueError( + "Conflicting configuration dicts: {!r} {!r}" + "".format(new_dict, d) +) + +raise ValueError( + "Conflicting configuration dicts: {!r} {!r}" + "".format(new_dict, d) + +) 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 ff2028b005b27..0ce52785c4139 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs @@ -384,7 +384,21 @@ pub(crate) fn f_strings( contents.push_str(&fstring); prev_end = range.end(); } - contents.push_str(checker.locator().slice(TextRange::new(prev_end, end))); + + // If the remainder is non-empty, add it to the contents. + let rest = checker.locator().slice(TextRange::new(prev_end, end)); + if !lexer::lex_starts_at(rest, Mode::Expression, prev_end) + .flatten() + .all(|(token, _)| match token { + Tok::Comment(_) | Tok::Newline | Tok::NonLogicalNewline | Tok::Indent | Tok::Dedent => { + true + } + Tok::String { value, .. } => value.is_empty(), + _ => false, + }) + { + contents.push_str(rest); + } // If necessary, add a space between any leading keyword (`return`, `yield`, `assert`, etc.) // and the string. For example, `return"foo"` is valid, but `returnf"foo"` is not. 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 b6849b082c216..4538fe9b917de 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 @@ -962,6 +962,8 @@ UP032_0.py:209:1: UP032 [*] Use f-string instead of `format` call 208 | # existing line length, so it's fine. 209 | "".format(self.internal_ids, self.external_ids, self.properties, self.tags, self.others) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP032 +210 | +211 | # When fixing, trim the trailing empty string. | = help: Convert to f-string @@ -971,5 +973,98 @@ UP032_0.py:209:1: UP032 [*] Use f-string instead of `format` call 208 208 | # existing line length, so it's fine. 209 |-"".format(self.internal_ids, self.external_ids, self.properties, self.tags, self.others) 209 |+f"" +210 210 | +211 211 | # When fixing, trim the trailing empty string. +212 212 | raise ValueError("Conflicting configuration dicts: {!r} {!r}" + +UP032_0.py:212:18: UP032 [*] Use f-string instead of `format` call + | +211 | # When fixing, trim the trailing empty string. +212 | raise ValueError("Conflicting configuration dicts: {!r} {!r}" + | __________________^ +213 | | "".format(new_dict, d)) + | |_______________________________________^ UP032 +214 | +215 | # When fixing, trim the trailing empty string. + | + = help: Convert to f-string + +ℹ Safe fix +209 209 | "".format(self.internal_ids, self.external_ids, self.properties, self.tags, self.others) +210 210 | +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}" + +UP032_0.py:216:18: UP032 [*] Use f-string instead of `format` call + | +215 | # When fixing, trim the trailing empty string. +216 | raise ValueError("Conflicting configuration dicts: {!r} {!r}" + | __________________^ +217 | | .format(new_dict, d)) + | |_____________________________________^ UP032 +218 | +219 | raise ValueError( + | + = help: Convert to f-string + +ℹ Safe fix +213 213 | "".format(new_dict, d)) +214 214 | +215 215 | # When fixing, trim the trailing empty string. +216 |-raise ValueError("Conflicting configuration dicts: {!r} {!r}" +217 |- .format(new_dict, d)) + 216 |+raise ValueError(f"Conflicting configuration dicts: {new_dict!r} {d!r}") +218 217 | +219 218 | raise ValueError( +220 219 | "Conflicting configuration dicts: {!r} {!r}" + +UP032_0.py:220:5: UP032 [*] Use f-string instead of `format` call + | +219 | raise ValueError( +220 | "Conflicting configuration dicts: {!r} {!r}" + | _____^ +221 | | "".format(new_dict, d) + | |__________________________^ UP032 +222 | ) + | + = help: Convert to f-string + +ℹ Safe fix +217 217 | .format(new_dict, d)) +218 218 | +219 219 | raise ValueError( +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( + +UP032_0.py:225:5: UP032 [*] Use f-string instead of `format` call + | +224 | raise ValueError( +225 | "Conflicting configuration dicts: {!r} {!r}" + | _____^ +226 | | "".format(new_dict, d) + | |__________________________^ UP032 +227 | +228 | ) + | + = help: Convert to f-string + +ℹ Safe fix +222 222 | ) +223 223 | +224 224 | raise ValueError( +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 | )