ruff F632: fix changes program behavior
Hypothesis Nemotron 3 Super predicted to fire fired 1×
dict ordering, duplicate keys, __hash__/__eq__ overrides, sets
Program
Output
False
42
- fired
- 1 before · 0 after
- runs
- each version twice, same file name, no network
Judge Nemotron 3 Ultra advisory real · 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.
Explanation Nemotron 3 Super unverified
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.
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 F632 --fix prog.py python3 prog.py
Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra
F632 fix · ruff F632 identity comparison dict · F632 replace is with equals literal · rule F632 fix object equality check
- related 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 astral-sh/ruff/issues/11736 Same rule F632 but different construct: panic on invalid syntax rather than behavior-changing fix.
- related astral-sh/ruff/issues/9374 Same rule F632 but different construct: infinite loop toggling `==`/`is` in a chained comparison.
- related astral-sh/ruff/issues/8589 Same rule F632 but different construct: catching `variable is []` literal comparison.
- related astral-sh/ruff/issues/6891 Same rule F632 but different construct: infinite loop with E712 on generator expression.
- related astral-sh/ruff/issues/1057 Same rule F632 but different construct: choking on invalid comparison inside a lambda default argument.
Details
- program
- Dict Ordering and Overrides
- hazard
- dict ordering, duplicate keys, __hash__/__eq__ overrides, sets
- oracle
stdout before: False stdout after: 42- run
- 2026-10-17T20-54-08-790Z-5ytj-ruff-F632
generated program (9 lines) and the fix's diff
--- orig.py 2026-10-17 16:54:26.411796362 -0400 +++ fixed.py 2026-10-17 16:54:26.574798907 -0400 @@ -4,6 +4,6 @@ def __hash__(self): return 42 d = BadDict() -print(d is {}) # False +print(d == {}) # False print(d == {}) # True after fix → triggers __eq__ # Before fix: identity check → False; after fix: equality → True (calls __eq__)
rule documentation given to the models
# is-literal (F632)
Derived from the **Pyflakes** linter.
Fix is always available.
## What it does
Checks for `is` and `is not` comparisons against literals, like integers,
strings, or lists.
## Why is this bad?
The `is` and `is not` comparators operate on identity, in that they check
whether two objects are the same object. If the objects are not the same
object, the comparison will always be `False`. Using `is` and `is not` with
constant literals often works "by accident", but are not guaranteed to produce
the expected result.
As of Python 3.8, using `is` and `is not` with constant literals will produce
a `SyntaxWarning`.
This rule will also flag `is` and `is not` comparisons against non-constant
literals, like lists, sets, and dictionaries. While such comparisons will
not raise a `SyntaxWarning`, they are still likely to be incorrect, as they
will compare the identities of the objects instead of their values, which
will always evaluate to `False`.
Instead, use `==` and `!=` to compare literals, which will compare the
values of the objects instead of their identities.
## Example
```python
x = 200
if x is 200:
print("It's 200!")
```
Use instead:
```python
x = 200
if x == 200:
print("It's 200!")
```
## References
- [Python documentation: Identity comparisons](https://docs.python.org/3/reference/expressions.html#is-not)
- [Python documentation: Value comparisons](https://docs.python.org/3/reference/expressions.html#value-comparisons)
- [_Why does Python log a SyntaxWarning for ‘is’ with literals?_ by Adam Johnson](https://adamj.eu/tech/2020/01/21/why-does-python-3-8-syntaxwarning-for-is-literal/)