How to make ruff to use f-string instead str.format?

601 views Asked by At

I'm trying ruff but when I do ruff check . on my example:

print("%s" % "hello")

it shows:

UP031 Use format specifiers instead of percent format

and if I do ruff check . --fix or ruff format . they don't change anything.

My pyproject.toml snipped:

[tool.ruff]
target-version = "py39"
line-length = 120
extend-select = ["E501", "UP", "RUF"]
2

There are 2 answers

0
0x00 On

You should always post the versions of the tools you are using and when asking for help with errors/outputs you should always post the whole output.

Running your example with ruff 0.1.2 (ruff check .) outputs:

main.py:1:7: UP031 Use format specifiers instead of percent format
Found 1 error.
No fixes available (1 hidden fix can be enabled with the `--unsafe-fixes` option).

The error message clearly states that there aren't fixes available unless you run the command with the option --unsafe-fixes. If you want ruff to fix it then you need to run the command ruff check . --fix --unsafe-fixes

$ ruff check . --fix --unsafe-fixes
Found 1 error (1 fixed, 0 remaining).

and it will fix the line to print("{}".format("hello"))

It is an unsafe fix as explained by the documentation, the value you are trying to print could change the way its printed if you change the formatting.

According to ruff rules (UP032) is sometimes able to fix .format() and turn it into an f-string, but in this case because you are directly using a string it doesn't fix it. If your code was:

a = "hello"
print("{}".format(a))

Ruff would fix it and turn it into (`ruff check . --fix):

a = "hello"
print(f"{a}")
0
alanwilter On

I got to understand better my problem and designed a better example.

pyupgrade:

cat <<EOF >|test.py
a=1
b=2
ab = "%s %s" % (a, b)
c = "%s %s"  % (ab, ab)
print("%s" % ab)
EOF
pyupgrade --py36-plus test.py
cat test.py
pyupgrade --py36-plus test.py
cat test.py

Rewriting test.py
a=1
b=2
ab = "{} {}".format(a, b)
c = "%s %s"  % (ab, ab)
print("%s" % ab)
Rewriting test.py
a=1
b=2
ab = f"{a} {b}"
c = "%s %s"  % (ab, ab)
print("%s" % ab)

So pyupgrade needs two runs and the final result is not great.

ruff:

cat <<EOF >|test.py
a=1
b=2
ab = "%s %s" % (a, b)
c = "%s %s"  % (ab, ab)
print("%s" % ab)
EOF
ruff check --fix --unsafe-fixes test.py
cat test.py

Found 4 errors (4 fixed, 0 remaining).
a=1
b=2
ab = f"{a} {b}"
c = f"{ab} {ab}"
print("%s" % ab)

ruff clearly does better: just one run and better results. Yet, I wonder why print("%s" % ab) is not converted to `print(f"{ab}").