fixhunt

ruff F632: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · highduplicate
Findings / 2026-10-17T20-54-08-790Z-5ytj-ruff-F632 / r2-p001ruff 0.17.19 → 6 lines2026-10-17 20:54 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

star-imports, module-level side effects, __all__

Program

before
1__all__ = ['x']
2x = []
3if x is []:
4 print('same object')
5del x
6from __main__ import *
after
1__all__ = ['x']
2x = []
3if x == []:
4 print('same object')
5del x
6from __main__ import *

Output

stdout beforeexit 1
(no stdout)
AttributeError: module '__main__' has no attribute 'x'
stdout afterexit 1
same object
AttributeError: module '__main__' has no attribute 'x'
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · high

The rule rewrites `x is []` to `x == []`, changing an identity comparison to a value comparison. The documentation explicitly states that `is` with literals is incorrect and that `==` should be used instead, so the behavioral change (from False to True) is exactly the semantic change the rule intends.

Explanation Nemotron 3 Super unverified

The original condition `x is []` checks identity; since each literal `[]` creates a new list object, it evaluates to False, so nothing prints. After rewriting to `x == []`, equality compares contents—both lists are empty—so True triggers printing 'same object'. Thus behavior changes because identity versus value equality differ for mutable objects like lists. No other modifications affect output.

Reproduce

file
prog.py (the before program)
minimized program
r2-p001.py
evidence sheet
r2-p001.md
regression fixture
r2-p001.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 list literal · is empty list check replacement · list equality vs identity lint

  • related astral-sh/ruff/issues/12518 Same rule F632 but different construct: False == 0 comparison instead of list identity check.
  • related astral-sh/ruff/issues/11736 Same rule F632 but different trigger: panic on invalid syntax rather than behavior-changing fix.
  • related astral-sh/ruff/issues/9374 Same rule F632 but different defect: infinite loop between == and is on chained comparisons.
  • duplicate astral-sh/ruff/issues/8589 Same rule F632 and same construct: 'variable is []' identity comparison being incorrectly rewritten to '== []'.
  • related astral-sh/ruff/issues/6891 Same rule F632 but different defect: infinite loop with E712 on generator expressions.
  • related astral-sh/ruff/issues/1057 Same rule F632 but different construct: 'value % 2 is 0' modulo comparison causing fix panic.
  • related astral-sh/ruff/pull/8607 Same rule F632 but different construct: 'None is False' constant comparison stabilization.
  • related astral-sh/ruff/pull/12049 Same rule F632 but broader stabilization work on 'is' comparisons to lists, not the specific behavior-change fix.

Details

program
Star Imports and Module Effects
hazard
star-imports, module-level side effects, __all__
oracle
stdout before: stdout after: same object
run
2026-10-17T20-54-08-790Z-5ytj-ruff-F632
generated program (9 lines) and the fix's diff
1__all__ = ['x']
2x = []
3if x is []:
4 print('same object')
5else:
6 print('different')
7del x
8from __main__ import *
9print(len(x))
--- orig.py	2026-10-17 16:54:35.720941205 -0400
+++ fixed.py	2026-10-17 16:54:36.128947530 -0400
@@ -1,6 +1,6 @@
 __all__ = ['x']
 x = []
-if x is []:
+if x == []:
   print('same object')
 else:
   print('different')
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/)