Use is/is not for same-enum identity comparisons (source)#171591
Conversation
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
|
While not mandatory I suggest splitting this into few smaller PR since it changes 765 files which make it impossible to review and very easily create a merge conflict. |
|
Yea, I think I agree 😅 |
|
Considering the number of CI failures with the patch applied, it suggests a definite regression is going on. I don't know if the issue is with the patch, or if the issue comes from the mypy plugin, but I suggest to avoid changing "tests" at the same time as "homeassistant" |
Yes, and I already found the issue. Modified the plugin. You're right though - I will create 2 Prs and split out homeassistant and test changes! |
Mechanical codemod that replaces `==` with `is` (and `!=` with `is not`) on every line where both operands statically resolve to the same enum class — as identified by `mypy_plugins.enum_identity_compare` from home-assistant#171551. This commit covers `homeassistant/` only (156 files, 289 sites). The companion tests-side change is in home-assistant#171689. Scope is intentionally narrow: - Plain `enum.Enum` subclasses: `Enum.__eq__` is identity-based, so `==` and `is` are mathematically equivalent. - `homeassistant.data_entry_flow.FlowResultType`: explicitly allowlisted StrEnum where HA's framework normalizes every consumer-facing result to the enum instance. NOT changed: other StrEnum/IntEnum/ReprEnum subclasses (their `__eq__` delegates to str/int equality and accepts raw primitives at runtime), and Flag/IntFlag (bitwise `==` is idiomatic). `homeassistant/data_entry_flow.py:497` is the one exception left as `!=` (with a noqa) because it runs before the legacy-string normalization shim a few lines below. Verified by re-running the mypy plugin against the codemodded source: zero remaining violations on this side.
The original line had two `==` comparisons on it: an enum compare (entry.state == ConfigEntryState.LOADED) and an unrelated str-vs-str compare (entry.domain == DOMAIN). The codemod's line-level replacement swapped both. Restoring the str compare to `==` since string interning is not guaranteed and the mypy plugin only flagged the enum site. Resolves Copilot review comment on home-assistant#171591.
…ant#171699) The IntentResponseType.ERROR identity swap in DefaultAgent.async_handle_intents is being handled in its own PR (home-assistant#171699) alongside an adjustment to a brittle mock_calls assertion that broke when the operator changed. Reverting just that one site here so the two PRs don't conflict on the same line.
Re-running the plugin (now handling LiteralType and UnionType, per home-assistant#171551) flagged 38 additional same-enum compare sites in homeassistant/ — typically the elif arm of an is/== chain (where mypy narrows the operand to a union of literals) and Literal[E.X]-annotated parameters. Pure ==/is and !=/is-not swaps, no other changes.
Proposed change
Mechanical codemod that replaces
==withis(and!=withis not)on every line where both operands statically resolve to the same enum
class — as identified by
mypy_plugins.enum_identity_comparefrom#171551.
This PR covers
homeassistant/source files only (156 files,289 sites). The corresponding tests-side codemod is in #171689.
Scope is intentionally narrow:
enum.Enumsubclasses — 100% safe, becauseEnum.__eq__is identity-based:
==andisgive the same result.homeassistant.data_entry_flow.FlowResultType— the onlyStrEnumon a curated allowlist, because HA's framework controlsevery value-assigning callsite (
async_show_form,async_create_entry,etc. all set it to the enum instance).
What is NOT changed:
StrEnum/IntEnum/ReprEnumsubclasses (HVACMode,HTTPStatus,Platform,EntityCategory, ...). Their__eq__delegates to
str/intequality, and callers routinely pass theunderlying primitive (which is the whole reason those base classes
exist). Replacing
==withisthere would silently break behavior.Flag/IntFlag— bitwise==is idiomatic.Type of change
Additional information
==/!=between same-enum operands #171551 (plugin), Useis/is notfor same-enum identity comparisons (tests) #171689 (tests-side codemod)The codemod is independent of #171551 and of the tests-side codemod.
All three can land in any order; CI on the plugin will be fully clean
only once both codemod halves land.
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: