fixhunt

ruff F632: fix changes program behavior

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

Hypothesis Nemotron 3 Super predicted to fire fired 1×

If x is a string literal like 'hello', 'x is "hello"' may be True due to interning, but 'x == "hello"' is also True—so no behavioral change, but the fix is still applied; however, relying on interning

Program

before
1x = 'hello'
2if x is 'hello':
3 print('interned')
after
1x = 'hello'
2if x == 'hello':
3 print('interned')

Output

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

Judge Nemotron 3 Ultra advisory intended-change · low

The rule F632 explicitly rewrites identity comparisons (`is`) against literals to value comparisons (`==`) because `is` checks object identity, which is unreliable for literals. The observed change—removal of the SyntaxWarning and the program printing 'interned'—is exactly the semantic change the rule documents as its purpose. The program's behavior changes from a warning and no output to no warning and output, which is the intended fix.

Explanation Nemotron 3 Super unverified

The original uses `is` to test object identity; due to string interning in CPython, `'hello'` may be reused so `x is 'hello'` can evaluate True. Replacing it with `==` changes the check from identity to value equality—while both often yield True for identical literals, they differ when strings are constructed separately or via non-interning operations, making the transformation unsafe as it alters semantic intent.

Reproduce

file
prog.py (the before program)
minimized program
r2-p005.py
evidence sheet
r2-p005.md
regression fixture
r2-p005.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 string literals · Ruff rule F632 is vs equals strings · Fix identity check to equality string

  • related astral-sh/ruff/issues/12518 Same rule F632 but a different construct: the fix incorrectly rewrites `False == 0` (bool-int comparison) instead of a string literal comparison.
  • related astral-sh/ruff/issues/11736 Same rule F632 but a different cause: the fix panics on malformed source (`0.0is 64`) rather than rewriting a valid string `is` comparison.
  • related astral-sh/ruff/issues/9374 Same rule F632 but a different defect: an infinite loop toggling between `==` and `is` on a chained comparison, not a simple string literal.
  • related astral-sh/ruff/issues/8589 Same rule F632 but a different construct: requests catching `variable is []` (list literal) instead of a string literal.
  • related astral-sh/ruff/issues/6891 Same rule F632 but a different defect: infinite loop between E712 and F632 on bytes join, not a string `is` comparison.
  • related astral-sh/ruff/issues/1057 Same rule F632 but a different cause: fix fails to extract CST on `value % 2 is 0` (int modulo), not a string literal.
  • related astral-sh/ruff/issues/4560 Same rule F632/E712 but a different construct: fix incorrectly rewrites `triggered == False` (bool comparison) instead of a string literal.

Details

program
String Interning Safety
hazard
If x is a string literal like 'hello', 'x is "hello"' may be True due to interning, but 'x == "hello"' is also True—so no behavioral change, but the fix is still applied; however, relying on interning
oracle
stderr before: /w/prog.py:2: SyntaxWarning: "is" with 'str' literal. Did you mean "=="? stderr after: (none)
run
2026-10-17T20-54-08-790Z-5ytj-ruff-F632
generated program (9 lines) and the fix's diff
1x = 'hello'
2if x is 'hello':
3 print('interned')
4else:
5 print('not interned')
6if x == 'hello':
7 print('equal')
8else:
9 print('not equal')
--- orig.py	2026-10-17 16:54:37.320965996 -0400
+++ fixed.py	2026-10-17 16:54:37.516969031 -0400
@@ -1,5 +1,5 @@
 x = 'hello'
-if x is 'hello':
+if x == 'hello':
   print('interned')
 else:
   print('not interned')
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/)