# ruff F632: 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: F632 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): real, severity high. The rule rewrites 'd is {}' to 'd == {}', changing an identity check into a value comparison. The program defines a class with a custom __eq__ that returns 42, so the equality comparison invokes that method and prints 42, whereas the original identity comparison correctly returned False. The documentation presents the rewrite as a safe equivalence for literal comparisons, but it is not equivalent when the left-hand operand overrides equality.
- Program: minimized from 9 to 5 lines

## Reproducer

```python
class BadDict:
    def __eq__(self, other):
        return 42
d = BadDict()
print(d is {})     # False
```

## Commands

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

## Observed

```
stdout before:
False
stdout after:
42
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:33:59.673563633 -0400
+++ fixed.py	2026-10-22 13:34:01.793599341 -0400
@@ -2,4 +2,4 @@
     def __eq__(self, other):
         return 42
 d = BadDict()
-print(d is {})     # False
+print(d == {})     # False
```

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

The original expression `d is {}` checks object identity between instance `d` and a newly created empty dict literal; since they are distinct objects, it evaluates to `False`. The rewrite replaces this with `d == {}`, which invokes `__eq__` on `d` (defined in `BadDict`) passing the new dict as `other`. That method returns the integer `42`, so the print outputs `42` instead of `False`, changing both type and value. Thus the transformation alters program semantics.

## Upstream search

Queries: "F632 fix", "ruff F632 identity comparison dict", "F632 replace is with equals literal", "rule F632 fix object equality check"

- related: https://github.com/astral-sh/ruff/issues/12518
  Same rule F632 but different construct: false positive when comparing `False == 0` instead of identity comparison with a custom `__eq__`.
- related: https://github.com/astral-sh/ruff/issues/11736
  Same rule F632 but different construct: panic on invalid syntax rather than behavior-changing fix.
- related: https://github.com/astral-sh/ruff/issues/9374
  Same rule F632 but different construct: infinite loop toggling `==`/`is` in a chained comparison.
- related: https://github.com/astral-sh/ruff/issues/8589
  Same rule F632 but different construct: catching `variable is []` literal comparison.
- related: https://github.com/astral-sh/ruff/issues/6891
  Same rule F632 but different construct: infinite loop with E712 on generator expression.
- related: https://github.com/astral-sh/ruff/issues/1057
  Same rule F632 but different construct: choking on invalid comparison inside a lambda default argument.

<details><summary>All hits</summary>

- [github, closed] unused-function-argument not silenced by prefixed underscore if variable name is "次" — https://github.com/astral-sh/ruff/issues/28721
- [github, open] Implement Pylint — https://github.com/astral-sh/ruff/issues/970
- [github, closed] Isort rule misses unsorted imports when using user-level ruff.toml file on windows — https://github.com/astral-sh/ruff/issues/19646
- [github, closed] [Feature Idea] Add column headers to `ruff check --statistics`, to avoid ambiguity — https://github.com/astral-sh/ruff/issues/13717
- [github, closed] F632 suggestion leads to false positive when comparing False == 0 — https://github.com/astral-sh/ruff/issues/12518
- [github, closed] Rule F632 cause panic — https://github.com/astral-sh/ruff/issues/11736
- [github, closed] [QA] Should Ruff be able to fix indentation errors (E999) ? — https://github.com/astral-sh/ruff/issues/11846
- [github, closed] Infinite loop in F632/E711 — https://github.com/astral-sh/ruff/issues/9374
- [github, closed] Catch `variable is []` — https://github.com/astral-sh/ruff/issues/8589
- [github, closed] Rules E712,F632 causes infinite loop — https://github.com/astral-sh/ruff/issues/6891
- [tavily] [bug] ruff chokes when fixing invalid comparison (`F632`) · Issue #1057 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/1057
- [tavily] D205 not fixable · Issue #1672 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/1672
- [tavily] Multi-root workspace makes Ruff use wrong settings · Issue #925 · astral-sh/ruff-vscode · GitHub — https://github.com/astral-sh/ruff-vscode/issues/925
- [tavily] Feature: Port Sonar's Python scanner checks · Issue #4935 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/4935

</details>
