Skip to content

Raw strings break the FLY002 fix #21082

@dscorbett

Description

@dscorbett

Summary

When the argument to str.join contains only string literals and the first is raw, the fix for static-join-to-f-string (FLY002) can introduce a syntax error or change the program’s behavior.

If a subsequent string isn’t raw, its contents will be inserted into the fix’s string, regardless of syntax errors. Example:

$ cat >fly002_1.py <<'# EOF'
"".join((r"", '"'))
# EOF

$ ruff check --isolated fly002_1.py --select FLY002 --unsafe-fixes --diff 2>&1 | grep error:
error: Fix introduced a syntax error. Reverting all changes.

Another example:

$ cat >fly002_2.py <<'# EOF'
"".join((r"", "\\"))
# EOF

$ ruff check --isolated fly002_2.py --select FLY002 --unsafe-fixes --diff 2>&1 | grep error:
error: Fix introduced a syntax error. Reverting all changes.

Another example:

$ cat >fly002_3.py <<'# EOF'
"".join((r"", "\0"))
# EOF

$ ruff check --isolated fly002_3.py --select FLY002 --unsafe-fixes --fix
Found 1 error (1 fixed, 0 remaining).

$ xxd fly002_3.py
00000000: 7222 0022 0a                             r".".

$ python fly002_3.py 2>&1 | tail -n 1
SyntaxError: source code cannot contain null bytes

It can also change the program’s behavior. Example:

$ cat >fly002_4.py <<'# EOF'
print("".join((r"", r'".__class__.__name__, 0xA, sep="~')))
# EOF

$ python fly002_4.py
".__class__.__name__, 0xA, sep="~

$ ruff check --isolated fly002_4.py --select FLY002 --unsafe-fixes --fix
Found 1 error (1 fixed, 0 remaining).

$ cat fly002_4.py
print(r"".__class__.__name__, 0xA, sep="~")

$ python fly002_4.py
str~10

If any string contains a carriage return via an escape sequence, the fix emits a multiline string containing a literal carriage return. Literal carriage returns are interpreted as line feeds, so this changes the program’s behavior. Example:

$ cat >fly002_5.py <<'# EOF'
print(repr("".join((r"", "\r"))))
# EOF

$ python fly002_5.py
'\r'

$ ruff check --isolated fly002_5.py --select FLY002 --unsafe-fixes --fix
Found 1 error (1 fixed, 0 remaining).

$ xxd fly002_5.py
00000000: 7072 696e 7428 7265 7072 2872 2222 220d  print(repr(r""".
00000010: 2222 2229 290a                           """)).

$ python fly002_5.py
'\n'

Version

ruff 0.14.2 (83a3bc4 2025-10-23)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixesRelated to suggested fixes for violations

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions