Fully type homeassistant integration (#107380)

This commit is contained in:
Marc Mueller 2024-01-08 10:07:30 +01:00 committed by GitHub
parent 5ae419367e
commit 78752264b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 65 additions and 49 deletions

View File

@ -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.*

View File

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

View File

@ -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"])

View File

@ -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],

View File

@ -135,7 +135,7 @@ class SceneConfig(NamedTuple):
id: str | None
name: str
icon: str | None
states: dict
states: dict[str, State]
@callback

View File

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

View File

@ -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(

View File

@ -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():

View File

@ -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():

View File

@ -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()

View File

@ -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,

View File

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

View File

@ -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