From 648ef948888fd9f5afbd15af89fda3f528cb016a Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:43:27 +0200 Subject: [PATCH] Improve type hints in core helper tests (#120096) --- tests/helpers/test_collection.py | 10 ++--- tests/helpers/test_config_validation.py | 6 +-- tests/helpers/test_discovery_flow.py | 15 +++++--- tests/helpers/test_entity.py | 28 +++++++------- tests/helpers/test_json.py | 6 +-- tests/helpers/test_restore_state.py | 4 +- tests/helpers/test_significant_change.py | 14 +++++-- tests/helpers/test_storage.py | 47 +++++++++++++----------- 8 files changed, 71 insertions(+), 59 deletions(-) diff --git a/tests/helpers/test_collection.py b/tests/helpers/test_collection.py index f4d5b06dae0..f0287218d7f 100644 --- a/tests/helpers/test_collection.py +++ b/tests/helpers/test_collection.py @@ -37,7 +37,7 @@ def track_changes(coll: collection.ObservableCollection): class MockEntity(collection.CollectionEntity): """Entity that is config based.""" - def __init__(self, config): + def __init__(self, config: ConfigType) -> None: """Initialize entity.""" self._config = config @@ -52,21 +52,21 @@ class MockEntity(collection.CollectionEntity): raise NotImplementedError @property - def unique_id(self): + def unique_id(self) -> str: """Return unique ID of entity.""" return self._config["id"] @property - def name(self): + def name(self) -> str: """Return name of entity.""" return self._config["name"] @property - def state(self): + def state(self) -> str: """Return state of entity.""" return self._config["state"] - async def async_update_config(self, config): + async def async_update_config(self, config: ConfigType) -> None: """Update entity config.""" self._config = config self.async_write_ha_state() diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 163a33db988..6df29eefaff 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -1240,7 +1240,7 @@ def test_enum() -> None: schema("value3") -def test_socket_timeout(): +def test_socket_timeout() -> None: """Test socket timeout validator.""" schema = vol.Schema(cv.socket_timeout) @@ -1679,7 +1679,7 @@ def test_color_hex() -> None: cv.color_hex(123456) -def test_determine_script_action_ambiguous(): +def test_determine_script_action_ambiguous() -> None: """Test determine script action with ambiguous actions.""" assert ( cv.determine_script_action( @@ -1696,6 +1696,6 @@ def test_determine_script_action_ambiguous(): ) -def test_determine_script_action_non_ambiguous(): +def test_determine_script_action_non_ambiguous() -> None: """Test determine script action with a non ambiguous action.""" assert cv.determine_script_action({"delay": "00:00:05"}) == "delay" diff --git a/tests/helpers/test_discovery_flow.py b/tests/helpers/test_discovery_flow.py index 7710eb2c7c7..9c2249ac17f 100644 --- a/tests/helpers/test_discovery_flow.py +++ b/tests/helpers/test_discovery_flow.py @@ -3,6 +3,7 @@ from unittest.mock import AsyncMock, call, patch import pytest +from typing_extensions import Generator from homeassistant import config_entries from homeassistant.core import EVENT_HOMEASSISTANT_STARTED, CoreState, HomeAssistant @@ -10,7 +11,7 @@ from homeassistant.helpers import discovery_flow @pytest.fixture -def mock_flow_init(hass): +def mock_flow_init(hass: HomeAssistant) -> Generator[AsyncMock]: """Mock hass.config_entries.flow.async_init.""" with patch.object( hass.config_entries.flow, "async_init", return_value=AsyncMock() @@ -18,7 +19,9 @@ def mock_flow_init(hass): yield mock_init -async def test_async_create_flow(hass: HomeAssistant, mock_flow_init) -> None: +async def test_async_create_flow( + hass: HomeAssistant, mock_flow_init: AsyncMock +) -> None: """Test we can create a flow.""" discovery_flow.async_create_flow( hass, @@ -36,7 +39,7 @@ async def test_async_create_flow(hass: HomeAssistant, mock_flow_init) -> None: async def test_async_create_flow_deferred_until_started( - hass: HomeAssistant, mock_flow_init + hass: HomeAssistant, mock_flow_init: AsyncMock ) -> None: """Test flows are deferred until started.""" hass.set_state(CoreState.stopped) @@ -59,7 +62,7 @@ async def test_async_create_flow_deferred_until_started( async def test_async_create_flow_checks_existing_flows_after_startup( - hass: HomeAssistant, mock_flow_init + hass: HomeAssistant, mock_flow_init: AsyncMock ) -> None: """Test existing flows prevent an identical ones from being after startup.""" hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) @@ -77,7 +80,7 @@ async def test_async_create_flow_checks_existing_flows_after_startup( async def test_async_create_flow_checks_existing_flows_before_startup( - hass: HomeAssistant, mock_flow_init + hass: HomeAssistant, mock_flow_init: AsyncMock ) -> None: """Test existing flows prevent an identical ones from being created before startup.""" hass.set_state(CoreState.stopped) @@ -100,7 +103,7 @@ async def test_async_create_flow_checks_existing_flows_before_startup( async def test_async_create_flow_does_nothing_after_stop( - hass: HomeAssistant, mock_flow_init + hass: HomeAssistant, mock_flow_init: AsyncMock ) -> None: """Test we no longer create flows when hass is stopping.""" hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index 9d2c9a66a5b..f76b8555580 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -237,12 +237,12 @@ async def test_async_async_request_call_without_lock(hass: HomeAssistant) -> Non class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id): + def __init__(self, entity_id: str) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass - async def testhelper(self, count): + async def testhelper(self, count: int) -> None: """Helper function.""" updates.append(count) @@ -274,7 +274,7 @@ async def test_async_async_request_call_with_lock(hass: HomeAssistant) -> None: class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id, lock): + def __init__(self, entity_id: str, lock: asyncio.Semaphore) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass @@ -324,13 +324,13 @@ async def test_async_parallel_updates_with_zero(hass: HomeAssistant) -> None: class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id, count): + def __init__(self, entity_id: str, count: int) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass self._count = count - async def async_update(self): + async def async_update(self) -> None: """Test update.""" updates.append(self._count) await test_lock.wait() @@ -363,7 +363,7 @@ async def test_async_parallel_updates_with_zero_on_sync_update( class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id, count): + def __init__(self, entity_id: str, count: int) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass @@ -404,14 +404,14 @@ async def test_async_parallel_updates_with_one(hass: HomeAssistant) -> None: class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id, count): + def __init__(self, entity_id: str, count: int) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass self._count = count self.parallel_updates = test_semaphore - async def async_update(self): + async def async_update(self) -> None: """Test update.""" updates.append(self._count) await test_lock.acquire() @@ -480,14 +480,14 @@ async def test_async_parallel_updates_with_two(hass: HomeAssistant) -> None: class AsyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id, count): + def __init__(self, entity_id: str, count: int) -> None: """Initialize Async test entity.""" self.entity_id = entity_id self.hass = hass self._count = count self.parallel_updates = test_semaphore - async def async_update(self): + async def async_update(self) -> None: """Test update.""" updates.append(self._count) await test_lock.acquire() @@ -550,13 +550,13 @@ async def test_async_parallel_updates_with_one_using_executor( class SyncEntity(entity.Entity): """Test entity.""" - def __init__(self, entity_id): + def __init__(self, entity_id: str) -> None: """Initialize sync test entity.""" self.entity_id = entity_id self.hass = hass self.parallel_updates = test_semaphore - def update(self): + def update(self) -> None: """Test update.""" locked.append(self.parallel_updates.locked()) @@ -629,7 +629,7 @@ async def test_async_remove_twice(hass: HomeAssistant) -> None: def __init__(self) -> None: self.remove_calls = [] - async def async_will_remove_from_hass(self): + async def async_will_remove_from_hass(self) -> None: self.remove_calls.append(None) platform = MockEntityPlatform(hass, domain="test") @@ -2376,7 +2376,7 @@ async def test_cached_entity_property_class_attribute(hass: HomeAssistant) -> No This class overrides the attribute property. """ - def __init__(self): + def __init__(self) -> None: self._attr_attribution = values[0] @cached_property diff --git a/tests/helpers/test_json.py b/tests/helpers/test_json.py index 57269963164..061faed6f93 100644 --- a/tests/helpers/test_json.py +++ b/tests/helpers/test_json.py @@ -7,7 +7,7 @@ import math import os from pathlib import Path import time -from typing import NamedTuple +from typing import Any, NamedTuple from unittest.mock import Mock, patch import pytest @@ -325,10 +325,10 @@ def test_find_unserializable_data() -> None: ) == {"$[0](Event: bad_event).data.bad_attribute": bad_data} class BadData: - def __init__(self): + def __init__(self) -> None: self.bla = bad_data - def as_dict(self): + def as_dict(self) -> dict[str, Any]: return {"bla": self.bla} assert find_paths_unserializable_data( diff --git a/tests/helpers/test_restore_state.py b/tests/helpers/test_restore_state.py index 729212f4c1d..865ee5efaf7 100644 --- a/tests/helpers/test_restore_state.py +++ b/tests/helpers/test_restore_state.py @@ -484,12 +484,12 @@ async def test_restore_entity_end_to_end( class MockRestoreEntity(RestoreEntity): """Mock restore entity.""" - def __init__(self): + def __init__(self) -> None: """Initialize the mock entity.""" self._state: str | None = None @property - def state(self): + def state(self) -> str | None: """Return the state.""" return self._state diff --git a/tests/helpers/test_significant_change.py b/tests/helpers/test_significant_change.py index e930ff30feb..f9dca5b6034 100644 --- a/tests/helpers/test_significant_change.py +++ b/tests/helpers/test_significant_change.py @@ -9,7 +9,9 @@ from homeassistant.helpers import significant_change @pytest.fixture(name="checker") -async def checker_fixture(hass): +async def checker_fixture( + hass: HomeAssistant, +) -> significant_change.SignificantlyChangedChecker: """Checker fixture.""" checker = await significant_change.create_checker(hass, "test") @@ -24,7 +26,9 @@ async def checker_fixture(hass): return checker -async def test_signicant_change(hass: HomeAssistant, checker) -> None: +async def test_signicant_change( + checker: significant_change.SignificantlyChangedChecker, +) -> None: """Test initialize helper works.""" ent_id = "test_domain.test_entity" attrs = {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY} @@ -48,7 +52,9 @@ async def test_signicant_change(hass: HomeAssistant, checker) -> None: assert checker.async_is_significant_change(State(ent_id, STATE_UNAVAILABLE, attrs)) -async def test_significant_change_extra(hass: HomeAssistant, checker) -> None: +async def test_significant_change_extra( + checker: significant_change.SignificantlyChangedChecker, +) -> None: """Test extra significant checker works.""" ent_id = "test_domain.test_entity" attrs = {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY} @@ -75,7 +81,7 @@ async def test_significant_change_extra(hass: HomeAssistant, checker) -> None: assert checker.async_is_significant_change(State(ent_id, "200", attrs), extra_arg=2) -async def test_check_valid_float(hass: HomeAssistant) -> None: +async def test_check_valid_float() -> None: """Test extra significant checker works.""" assert significant_change.check_valid_float("1") assert significant_change.check_valid_float("1.0") diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index 651c7ce5cbc..822b56604c0 100644 --- a/tests/helpers/test_storage.py +++ b/tests/helpers/test_storage.py @@ -40,13 +40,13 @@ MOCK_DATA2 = {"goodbye": "cruel world"} @pytest.fixture -def store(hass): +def store(hass: HomeAssistant) -> storage.Store: """Fixture of a store that prevents writing on Home Assistant stop.""" return storage.Store(hass, MOCK_VERSION, MOCK_KEY) @pytest.fixture -def store_v_1_1(hass): +def store_v_1_1(hass: HomeAssistant) -> storage.Store: """Fixture of a store that prevents writing on Home Assistant stop.""" return storage.Store( hass, MOCK_VERSION, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_1 @@ -54,7 +54,7 @@ def store_v_1_1(hass): @pytest.fixture -def store_v_1_2(hass): +def store_v_1_2(hass: HomeAssistant) -> storage.Store: """Fixture of a store that prevents writing on Home Assistant stop.""" return storage.Store( hass, MOCK_VERSION, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_2 @@ -62,7 +62,7 @@ def store_v_1_2(hass): @pytest.fixture -def store_v_2_1(hass): +def store_v_2_1(hass: HomeAssistant) -> storage.Store: """Fixture of a store that prevents writing on Home Assistant stop.""" return storage.Store( hass, MOCK_VERSION_2, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_1 @@ -70,12 +70,12 @@ def store_v_2_1(hass): @pytest.fixture -def read_only_store(hass): +def read_only_store(hass: HomeAssistant) -> storage.Store: """Fixture of a read only store.""" return storage.Store(hass, MOCK_VERSION, MOCK_KEY, read_only=True) -async def test_loading(hass: HomeAssistant, store) -> None: +async def test_loading(hass: HomeAssistant, store: storage.Store) -> None: """Test we can save and load data.""" await store.async_save(MOCK_DATA) data = await store.async_load() @@ -100,7 +100,7 @@ async def test_custom_encoder(hass: HomeAssistant) -> None: assert data == "9" -async def test_loading_non_existing(hass: HomeAssistant, store) -> None: +async def test_loading_non_existing(hass: HomeAssistant, store: storage.Store) -> None: """Test we can save and load data.""" with patch("homeassistant.util.json.open", side_effect=FileNotFoundError): data = await store.async_load() @@ -109,7 +109,7 @@ async def test_loading_non_existing(hass: HomeAssistant, store) -> None: async def test_loading_parallel( hass: HomeAssistant, - store, + store: storage.Store, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture, ) -> None: @@ -292,7 +292,7 @@ async def test_not_saving_while_stopping( async def test_loading_while_delay( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test we load new data even if not written yet.""" await store.async_save({"delay": "no"}) @@ -316,7 +316,7 @@ async def test_loading_while_delay( async def test_writing_while_writing_delay( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test a write while a write with delay is active.""" store.async_delay_save(lambda: {"delay": "yes"}, 1) @@ -343,7 +343,7 @@ async def test_writing_while_writing_delay( async def test_multiple_delay_save_calls( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test a write while a write with changing delays.""" store.async_delay_save(lambda: {"delay": "yes"}, 1) @@ -390,7 +390,7 @@ async def test_delay_save_zero( async def test_multiple_save_calls( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test multiple write tasks.""" @@ -410,7 +410,7 @@ async def test_multiple_save_calls( async def test_migrator_no_existing_config( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test migrator with no existing config.""" with ( @@ -424,7 +424,7 @@ async def test_migrator_no_existing_config( async def test_migrator_existing_config( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test migrating existing config.""" with patch("os.path.isfile", return_value=True), patch("os.remove") as mock_remove: @@ -443,7 +443,7 @@ async def test_migrator_existing_config( async def test_migrator_transforming_config( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test migrating config to new format.""" @@ -471,7 +471,7 @@ async def test_migrator_transforming_config( async def test_minor_version_default( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test minor version default.""" @@ -480,7 +480,7 @@ async def test_minor_version_default( async def test_minor_version( - hass: HomeAssistant, store_v_1_2, hass_storage: dict[str, Any] + hass: HomeAssistant, store_v_1_2: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test minor version.""" @@ -489,7 +489,7 @@ async def test_minor_version( async def test_migrate_major_not_implemented_raises( - hass: HomeAssistant, store, store_v_2_1 + hass: HomeAssistant, store: storage.Store, store_v_2_1: storage.Store ) -> None: """Test migrating between major versions fails if not implemented.""" @@ -499,7 +499,10 @@ async def test_migrate_major_not_implemented_raises( async def test_migrate_minor_not_implemented( - hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_1, store_v_1_2 + hass: HomeAssistant, + hass_storage: dict[str, Any], + store_v_1_1: storage.Store, + store_v_1_2: storage.Store, ) -> None: """Test migrating between minor versions does not fail if not implemented.""" @@ -525,7 +528,7 @@ async def test_migrate_minor_not_implemented( async def test_migration( - hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2 + hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2: storage.Store ) -> None: """Test migration.""" calls = 0 @@ -564,7 +567,7 @@ async def test_migration( async def test_legacy_migration( - hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2 + hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2: storage.Store ) -> None: """Test legacy migration method signature.""" calls = 0 @@ -600,7 +603,7 @@ async def test_legacy_migration( async def test_changing_delayed_written_data( - hass: HomeAssistant, store, hass_storage: dict[str, Any] + hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any] ) -> None: """Test changing data that is written with delay.""" data_to_store = {"hello": "world"}