ruff RUF019: fix changes program behavior
Hypothesis Nemotron 3 Super predicted to fire fired 1×
Original evaluates 'in' then __getitem__; fix may evaluate __getitem__ twice or change order if not using .get().
Program
Output
true []
(no stdout) AttributeError: 'D' object has no attribute 'get'
- fired
- 1 before · 0 after
- runs
- each version twice, same file name, no network
Judge Nemotron 3 Ultra advisory real · high
The rule assumes the target object has a `get` method like a standard dict, but the program uses a custom class that implements `__contains__` and `__getitem__` without providing `get`. The rewrite replaces a working containment check and item access with a call to a missing method, causing an AttributeError at runtime.
Explanation Nemotron 3 Super unverified
The original condition checks membership via `__contains__` then accesses `d['x']` using `__getitem__`. The replacement uses `dict.get`, which requires a `get` method; class `D` lacks it, causing an `AttributeError`. Since `__contains__` returns `True` for `'x'` and `__getitem__` returns `1` (truthy), the original prints `"true []"`; the rewritten version fails before reaching that point. Thus, the fix alters behavior by assuming a dictionary interface not present in `D`.
Reproduce
- file
prog.py(the before program)- minimized program
- r1-p003.py
- evidence sheet
- r1-p003.md
- regression fixture
- r1-p003.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 RUF019 --fix prog.py python3 prog.py
Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra
RUF019 fix · RUF019 dict get optimization · in operator redundant check · __contains__ method replacement
- duplicate astral-sh/ruff/issues/14011 Same rule RUF019 and same defect class: the fix replaces 'key in obj and obj[key]' with 'obj.get(key)' on an object lacking .get(), changing behavior.
- related astral-sh/ruff/issues/12953 Same rule RUF019 but different cause: f-string side effects in contains_effect vs missing .get() method on custom mapping.
- related astral-sh/ruff/issues/12285 Same rule RUF019 but different construct: missing detection with 'not' operator vs incorrect rewrite on custom mapping without .get().
Details
- program
- Evaluation order and side effects in merged expressions
- hazard
- Original evaluates 'in' then __getitem__; fix may evaluate __getitem__ twice or change order if not using .get().
- oracle
stdout before: true [] stdout after: exit 0 → 1 stderr before: (none) stderr after: AttributeError: 'D' object has no attribute 'get'- run
- 2026-10-17T21-39-23-080Z-ah8u-ruff-RUF019
generated program (22 lines) and the fix's diff
--- orig.py 2026-10-17 17:39:37.155519931 -0400 +++ fixed.py 2026-10-17 17:39:37.312518594 -0400 @@ -11,7 +11,7 @@ return self[k] if k in self else default d = D() -if "x" in d and d["x"]: +if d.get("x"): print("true", state) else: print("false", state)
rule documentation given to the models
# unnecessary-key-check (RUF019)
Derived from the **Ruff-specific rules** linter.
Fix is always available.
## What it does
Checks for unnecessary key checks prior to accessing a dictionary.
## Why is this bad?
When working with dictionaries, the `get` can be used to access a value
without having to check if the dictionary contains the relevant key,
returning `None` if the key is not present.
## Example
```python
if "key" in dct and dct["key"]:
...
```
Use instead:
```python
if dct.get("key"):
...
```
## Fix safety
This rule's fix is marked as safe, unless the expression contains comments
or may have side effects.