Use is/is not for same-enum identity comparisons (tests)#171689
Merged
justanotherariel merged 4 commits intoMay 22, 2026
Merged
Conversation
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.
Contributor
There was a problem hiding this comment.
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
==/!=withis/is notfor 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.pyremoves 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.
21 tasks
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.
Contributor
There was a problem hiding this comment.
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.TRIGGERcomparison withisto 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.TRIGGERcomparison withisto keep enum comparisons consistent within this function after updating theMODERNbranch to use identity.
21 tasks
joostlek
approved these changes
May 21, 2026
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.
joostlek
approved these changes
May 21, 2026
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
tests/files only (95 files). The correspondingsource-side codemod is in #171591.
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. Reviewers have been requesting
assert result["type"] is FlowResultType.Xin PR reviewsconsistently for 2 years (~260 review comments across the corpus).
What is NOT changed:
StrEnum/IntEnum/ReprEnumsubclasses (HVACMode,HTTPStatus,Platform,EntityCategory, ...). Their__eq__delegates to
str/intequality and accepts raw primitives —test fixtures and
hass.states.async_setcommonly pass thestring.
iswould silently break those tests.Flag/IntFlag— bitwise==is idiomatic.Type of change
Additional information
==/!=between same-enum operands #171551 (plugin), Useis/is notfor same-enum identity comparisons (source) #171591 (source-side codemod)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
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: