fixhunt

ruff F632: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · lowrelated
Findings / 2026-10-17T20-54-08-790Z-5ytj-ruff-F632 / r1-p007ruff 0.17.115 → 5 lines2026-10-17 20:54 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

If x is a numpy array, 'x is 5' is always False, but 'x == 5' returns an array of booleans

Program

before
1class MockArray:
2 def __init__(self, val):
3 self.val = val
4x = MockArray(5)
5print(x is 5) # False
after
1class MockArray:
2 def __init__(self, val):
3 self.val = val
4x = MockArray(5)
5print(x == 5) # False

Output

stdout beforeexit 0
False
/w/prog.py:5: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
stdout afterexit 0
False
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · low

The rule rewrites identity comparison (`is`) to equality comparison (`==`) for literals, which is the documented semantic change. The program's custom class `MockArray` does not define `__eq__`, so `x == 5` falls back to identity comparison and returns `False`, matching the original `x is 5` result. The observed difference is the removal of the SyntaxWarning, which is the intended effect of the fix.

Explanation Nemotron 3 Super unverified

The original expression `x is 5` checks identity between object `x` and integer literal `5`, which is always false for distinct objects; the warning notes this misuse. Replacing `is` with `==` changes the operation to value equality, invoking `__eq__` if defined or default object comparison—here still false but semantically different: identity versus equivalence. The fix alters the program’s meaning by substituting a fundamentally different operation, despite both yielding false in this case. This violates semantic preservation because the logical intent of the test changes, even if the outcome coincides here. The tool incorrectly labels the rewrite safe, ignoring that `is` and `==` are not interchangeable in general.

Reproduce

file
prog.py (the before program)
minimized program
r1-p007.py
evidence sheet
r1-p007.md
regression fixture
r1-p007.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 · F632 identity comparison integer · ruff F632 is int literal warning · MockArray equality check replacement

  • related astral-sh/ruff/issues/12518 Same rule F632 but a different construct: the fix incorrectly suggests '==' for 'False is 0' where 'is' is actually correct.
  • related astral-sh/ruff/issues/11736 Same rule F632 but a different cause: the fixer panics on a malformed string containing 'is' rather than rewriting a comparison.
  • related astral-sh/ruff/issues/9374 Same rule F632 but a different construct: an infinite loop toggling between '==' and 'is' in a chained comparison.
  • related astral-sh/ruff/issues/8589 Same rule F632 but a different construct: requests catching 'variable is []' list-literal comparisons.
  • related astral-sh/ruff/issues/6891 Same rules F632/E712 but a different construct: infinite loop when fixing comparisons inside a generator expression.
  • related astral-sh/ruff/issues/1057 Same rule F632 but a different cause: the fixer chokes on a lambda containing 'is 0' and fails to extract a CST.
  • related astral-sh/ruff/issues/4560 Same rule F632/E712 but a different construct: fix incorrectly changes '==' to 'is' for NumPy/Pandas arrays where element-wise comparison is needed.

Details

program
Numpy Array Comparison
hazard
If x is a numpy array, 'x is 5' is always False, but 'x == 5' returns an array of booleans
oracle
stderr before: /w/prog.py:5: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? stderr after: (none)
run
2026-10-17T20-54-08-790Z-5ytj-ruff-F632
generated program (15 lines) and the fix's diff
1import sys
2sys.path.insert(0, '.')
3# Cannot import numpy per constraints → simulate with a mock class that mimics np.array behavior
4class MockArray:
5 def __init__(self, val):
6 self.val = val
7 def __eq__(self, other):
8 return [self.val == other] # returns list of bool → like np.array([5]) == 5 → [True]
9 def __is__(self, other):
10 return False # not real, but we simulate
11x = MockArray(5)
12print(x is 5) # False
13print(x == 5) # [True] → truth value of list is True → changes conditional behavior
14# Before: `if x is 5:` → False
15# After fix: `if x == 5:` → if [True]: → True → different branch
--- orig.py	2026-10-17 16:54:27.078806775 -0400
+++ fixed.py	2026-10-17 16:54:27.274809834 -0400
@@ -9,7 +9,7 @@
     def __is__(self, other):
         return False  # not real, but we simulate
 x = MockArray(5)
-print(x is 5)   # False
+print(x == 5)   # False
 print(x == 5)   # [True] → truth value of list is True → changes conditional behavior
 # Before: `if x is 5:` → False
 # After fix: `if x == 5:` → if [True]: → True → different branch
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/)