Skip to content

Use is/is not for same-enum identity comparisons (tests)#171689

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

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

Conversation

@justanotherariel
Copy link
Copy Markdown
Member

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 tests/ files only (95 files). The corresponding
source-side codemod is in #171591.

# Before:
assert result["type"] == FlowResultType.FORM   # both sides resolve to FlowResultType
# After:
assert result["type"] is FlowResultType.FORM

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. Reviewers have been requesting
    assert result["type"] is FlowResultType.X in PR reviews
    consistently for 2 years (~260 review comments across the corpus).

What is NOT changed:

  • Other StrEnum/IntEnum/ReprEnum subclasses (HVACMode,
    HTTPStatus, Platform, EntityCategory, ...). Their __eq__
    delegates to str/int equality and accepts raw primitives —
    test fixtures and hass.states.async_set commonly pass the
    string. is would silently break those tests.
  • 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 source-side codemod
(#171591). 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:

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 `tests/` only (95 files, 709 sites). The companion
source-side change is in home-assistant#171591.

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).

Verified by re-running the mypy plugin against the codemodded tests/:
zero remaining violations on this side.
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

This PR primarily updates Home Assistant’s test suite to use is / is not for comparisons where both operands are enum members of the same enum type (notably FlowResultType and other Enum subclasses), matching the intent of the enum-identity comparison linting work.

Changes:

  • Replace ==/!= with is/is not for same-enum comparisons across many test assertions and control-flow checks.
  • Update a few conditional checks (e.g., progress-flow loops) to use identity comparison for enum sentinels.
  • Notable: tests/components/wyoming/test_conversation.py removes multiple test cases unrelated to enum comparison updates.

Reviewed changes

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

Show a summary per file
File Description
tests/test_data_entry_flow.py Use is for FlowResultType assertions.
tests/test_core.py Use is for core-state and HassJobType enum assertions.
tests/test_config_entries.py Use is for flow result and config entry state assertions.
tests/syrupy.py Use is not for ItemStatus enum check when merging reports.
tests/helpers/test_schema_config_entry_flow.py Use is for FlowResultType assertions.
tests/helpers/test_intent.py Use is for intent enum result assertions (MatchFailedReason, response type).
tests/helpers/test_entity.py Use is for EntityPlatformState enum assertions.
tests/helpers/test_config_entry_oauth2_flow.py Use is for FlowResultType assertions.
tests/helpers/test_config_entry_flow.py Use is for FlowResultType assertions.
tests/components/zha/test_helpers.py Use is for ZHA enum assertions after type validation.
tests/components/zha/test_config_flow.py Use is not/is for progress loop FlowResultType checks.
tests/components/yale_smart_alarm/test_config_flow.py Use is for ConfigEntryState assertion.
tests/components/wyoming/test_satellite.py Use is for intent response type assertions.
tests/components/wyoming/test_conversation.py Switch enum comparisons to is; also removes multiple unrelated tests.
tests/components/wled/test_init.py Use is for ConfigEntryState assertions.
tests/components/weather/test_intent.py Use is for intent enum assertions.
tests/components/vodafone_station/test_init.py Use is for ConfigEntryState assertion.
tests/components/vera/common.py Use is for local ConfigSource enum checks.
tests/components/valve/test_intent.py Use is for intent response type assertions.
tests/components/vacuum/test_intent.py Use is for intent response/match failure enum assertions.
tests/components/uhoo/test_config_flow.py Use is for FlowResultType assertion.
tests/components/tplink/test_config_flow.py Use is/is not for parametrized FlowResultType comparisons.
tests/components/tplink_omada/test_init.py Use is for config entry state assertion.
tests/components/todo/test_intent.py Use is for intent response/match failure enum assertions.
tests/components/template/conftest.py Use is for ConfigurationStyle enum checks.
tests/components/telegram_bot/test_telegram_bot.py Use is for ConfigEntryState assertion.
tests/components/tami4/test_init.py Use is for config entry state assertion.
tests/components/switchbot_cloud/test_init.py Use is for config entry state assertion.
tests/components/stt/test_init.py Use is for Audio* enum assertions after isinstance checks.
tests/components/snooz/init.py Use is not for SnoozConnectionStatus enum check.
tests/components/sma/test_init.py Use is for config entry state assertion.
tests/components/shopping_list/test_intent.py Use is for intent response type assertions.
tests/components/shopping_list/test_init.py Use is for intent response type assertion.
tests/components/sftp_storage/test_backup.py Use is for ConfigEntryState in boolean expression.
tests/components/satel_integra/test_init.py Use is for config entry state assertion.
tests/components/samsungtv/test_init.py Use is for ConfigEntryState assertion.
tests/components/roborock/conftest.py Use is for RoborockCategory enum check in fixture setup.
tests/components/reolink/test_init.py Use is for config entry state assertion.
tests/components/recorder/common.py Use is for EventOrigin enum assertion.
tests/components/radio_browser/test_media_source.py Use is for ConfigEntryState assertions.
tests/components/radio_browser/conftest.py Use is for ConfigEntryState assertion.
tests/components/proxmoxve/test_init.py Use is for ConfigEntryState assertions.
tests/components/portainer/test_init.py Use is for config entry state assertions.
tests/components/paperless_ngx/test_init.py Use is for config entry state assertion.
tests/components/overseerr/test_init.py Use is for config entry state assertion.
tests/components/ourgroceries/test_init.py Use is for config entry state assertion.
tests/components/otbr/test_config_flow.py Use is for KeyFormat enum comparisons in logic/expressions.
tests/components/otbr/conftest.py Use is for KeyFormat enum check in HTTPStatus selection.
tests/components/orvibo/test_config_flow.py Use is for FlowResultType assertions.
tests/components/openai_conversation/test_conversation.py Use is for intent response type assertions.
tests/components/open_router/test_conversation.py Use is for intent response type assertions.
tests/components/ollama/test_conversation.py Use is for intent response type assertions.
tests/components/nextcloud/test_init.py Use is for config entry state assertion.
tests/components/media_player/test_intent.py Use is for intent response type assertions.
tests/components/lg_netcast/test_config_flow.py Use is for FlowResultType assertions.
tests/components/lcn/test_config_flow.py Use is for FlowResultType assertions.
tests/components/lawn_mower/test_intent.py Use is for intent response type assertions.
tests/components/intent/test_timers.py Use is for intent response type assertions.
tests/components/intent/test_temperature.py Use is for intent response/match failure enum assertions.
tests/components/intent/test_init.py Use is for intent response type assertions.
tests/components/influxdb/test_init.py Use is for ConfigEntryState assertions.
tests/components/imap/test_config_flow.py Use is for parametrized FlowResultType assertion.
tests/components/humidifier/test_intent.py Use is for intent response/match failure enum assertions.
tests/components/html5/test_config_flow.py Use is for FlowResultType assertion.
tests/components/homeassistant_sky_connect/test_util.py Use is for HardwareVariant enum assertions.
tests/components/homeassistant_sky_connect/test_const.py Use is for HardwareVariant enum assertion.
tests/components/homeassistant_hardware/test_config_flow.py Use is not/is for progress loop FlowResultType checks.
tests/components/home_connect/test_init.py Use is for config entry state assertion.
tests/components/google_generative_ai_conversation/test_conversation.py Use is for intent response type assertions.
tests/components/go2rtc/test_init.py Use is for config entry state assertions.
tests/components/firefly_iii/test_init.py Use is for config entry state assertion.
tests/components/fan/test_intent.py Use is for intent response type assertion.
tests/components/cover/test_intent.py Use is for intent response type assertions.
tests/components/cookidoo/test_init.py Use is for config entry state assertion.
tests/components/conversation/test_default_agent_intents.py Use is for intent response type assertions.
tests/components/config/test_config_entries.py Use is for FlowResultType assertions in multi-flow tests.
tests/components/comelit/test_init.py Use is for ConfigEntryState assertion.
tests/components/climate/test_intent.py Use is for intent response/match failure enum assertions.
tests/components/casper_glow/test_init.py Use is for ConfigEntryState assertion.
tests/components/bring/test_init.py Use is for config entry state assertion.
tests/components/bayesian/test_config_flow.py Use is for flow result type assertions.
tests/components/azure_data_explorer/test_config_flow.py Use is for FlowResultType assertions.
tests/components/axis/test_hub.py Use is for ConfigEntryState assertions.
tests/components/anthropic/test_coordinator.py Use is for intent response type assertions.
tests/components/anthropic/test_conversation.py Use is for intent response type assertions.
tests/components/alexa_devices/test_init.py Use is for ConfigEntryState assertion.
tests/components/airos/test_init.py Use is for config entry state assertion.
tests/components/airos/test_config_flow.py Use is for flow result type assertions.
tests/auth/test_init.py Use is for FlowResultType assertions in login flows.
tests/auth/providers/test_homeassistant.py Use is for FlowResultType assertions.
tests/auth/providers/test_command_line.py Use is for FlowResultType assertions.
tests/auth/mfa_modules/test_totp.py Use is for FlowResultType assertions.
tests/auth/mfa_modules/test_notify.py Use is for FlowResultType assertions.
tests/auth/mfa_modules/test_insecure_example.py Use is for FlowResultType assertions.
Comments suppressed due to low confidence (1)

tests/components/wyoming/test_conversation.py:20

  • Restore the removed Wyoming conversation tests (or move them to a separate PR) so this change set stays a pure enum-identity codemod as described.

justanotherariel added a commit to justanotherariel/hass_core that referenced this pull request May 21, 2026
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.
@justanotherariel justanotherariel marked this pull request as draft May 21, 2026 09:40
The earlier merge of dev into this branch incorrectly discarded four test functions added on dev (test_multiple_intents, test_multiple_intents_handle_error, test_intent_supports_home_control, test_handle_supports_home_control). Restored from dev with only the targeted enum-identity swap reapplied.
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 95 out of 95 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

tests/components/template/conftest.py:171

  • Replace the remaining == ConfigurationStyle.TRIGGER comparison with is to match the enum-identity comparison change made in this hunk (and avoid leaving mixed identity/equality checks for the same enum type).
    tests/components/template/conftest.py:240
  • Replace the remaining == ConfigurationStyle.TRIGGER comparison with is to keep enum comparisons consistent within this function after updating the MODERN branch to use identity.

Comment thread tests/components/template/conftest.py
Comment thread tests/components/wyoming/test_conversation.py Outdated
@justanotherariel justanotherariel marked this pull request as ready for review May 21, 2026 10:51
Re-running the plugin (now handling LiteralType and UnionType, per home-assistant#171551) flagged 22 additional same-enum compare sites in tests/ — 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.
@justanotherariel justanotherariel requested review from a team as code owners May 21, 2026 17:04
IntentResponseErrorCode is a StrEnum and is not in _FRAMEWORK_GUARANTEED_ENUMS, so the narrowed plugin does not flag it. Three swaps slipped through from an earlier broad-plugin pass and were never reverted. Restoring them to `==` so the PR strictly matches the plugin's narrowed scope (plain Enum + FlowResultType only).
Copilot AI review requested due to automatic review settings May 21, 2026 18:01
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 98 out of 98 changed files in this pull request and generated no new comments.

@justanotherariel justanotherariel merged commit 5432d29 into home-assistant:dev May 22, 2026
48 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 23, 2026
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.

4 participants