Description
Description
explicit-f-string-type-conversion
(RUF010) has many errors in Ruff 0.9.7.
If the argument to ascii
, repr
, or str
is a comprehension or display for a set or dictionary, the rule does not report it.
$ cat >ruf010_1.py <<'# EOF'
print(f"{ascii({})}")
# EOF
$ ruff --isolated check --select RUF010 ruf010_1.py
All checks passed!
That false negative is intentional, to fix #5530, but a better solution is to add a space as ruff format
does.
print(f"{ {}!a}")
Skipping those comprehensions and displays does not fix that problem anyway. If the argument starts with one but continues further, the rule introduces a syntax error.
$ cat >ruf010_2.py <<'# EOF'
print(f"{ascii({} | {})}")
# EOF
$ ruff --isolated check --select RUF010 ruf010_2.py --diff 2>&1 | grep error:
error: Fix introduced a syntax error. Reverting all changes.
The fix is suppressed when the conversion function expression is not exactly ascii
, repr
, or str
. Since the rule is able to detect equivalent expressions it should be able to fix them.
$ cat >ruf010_3.py <<'# EOF'
import builtins
print(f"{builtins.ascii(1)}")
print(f"{𝑎𝑠𝑐𝑖𝑖(1)}")
# EOF
$ ruff --isolated check --select RUF010 ruf010_3.py --output-format concise
ruf010_3.py:2:10: RUF010 Use explicit conversion flag
ruf010_3.py:3:10: RUF010 Use explicit conversion flag
Found 2 errors.
The fix for an expression followed by an equals sign is not safe, because it changes behavior. In that specific case, the fix should be marked unsafe or should be suppressed.
$ cat >ruf010_4.py <<'# EOF'
print(f"{ascii(1)=}")
# EOF
$ python ruf010_4.py
ascii(1)='1'
$ ruff --isolated check --select RUF010 ruf010_4.py --fix
Found 1 error (1 fixed, 0 remaining).
$ cat ruf010_4.py
print(f"{1=!a}")
$ python ruf010_4.py
1=1
RUF010 introduces a syntax error when the argument is an unparenthesized lambda expression. The fix should add parentheses around the lambda expression.
$ cat >ruf010_5.py <<'# EOF'
print(f"{ascii(lambda: 1)}")
# EOF
$ ruff --isolated check --select RUF010 ruf010_5.py --diff 2>&1 | grep error:
error: Fix introduced a syntax error. Reverting all changes.
When the argument is an unparenthesized assignment expression, the fix misinterprets the colon of the :=
as the sigil of a format specifier. The fix should add parentheses around the assignment expression.
$ cat >ruf010_6.py <<'# EOF'
x = 1
print(f"{ascii(x := 2)}")
# EOF
$ python ruf010_6.py
2
$ ruff --isolated check --select RUF010 ruf010_6.py --fix
Found 1 error (1 fixed, 0 remaining).
$ python ruf010_6.py
Traceback (most recent call last):
File "ruf010_6.py", line 2, in <module>
print(f"{x := 2!a}")
^^^^^^^^^^
ValueError: Invalid format specifier '= 2!a' for object of type 'int'
The fix deletes the star from a starred expression. RUF010 should be suppressed in that context.
$ cat >ruf010_7.py <<'# EOF'
args = (b"\xa1", "latin-1")
print(f"{str(*args)}")
# EOF
$ python ruf010_7.py
¡
$ ruff --isolated check --select RUF010 ruf010_7.py --fix
Found 1 error (1 fixed, 0 remaining).
$ cat ruf010_7.py
args = (b"\xa1", "latin-1")
print(f"{args!s}")
$ python ruf010_7.py
(b'\xa1', 'latin-1')