pylint icon indicating copy to clipboard operation
pylint copied to clipboard

Detect useless f-strings

Open socketpair opened this issue 3 months ago • 7 comments

Current problem

Real diff:

-                cursor.executescript(f'BEGIN;\n{diff}\nCOMMIT;')
+                cursor.executescript(f'{diff}')

This is an example where Pylint could identify codestyle problem. Useless f-string. i.e. f-strings containing single variable without formatting attributes and without other f-string parts.

Desired solution

Detect such cases and notify

Additional context

No response

socketpair avatar Apr 02 '24 11:04 socketpair

+1 from me. It also seems relatively immune to false positive and simple without looking too much into it. How would you name it ? useless-string, useless-fstring-formatting useless-format-string ?

Pierre-Sassoulas avatar Apr 02 '24 12:04 Pierre-Sassoulas

@Pierre-Sassoulas I would call useless-f-string

socketpair avatar Apr 02 '24 12:04 socketpair

class SneakyString(str):
    def __str__(self) -> str:
        return "Different string"


x = SneakyString("A")

print(f"{x}" + "B")
print(f"{x:.2}" + "B")
print(x + "B")

I think there is a actually a pretty high chance for false positives as the logic for f-strings is quite difficult to statically imitate.

DanielNoord avatar Apr 03 '24 07:04 DanielNoord

Not sure what the false positive is in this case @DanielNoord ? Isn't print(f"{x}" + "B") an actual issue ? As it should be print(str(x) + "B") to be equivalent (well, print(f"{x}B"), but this would become hard). I imagine the message raised should be something like Useless f-string, use 'x' or str(x)' instead of 'f"{x}"'.

Pierre-Sassoulas avatar Apr 03 '24 09:04 Pierre-Sassoulas

The false positive is that f"{x}" isn't the same as x. f"{x}" is probably quicker than str(x) as there is no lookup for the str() function and thus suggesting str(x) instead of f"{x}" is actually not in line with some of our other checks :sweat_smile:

DanielNoord avatar Apr 03 '24 09:04 DanielNoord

@DanielNoord

In [1]: timeit f'{42}'
70 ns ± 1.14 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

In [2]: timeit str(42)
71.9 ns ± 0.856 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

socketpair avatar Apr 03 '24 11:04 socketpair

Right. Still + 0.5 on this, but it's less useful if it become consider-f-string-uselessness and a convention check, for sure.

Pierre-Sassoulas avatar Apr 03 '24 22:04 Pierre-Sassoulas