# ruff RUF019: fix changes program behavior

Internal evidence sheet generated by fixhunt. Not an issue text. A human re-verifies, checks the duplicates
below, and writes the upstream report in their own words following the project's AI policy.

- Tool: ruff ruff 0.17.1
- Rule: RUF019 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): real, severity 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.
- Program: minimized from 22 to 9 lines

## Reproducer

```python
state = []
class D:
    def __contains__(self, k):
        return k == 'x'
    def __getitem__(self, k):
        return 1 if k == 'x' else None
d = D()
if "x" in d and d["x"]:
    print("true", state)
```

## Commands

```sh
python3 prog.py
ruff check --preview --isolated --select RUF019 --fix prog.py
python3 prog.py
```

## Observed

```
stdout before:
true []
stdout after:

exit 0 → 1
stderr before: (none)
stderr after: AttributeError: 'D' object has no attribute 'get'
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:43:27.006387129 -0400
+++ fixed.py	2026-10-22 13:43:28.930786122 -0400
@@ -5,5 +5,5 @@
     def __getitem__(self, k):
         return 1 if k == 'x' else None
 d = D()
-if "x" in d and d["x"]:
+if d.get("x"):
     print("true", state)
```

## Why the rewrite is not equivalent (model draft, verify before use)

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`.

## Upstream search

Queries: "RUF019 fix", "RUF019 dict get optimization", "in operator redundant check", "__contains__ method replacement"

- duplicate: https://github.com/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: https://github.com/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: https://github.com/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><summary>All hits</summary>

- [github, open] Possible false positives for RUF019 — https://github.com/astral-sh/ruff/issues/14011
- [github, closed] unused-function-argument not silenced by prefixed underscore if variable name is "次" — https://github.com/astral-sh/ruff/issues/28721
- [github, closed] `contains_effect` should consider f-strings to have effects — https://github.com/astral-sh/ruff/issues/12953
- [github, closed] False negative for RUF019 with `not` operator — https://github.com/astral-sh/ruff/issues/12285
- [github, closed] Fixed code unformatted — https://github.com/astral-sh/ruff/issues/8619
- [github, closed] Add option to disable preview warnings — https://github.com/astral-sh/ruff/issues/8620
- [github, open] Improve detection of redundant parenthesis — https://github.com/astral-sh/ruff/issues/19027
- [github, open] Implement remaining `pycodestyle` rules — https://github.com/astral-sh/ruff/issues/2402
- [github, open] Feature: Port Sonar's Python scanner checks — https://github.com/astral-sh/ruff/issues/4935
- [github, open] Support for refurb — https://github.com/astral-sh/ruff/issues/1348
- [github, open] Preview rules — https://github.com/astral-sh/ruff/issues/27051
- [github, open] Implement Pylint — https://github.com/astral-sh/ruff/issues/970
- [github, open] Implement C0325 to catch unnecessary parentheses — https://github.com/astral-sh/ruff/issues/2389
- [github, open] Ruleset Suggestion: wemake-python-styleguide — https://github.com/astral-sh/ruff/issues/3845
- [github, closed] PYI061 fix can change operator precedence — https://github.com/astral-sh/ruff/issues/20265
- [github, closed] `TC006` in `0.8.1` is too broad — https://github.com/astral-sh/ruff/issues/14676

</details>
