diff --git a/.strict-typing b/.strict-typing index 33e608d38c8..501779c4700 100644 --- a/.strict-typing +++ b/.strict-typing @@ -196,8 +196,7 @@ homeassistant.components.here_travel_time.* homeassistant.components.history.* homeassistant.components.history_stats.* homeassistant.components.holiday.* -homeassistant.components.homeassistant.exposed_entities -homeassistant.components.homeassistant.triggers.event +homeassistant.components.homeassistant.* homeassistant.components.homeassistant_alerts.* homeassistant.components.homeassistant_green.* homeassistant.components.homeassistant_hardware.* diff --git a/homeassistant/components/homeassistant/__init__.py b/homeassistant/components/homeassistant/__init__.py index c978a7d4320..0a5649ba26b 100644 --- a/homeassistant/components/homeassistant/__init__.py +++ b/homeassistant/components/homeassistant/__init__.py @@ -94,8 +94,8 @@ async def async_setup(hass: ha.HomeAssistant, config: ConfigType) -> bool: # no sorted(all_referenced), lambda item: ha.split_entity_id(item)[0] ) - tasks = [] - unsupported_entities = set() + tasks: list[Coroutine[Any, Any, ha.ServiceResponse]] = [] + unsupported_entities: set[str] = set() for domain, ent_ids in by_domain: # This leads to endless loop. @@ -298,7 +298,7 @@ async def async_setup(hass: ha.HomeAssistant, config: ConfigType) -> bool: # no async def async_handle_reload_config_entry(call: ha.ServiceCall) -> None: """Service handler for reloading a config entry.""" - reload_entries = set() + reload_entries: set[str] = set() if ATTR_ENTRY_ID in call.data: reload_entries.add(call.data[ATTR_ENTRY_ID]) reload_entries.update(await async_extract_config_entry_ids(hass, call)) @@ -376,7 +376,7 @@ async def async_setup(hass: ha.HomeAssistant, config: ConfigType) -> bool: # no return True -async def _async_stop(hass: ha.HomeAssistant, restart: bool): +async def _async_stop(hass: ha.HomeAssistant, restart: bool) -> None: """Stop home assistant.""" exit_code = RESTART_EXIT_CODE if restart else 0 # Track trask in hass.data. No need to cleanup, we're stopping. diff --git a/homeassistant/components/homeassistant/exposed_entities.py b/homeassistant/components/homeassistant/exposed_entities.py index 926ab5025f6..b53f28f4cee 100644 --- a/homeassistant/components/homeassistant/exposed_entities.py +++ b/homeassistant/components/homeassistant/exposed_entities.py @@ -475,7 +475,7 @@ def ws_expose_new_entities_get( def ws_expose_new_entities_set( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any] ) -> None: - """Expose new entities to an assistatant.""" + """Expose new entities to an assistant.""" exposed_entities: ExposedEntities = hass.data[DATA_EXPOSED_ENTITIES] exposed_entities.async_set_expose_new_entities(msg["assistant"], msg["expose_new"]) connection.send_result(msg["id"]) diff --git a/homeassistant/components/homeassistant/logbook.py b/homeassistant/components/homeassistant/logbook.py index 229fb24cb27..60e8794799d 100644 --- a/homeassistant/components/homeassistant/logbook.py +++ b/homeassistant/components/homeassistant/logbook.py @@ -28,7 +28,7 @@ def async_describe_events( @callback def async_describe_hass_event(event: Event) -> dict[str, str]: - """Describe homeassisant logbook event.""" + """Describe homeassistant logbook event.""" return { LOGBOOK_ENTRY_NAME: "Home Assistant", LOGBOOK_ENTRY_MESSAGE: EVENT_TO_NAME[event.event_type], diff --git a/homeassistant/components/homeassistant/scene.py b/homeassistant/components/homeassistant/scene.py index 9abfefc996f..f8fd901a18a 100644 --- a/homeassistant/components/homeassistant/scene.py +++ b/homeassistant/components/homeassistant/scene.py @@ -135,7 +135,7 @@ class SceneConfig(NamedTuple): id: str | None name: str icon: str | None - states: dict + states: dict[str, State] @callback diff --git a/homeassistant/components/homeassistant/system_health.py b/homeassistant/components/homeassistant/system_health.py index 4006228de25..488328b6e4e 100644 --- a/homeassistant/components/homeassistant/system_health.py +++ b/homeassistant/components/homeassistant/system_health.py @@ -1,4 +1,8 @@ """Provide info to system health.""" +from __future__ import annotations + +from typing import Any + from homeassistant.components import system_health from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import system_info @@ -12,7 +16,7 @@ def async_register( register.async_register_info(system_health_info) -async def system_health_info(hass): +async def system_health_info(hass: HomeAssistant) -> dict[str, Any]: """Get info for the info page.""" info = await system_info.async_get_system_info(hass) diff --git a/homeassistant/components/homeassistant/trigger.py b/homeassistant/components/homeassistant/trigger.py index 3160af58079..401da9d01e7 100644 --- a/homeassistant/components/homeassistant/trigger.py +++ b/homeassistant/components/homeassistant/trigger.py @@ -23,7 +23,7 @@ async def async_validate_trigger_config( if hasattr(platform, "async_validate_trigger_config"): return await platform.async_validate_trigger_config(hass, config) - return platform.TRIGGER_SCHEMA(config) + return platform.TRIGGER_SCHEMA(config) # type: ignore[no-any-return] async def async_attach_trigger( diff --git a/homeassistant/components/homeassistant/triggers/numeric_state.py b/homeassistant/components/homeassistant/triggers/numeric_state.py index d822cd523fc..dad57bbcdb3 100644 --- a/homeassistant/components/homeassistant/triggers/numeric_state.py +++ b/homeassistant/components/homeassistant/triggers/numeric_state.py @@ -1,5 +1,10 @@ """Offer numeric state listening automation rules.""" +from __future__ import annotations + +from collections.abc import Callable +from datetime import timedelta import logging +from typing import Any, TypeVar import voluptuous as vol @@ -13,7 +18,7 @@ from homeassistant.const import ( CONF_PLATFORM, CONF_VALUE_TEMPLATE, ) -from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback +from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, State, callback from homeassistant.helpers import ( condition, config_validation as cv, @@ -21,14 +26,17 @@ from homeassistant.helpers import ( template, ) from homeassistant.helpers.event import ( + EventStateChangedData, async_track_same_state, async_track_state_change_event, ) from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo -from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.typing import ConfigType, EventType + +_T = TypeVar("_T", bound=dict[str, Any]) -def validate_above_below(value): +def validate_above_below(value: _T) -> _T: """Validate that above and below can co-exist.""" above = value.get(CONF_ABOVE) below = value.get(CONF_BELOW) @@ -96,9 +104,9 @@ async def async_attach_trigger( time_delta = config.get(CONF_FOR) template.attach(hass, time_delta) value_template = config.get(CONF_VALUE_TEMPLATE) - unsub_track_same = {} - armed_entities = set() - period: dict = {} + unsub_track_same: dict[str, Callable[[], None]] = {} + armed_entities: set[str] = set() + period: dict[str, timedelta] = {} attribute = config.get(CONF_ATTRIBUTE) job = HassJob(action, f"numeric state trigger {trigger_info}") @@ -108,7 +116,7 @@ async def async_attach_trigger( if value_template is not None: value_template.hass = hass - def variables(entity_id): + def variables(entity_id: str) -> dict[str, Any]: """Return a dict with trigger variables.""" trigger_info = { "trigger": { @@ -122,7 +130,9 @@ async def async_attach_trigger( return {**_variables, **trigger_info} @callback - def check_numeric_state(entity_id, from_s, to_s): + def check_numeric_state( + entity_id: str, from_s: State | None, to_s: str | State | None + ) -> bool: """Return whether the criteria are met, raise ConditionError if unknown.""" return condition.async_numeric_state( hass, to_s, below, above, value_template, variables(entity_id), attribute @@ -141,14 +151,17 @@ async def async_attach_trigger( ) @callback - def state_automation_listener(event): + def state_automation_listener(event: EventType[EventStateChangedData]) -> None: """Listen for state changes and calls action.""" - entity_id = event.data.get("entity_id") - from_s = event.data.get("old_state") - to_s = event.data.get("new_state") + entity_id = event.data["entity_id"] + from_s = event.data["old_state"] + to_s = event.data["new_state"] + + if to_s is None: + return @callback - def call_action(): + def call_action() -> None: """Call action with right context.""" hass.async_run_hass_job( job, @@ -169,7 +182,9 @@ async def async_attach_trigger( ) @callback - def check_numeric_state_no_raise(entity_id, from_s, to_s): + def check_numeric_state_no_raise( + entity_id: str, from_s: State | None, to_s: State | None + ) -> bool: """Return True if the criteria are now met, False otherwise.""" try: return check_numeric_state(entity_id, from_s, to_s) @@ -216,7 +231,7 @@ async def async_attach_trigger( unsub = async_track_state_change_event(hass, entity_ids, state_automation_listener) @callback - def async_remove(): + def async_remove() -> None: """Remove state listeners async.""" unsub() for async_remove in unsub_track_same.values(): diff --git a/homeassistant/components/homeassistant/triggers/state.py b/homeassistant/components/homeassistant/triggers/state.py index 2cac07e7cd9..061c2468c30 100644 --- a/homeassistant/components/homeassistant/triggers/state.py +++ b/homeassistant/components/homeassistant/triggers/state.py @@ -1,6 +1,7 @@ """Offer state listening automation rules.""" from __future__ import annotations +from collections.abc import Callable from datetime import timedelta import logging @@ -114,7 +115,7 @@ async def async_attach_trigger( match_all = all( item not in config for item in (CONF_FROM, CONF_NOT_FROM, CONF_NOT_TO, CONF_TO) ) - unsub_track_same = {} + unsub_track_same: dict[str, Callable[[], None]] = {} period: dict[str, timedelta] = {} attribute = config.get(CONF_ATTRIBUTE) job = HassJob(action, f"state trigger {trigger_info}") @@ -158,7 +159,7 @@ async def async_attach_trigger( return @callback - def call_action(): + def call_action() -> None: """Call action with right context.""" hass.async_run_hass_job( job, @@ -201,7 +202,7 @@ async def async_attach_trigger( ) return - def _check_same_state(_, _2, new_st: State | None) -> bool: + def _check_same_state(_: str, _2: State | None, new_st: State | None) -> bool: if new_st is None: return False @@ -227,7 +228,7 @@ async def async_attach_trigger( unsub = async_track_state_change_event(hass, entity_ids, state_automation_listener) @callback - def async_remove(): + def async_remove() -> None: """Remove state listeners async.""" unsub() for async_remove in unsub_track_same.values(): diff --git a/homeassistant/components/homeassistant/triggers/time.py b/homeassistant/components/homeassistant/triggers/time.py index 5b3cd8590a7..3cb8809a7ad 100644 --- a/homeassistant/components/homeassistant/triggers/time.py +++ b/homeassistant/components/homeassistant/triggers/time.py @@ -53,7 +53,9 @@ async def async_attach_trigger( job = HassJob(action, f"time trigger {trigger_info}") @callback - def time_automation_listener(description, now, *, entity_id=None): + def time_automation_listener( + description: str, now: datetime, *, entity_id: str | None = None + ) -> None: """Listen for time changes and calls action.""" hass.async_run_hass_job( job, @@ -183,7 +185,7 @@ async def async_attach_trigger( ) @callback - def remove_track_time_changes(): + def remove_track_time_changes() -> None: """Remove tracked time changes.""" for remove in entities.values(): remove() diff --git a/homeassistant/components/homeassistant/triggers/time_pattern.py b/homeassistant/components/homeassistant/triggers/time_pattern.py index 63f9b18cf9b..d8ac55eb04f 100644 --- a/homeassistant/components/homeassistant/triggers/time_pattern.py +++ b/homeassistant/components/homeassistant/triggers/time_pattern.py @@ -1,4 +1,9 @@ """Offer time listening automation rules.""" +from __future__ import annotations + +from datetime import datetime +from typing import Any + import voluptuous as vol from homeassistant.const import CONF_PLATFORM @@ -19,15 +24,15 @@ class TimePattern: :raises Invalid: If the value has a wrong format or is outside the range. """ - def __init__(self, maximum): + def __init__(self, maximum: int) -> None: """Initialize time pattern.""" self.maximum = maximum - def __call__(self, value): + def __call__(self, value: Any) -> str | int: """Validate input.""" try: if value == "*": - return value + return value # type: ignore[no-any-return] if isinstance(value, str) and value.startswith("/"): number = int(value[1:]) @@ -39,7 +44,7 @@ class TimePattern: except ValueError as err: raise vol.Invalid("invalid time_pattern value") from err - return value + return value # type: ignore[no-any-return] TRIGGER_SCHEMA = vol.All( @@ -75,7 +80,7 @@ async def async_attach_trigger( seconds = 0 @callback - def time_automation_listener(now): + def time_automation_listener(now: datetime) -> None: """Listen for time changes and calls action.""" hass.async_run_hass_job( job, diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 656b2c21129..dee896ccba2 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -520,7 +520,7 @@ def async_extract_referenced_entity_ids( @bind_hass async def async_extract_config_entry_ids( hass: HomeAssistant, service_call: ServiceCall, expand_group: bool = True -) -> set: +) -> set[str]: """Extract referenced config entry ids from a service call.""" referenced = async_extract_referenced_entity_ids(hass, service_call, expand_group) ent_reg = entity_registry.async_get(hass) diff --git a/mypy.ini b/mypy.ini index e68048c8001..3315704745f 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1721,17 +1721,7 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true -[mypy-homeassistant.components.homeassistant.exposed_entities] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_subclassing_any = true -disallow_untyped_calls = true -disallow_untyped_decorators = true -disallow_untyped_defs = true -warn_return_any = true -warn_unreachable = true - -[mypy-homeassistant.components.homeassistant.triggers.event] +[mypy-homeassistant.components.homeassistant.*] check_untyped_defs = true disallow_incomplete_defs = true disallow_subclassing_any = true