Skip to content

Use is/is not for same-enum identity comparisons (source)#171591

Merged
joostlek merged 4 commits into
home-assistant:devfrom
justanotherariel:automation-enum-is-codemod
May 21, 2026
Merged

Use is/is not for same-enum identity comparisons (source)#171591
joostlek merged 4 commits into
home-assistant:devfrom
justanotherariel:automation-enum-is-codemod

Conversation

@justanotherariel
Copy link
Copy Markdown
Member

@justanotherariel justanotherariel commented May 20, 2026

Proposed change

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
#171551.

This PR covers homeassistant/ source files only (156 files,
289 sites). The corresponding tests-side codemod is in #171689.

# Before:
if self.state == ConfigEntryState.LOADED:  # both sides are ConfigEntryState
# After:
if self.state is ConfigEntryState.LOADED:

Scope is intentionally narrow:

  • Plain enum.Enum subclasses — 100% safe, because Enum.__eq__
    is identity-based: == and is give the same result.
  • homeassistant.data_entry_flow.FlowResultType — the only
    StrEnum on a curated allowlist, because HA's framework controls
    every value-assigning callsite (async_show_form, async_create_entry,
    etc. all set it to the enum instance).

What is NOT changed:

  • Other StrEnum/IntEnum/ReprEnum subclasses (HVACMode,
    HTTPStatus, Platform, EntityCategory, ...). Their __eq__
    delegates to str/int equality, and callers routinely pass the
    underlying primitive (which is the whole reason those base classes
    exist). Replacing == with is there would silently break behavior.
  • Flag/IntFlag — bitwise == is idiomatic.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

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

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings May 20, 2026 14:48
@justanotherariel justanotherariel requested a review from a team as a code owner May 20, 2026 14:48
Copy link
Copy Markdown
Contributor

@home-assistant home-assistant Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a merge conflict.

@home-assistant
Copy link
Copy Markdown
Contributor

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@thecode
Copy link
Copy Markdown
Member

thecode commented May 20, 2026

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.

@justanotherariel
Copy link
Copy Markdown
Member Author

Yea, I think I agree 😅

thecode
thecode previously approved these changes May 20, 2026
@epenet
Copy link
Copy Markdown
Contributor

epenet commented May 21, 2026

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"

@justanotherariel
Copy link
Copy Markdown
Member Author

justanotherariel commented May 21, 2026

it suggests a definite regression is going on

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!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 251 out of 251 changed files in this pull request and generated 1 comment.

Comment thread homeassistant/components/octoprint/__init__.py
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.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 156 out of 156 changed files in this pull request and generated 1 comment.

Comment thread homeassistant/data_entry_flow.py
…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.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 156 out of 156 changed files in this pull request and generated no new comments.

Comment thread homeassistant/components/arcam_fmj/media_player.py Outdated
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.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants