fixhunt

ruff W605: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · lowduplicate
Findings / 2026-10-17T20-50-05-853Z-2tuo-ruff-W605 / r1-p002ruff 0.17.18 → 2 lines2026-10-17 20:50 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

mutable default arguments and aliasing after a rewrite

Program

before
1def f(x=['\_']):
2 x[0] = 'changed'
after
1def f(x=[r'\_']):
2 x[0] = 'changed'

Output

stdout beforeexit 0
(no stdout)
/w/prog.py:1: SyntaxWarning: invalid escape sequence '\_'
stdout afterexit 0
(no stdout)
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · low

The rule rewrites the string literal containing an invalid escape sequence '\_' into a raw string r'\_' to eliminate the SyntaxWarning, which is the documented purpose. The stderr difference (warning disappears) is exactly the intended semantic change, not a behavioral bug.

Explanation Nemotron 3 Super unverified

The original default argument `['\_']` contains a backslash followed by underscore; Python interprets `\_` as an invalid escape sequence but still treats it as two literal characters: backslash then underscore. After the rewrite, `r'\_'` is a raw string where the backslash is preserved literally, so the list becomes `[r'\_']`, which is identical in content—both represent a single string consisting of a backslash and an underscore. However, the original code triggered a SyntaxWarning due to the invalid escape, while the raw string suppresses it. The functional behavior of the list mutation (`x[0] = 'changed'`) remains unchanged because the string value is the same in both cases. Thus, the rewrite does not alter program semantics—it only eliminates a warning. The observed difference is purely diagnostic, not behavioral. Any claim of changed behavior must stem from reliance on the warning’s presence, which is not part of the program’s semantics.

Reproduce

file
prog.py (the before program)
minimized program
r1-p002.py
evidence sheet
r1-p002.md
regression fixture
r1-p002.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py
ruff check --preview --isolated --select W605 --fix prog.py
python3 prog.py

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

W605 fix · W605 mutable default argument list literal · W605 function parameter default value escaping backslash underscore · W605 def f x equals bracket backslash underscore bracket

Details

program
Mutable default arguments and aliasing
hazard
mutable default arguments and aliasing after a rewrite
oracle
stderr before: /w/prog.py:1: SyntaxWarning: invalid escape sequence '\_' stderr after: (none)
run
2026-10-17T20-50-05-853Z-2tuo-ruff-W605
generated program (8 lines) and the fix's diff
1def f(x=['\_']):
2 x[0] = 'changed'
3 return x
4print(f())
5print(f())
6s = ['\_']
7f(s)
8print(s)
--- orig.py	2026-10-17 16:50:20.330520613 -0400
+++ fixed.py	2026-10-17 16:50:20.541524714 -0400
@@ -1,8 +1,8 @@
-def f(x=['\_']):
+def f(x=[r'\_']):
     x[0] = 'changed'
     return x
 print(f())
 print(f())
-s = ['\_']
+s = [r'\_']
 f(s)
 print(s)
rule documentation given to the models
# invalid-escape-sequence (W605)

Derived from the **pycodestyle** linter.

Fix is always available.

## What it does
Checks for invalid escape sequences.

## Why is this bad?
Invalid escape sequences are deprecated in Python 3.6.

## Example
```python
regex = "\.png$"
```

Use instead:
```python
regex = r"\.png$"
```

Or, if the string already contains a valid escape sequence:
```python
value = "new line\nand invalid escape \_ here"
```

Use instead:
```python
value = "new line\nand invalid escape \\_ here"
```

## References
- [Python documentation: String and Bytes literals](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)