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 09ea36db61943..497caa8d3c663 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py +++ b/crates/ruff_linter/resources/test/fixtures/pyupgrade/UP032_0.py @@ -259,3 +259,9 @@ async def c(): # The string _should_ be converted, since the function call is repeated in the arguments. "{0} {1}".format(foo(), foo()) + +# The call should be removed, but the string itself should remain. +''.format(self.project) + +# The call should be removed, but the string itself should remain. +"".format(self.project) 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 31a2383274349..d6441f9904490 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/f_strings.rs @@ -400,7 +400,7 @@ pub(crate) fn f_strings(checker: &mut Checker, call: &ast::ExprCall, summary: &F return; }; - if !value.is_string_literal_expr() { + let Expr::StringLiteral(literal) = &**value else { return; }; @@ -520,10 +520,18 @@ pub(crate) fn f_strings(checker: &mut Checker, call: &ast::ExprCall, summary: &F .intersects(call.arguments.range()); if !has_comments { - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - contents, - call.range(), - ))); + if contents.is_empty() { + // Ex) `''.format(self.project)` + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + checker.locator().slice(literal).to_string(), + call.range(), + ))); + } else { + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( + contents, + call.range(), + ))); + } }; checker.diagnostics.push(diagnostic); } 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 e5eb894054014..63a25c3f5922a 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 @@ -1321,6 +1321,8 @@ UP032_0.py:261:1: UP032 [*] Use f-string instead of `format` call 260 | # The string _should_ be converted, since the function call is repeated in the arguments. 261 | "{0} {1}".format(foo(), foo()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP032 +262 | +263 | # The call should be removed, but the string itself should remain. | = help: Convert to f-string @@ -1330,3 +1332,41 @@ UP032_0.py:261:1: UP032 [*] Use f-string instead of `format` call 260 260 | # The string _should_ be converted, since the function call is repeated in the arguments. 261 |-"{0} {1}".format(foo(), foo()) 261 |+f"{foo()} {foo()}" +262 262 | +263 263 | # The call should be removed, but the string itself should remain. +264 264 | ''.format(self.project) + +UP032_0.py:264:1: UP032 [*] Use f-string instead of `format` call + | +263 | # The call should be removed, but the string itself should remain. +264 | ''.format(self.project) + | ^^^^^^^^^^^^^^^^^^^^^^^ UP032 +265 | +266 | # The call should be removed, but the string itself should remain. + | + = help: Convert to f-string + +ℹ Safe fix +261 261 | "{0} {1}".format(foo(), foo()) +262 262 | +263 263 | # The call should be removed, but the string itself should remain. +264 |-''.format(self.project) + 264 |+'' +265 265 | +266 266 | # The call should be removed, but the string itself should remain. +267 267 | "".format(self.project) + +UP032_0.py:267:1: UP032 [*] Use f-string instead of `format` call + | +266 | # The call should be removed, but the string itself should remain. +267 | "".format(self.project) + | ^^^^^^^^^^^^^^^^^^^^^^^ UP032 + | + = help: Convert to f-string + +ℹ Safe fix +264 264 | ''.format(self.project) +265 265 | +266 266 | # The call should be removed, but the string itself should remain. +267 |-"".format(self.project) + 267 |+""