# 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): intended-change, severity high. The rule rewrites 'x is []' to 'x == []' because identity comparison with a list literal is always False; the program demonstrates the semantic change by printing 'cache hit' only after the fix, which is exactly the behavior the rule documents as correct.
- Program: minimized from 18 to 6 lines

## Reproducer

```python
cache = []
def get_cache():
  return cache
x = get_cache()
if x is []:
  print('cache hit')
```

## Commands

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

## Observed

```
stdout before:

stdout after:
cache hit
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:34:28.894055941 -0400
+++ fixed.py	2026-10-22 13:34:31.196094739 -0400
@@ -2,5 +2,5 @@
 def get_cache():
   return cache
 x = get_cache()
-if x is []:
+if x == []:
   print('cache hit')
```

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

The original condition `x is []` checks whether `x` refers to the exact same list object as the newly created literal `[]`. Since each evaluation of `[]` produces a distinct list object, even if two lists have identical contents, they are different objects in memory. Therefore, `x is []` evaluates to False when `x` is the list returned by `get_cache()`, which is the same object as `cache`. After the rewrite, `x == []` compares the contents of the lists for equality. Because both lists are empty, this comparison returns True, causing the print statement to execute where it previously did not. This change in behavior occurs because identity (`is`) and equality (`==`) are fundamentally different operations in Python. The fix incorrectly assumes they are interchangeable here, but they are not—especially when dealing with mutable objects like lists that can have equal contents without being the same object. Thus, the transformation alters the program’s semantics.

## Upstream search

Queries: "F632 fix", "ruff F632 identity comparison list literal", "F632 replace is with equals empty list", "rule F632 fix identity check to equality"

- related: https://github.com/astral-sh/ruff/issues/12518
  Same F632 rule but different construct: False == 0 boolean/integer comparison vs list identity check.
- related: https://github.com/astral-sh/ruff/issues/11736
  Same F632 rule but different trigger: parser panic on invalid syntax vs valid list identity comparison.
- related: https://github.com/astral-sh/ruff/issues/9374
  Same F632 rule but different construct: chained comparison loop (c > 0 == None) vs simple list identity check.
- duplicate: https://github.com/astral-sh/ruff/issues/8589
  Same F632 rule and same construct: 'variable is []' list identity comparison incorrectly rewritten to '=='.
- related: https://github.com/astral-sh/ruff/issues/6891
  Same F632 rule but different construct: complex generator expression comparison causing infinite loop vs simple list identity.
- related: https://github.com/astral-sh/ruff/issues/1057
  Same F632 rule but different construct: modulo comparison 'value % 2 is 0' causing CST extraction failure vs list identity.

<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
- [github, open] Feature: Port Sonar's Python scanner checks — https://github.com/astral-sh/ruff/issues/4935

</details>
