ruff SIM911: fix changes program behavior
Hypothesis Nemotron 3 Super predicted to fire fired 1×
string formatting edge cases: %, format, f-strings, repr vs str, nested quotes
Program
Output
[]
[('a', 1), ('b', 2)]- fired
- 1 before · 0 after
- runs
- each version twice, same file name, no network
Judge Nemotron 3 Ultra advisory real · high
The rule rewrites `zip(d.keys(), d.values())` to `d.items()`, but `zip` returns a reusable iterator while `dict.items()` returns a view that reflects the dictionary's current state. In the program, the view is consumed by the for-loop, so `list(zipped)` afterwards yields the items, whereas the original exhausted zip iterator yields an empty list. This is a silent change in runtime behavior for plausible code.
Explanation Nemotron 3 Super unverified
The original `zip` creates an iterator consumed by the loop; afterwards it’s exhausted, so converting it to a list yields []. Replacing it with `dict.items()` returns a view that remains reusable—iterating over it does not consume the view itself—so the subsequent `list(zipped)` captures all items, changing the output from [] to [('a', 1), ('b', 2)]. This alters program behavior, making the rewrite unsafe.
Reproduce
- file
prog.py(the before program)- minimized program
- r1-p006.py
- evidence sheet
- r1-p006.md
- regression fixture
- r1-p006.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 SIM911 --fix prog.py python3 prog.py
Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra
SIM911 fix · SIM911 dict keys values zip · Ruff lint zip dictionary iteration · Rule SIM911 replace zip with items
- related astral-sh/ruff/issues/18775 SIM910/SIM911 fix deletes comments inside the get call
- related astral-sh/ruff/issues/18778 SIM911 false positive when methods have arguments that get dropped by .items()
- related astral-sh/ruff/issues/18776 SIM911 fix causes syntax error due to missing parentheses
- related astral-sh/ruff/issues/11125 SIM911 false positive on non-zip attribute calls like plt.bar(dict.keys(), dict.values())
- related astral-sh/ruff/issues/9319 original implementation of SIM911 rule for zip(dict.keys(), dict.values()) → dict.items()
- related astral-sh/ruff/issues/18777 SIM910/SIM911 false negative when variable is named dict
Details
- program
- String Formatting Edge Cases
- hazard
- string formatting edge cases: %, format, f-strings, repr vs str, nested quotes
- oracle
stdout before: [] stdout after: [('a', 1), ('b', 2)]- run
- 2026-10-17T20-38-44-795Z-ekj4-ruff-SIM911
generated program (13 lines) and the fix's diff
--- orig.py 2026-10-17 16:38:58.621792777 -0400 +++ fixed.py 2026-10-17 16:38:58.785800554 -0400 @@ -1,5 +1,5 @@ d = {'a': 1, 'b': 2} -zipped = zip(d.keys(), d.values()) +zipped = d.items() for k, v in zipped: s = f'{k!r}:{v!r}' print(s)
rule documentation given to the models
# zip-dict-keys-and-values (SIM911)
Derived from the **flake8-simplify** linter.
Fix is always available.
## What it does
Checks for use of `zip()` to iterate over keys and values of a dictionary at once.
## Why is this bad?
The `dict` type provides an `.items()` method which is faster and more readable.
## Example
```python
flag_stars = {"USA": 50, "Slovenia": 3, "Panama": 2, "Australia": 6}
for country, stars in zip(flag_stars.keys(), flag_stars.values()):
print(f"{country}'s flag has {stars} stars.")
```
Use instead:
```python
flag_stars = {"USA": 50, "Slovenia": 3, "Panama": 2, "Australia": 6}
for country, stars in flag_stars.items():
print(f"{country}'s flag has {stars} stars.")
```
## Fix safety
This rule's fix is marked as safe, unless the expression contains comments.
## References
- [Python documentation: `dict.items`](https://docs.python.org/3/library/stdtypes.html#dict.items)