fixhunt

ruff PLR1733: fix changes program behavior

fix-changes-behaviorlabelled safereal · highrelated
Findings / 2026-10-17T21-02-04-500Z-1p30-ruff-PLR1733 / r1-p004ruff 0.17.111 → 5 lines2026-10-17 21:02 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

Inner loop reuses k,v; fix incorrectly binds to inner loop var instead of outer dict lookup.

Program

before
1outer = {'x': 10}
2middle = {'y': 20}
3for k, v in outer.items(): # outer k='x', v=10
4 for k, v in middle.items(): # inner k='y', v=20 (shadows outer)
5 x = outer[k] # triggers PLR1733: outer['y']?? -> KeyError
after
1outer = {'x': 10}
2middle = {'y': 20}
3for k, v in outer.items(): # outer k='x', v=10
4 for k, v in middle.items(): # inner k='y', v=20 (shadows outer)
5 x = v # triggers PLR1733: outer['y']?? -> KeyError

Output

stdout beforeexit 1
(no stdout)
KeyError: 'y'
stdout afterexit 0
(no stdout)
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory real · high

The fix incorrectly assumes the loop variable 'k' refers to the outer dictionary's key, but the inner loop shadows 'k' with the inner dictionary's key. Replacing 'outer[k]' with 'v' uses the inner loop's value instead of the outer loop's key, changing a KeyError into silent wrong behavior.

Explanation Nemotron 3 Super unverified

The original code uses `k` from the inner loop to index into `outer`, which shadows the outer `k`. After fixing, it incorrectly replaces `outer[k]` with `v`, where `v` comes from the inner loop (`'y'`), but this does not replicate the intended access—it changes the meaning entirely, causing different behavior despite avoiding the error.

Reproduce

file
prog.py (the before program)
minimized program
r1-p004.py
evidence sheet
r1-p004.md
regression fixture
r1-p004.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 PLR1733 --fix prog.py
python3 prog.py

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

PLR1733 fix · PLR1733 variable shadowing nested loops · PLR1733 dictionary key access loop variables · PLR1733 unused loop variable replacement

Details

program
Nested Loops Variable Capture
hazard
Inner loop reuses k,v; fix incorrectly binds to inner loop var instead of outer dict lookup.
oracle
exit 1 → 0 stderr before: KeyError: 'y' stderr after: (none)
run
2026-10-17T21-02-04-500Z-1p30-ruff-PLR1733
generated program (11 lines) and the fix's diff
1outer = {'x': 10}
2middle = {'y': 20}
3inner = [1, 2]
4trace = []
5for k, v in outer.items(): # outer k='x', v=10
6 for k, v in middle.items(): # inner k='y', v=20 (shadows outer)
7 for _ in inner:
8 trace.append((k, v)) # k,y v,20 from middle
9 x = outer[k] # triggers PLR1733: outer['y']?? -> KeyError
10 trace.append(('got', x))
11print('trace:', trace)
--- orig.py	2026-10-17 17:02:18.733156437 -0400
+++ fixed.py	2026-10-17 17:02:19.118161012 -0400
@@ -6,6 +6,6 @@
     for k, v in middle.items():       # inner k='y', v=20 (shadows outer)
         for _ in inner:
             trace.append((k, v))      # k,y v,20 from middle
-            x = outer[k]              # triggers PLR1733: outer['y']?? -> KeyError
+            x = v              # triggers PLR1733: outer['y']?? -> KeyError
             trace.append(('got', x))
 print('trace:', trace)
rule documentation given to the models
# unnecessary-dict-index-lookup (PLR1733)

Derived from the **Pylint** linter.

Fix is always available.

## What it does
Checks for key-based dict accesses during `.items()` iterations.

## Why is this bad?
When iterating over a dict via `.items()`, the current value is already
available alongside its key. Using the key to look up the value is
unnecessary.

## Example
```python
FRUITS = {"apple": 1, "orange": 10, "berry": 22}

for fruit_name, fruit_count in FRUITS.items():
    print(FRUITS[fruit_name])
```

Use instead:
```python
FRUITS = {"apple": 1, "orange": 10, "berry": 22}

for fruit_name, fruit_count in FRUITS.items():
    print(fruit_count)
```