ruff PLR1733: fix changes program behavior
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
Output
(no stdout) KeyError: 'y'
(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
- related astral-sh/ruff/issues/25182 same rule PLR1733 but different construct (for-else clause vs nested loop variable shadowing)
- related astral-sh/ruff/issues/29422 same rule PLR1733 mentioned among other fix bugs but no detail on this construct
- related astral-sh/ruff/issues/25150 same rule PLR1733 false positive but different construct (for-else clause vs nested loop variable shadowing)
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
--- 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)
```