diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index b7707b844d4..e819da9873a 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -1,13 +1,13 @@ """Helpers for listening to events.""" from datetime import datetime, timedelta import functools as ft -from typing import Callable +from typing import Any, Callable, Iterable, Optional, Union import attr from homeassistant.loader import bind_hass from homeassistant.helpers.sun import get_astral_event_next -from homeassistant.core import HomeAssistant, callback, CALLBACK_TYPE +from homeassistant.core import HomeAssistant, callback, CALLBACK_TYPE, Event from homeassistant.const import ( ATTR_NOW, EVENT_STATE_CHANGED, @@ -240,7 +240,9 @@ track_point_in_utc_time = threaded_listener_factory(async_track_point_in_utc_tim @callback @bind_hass -def async_call_later(hass, delay, action): +def async_call_later( + hass: HomeAssistant, delay: float, action: Callable[..., None] +) -> CALLBACK_TYPE: """Add a listener that is called in .""" return async_track_point_in_utc_time( hass, action, dt_util.utcnow() + timedelta(seconds=delay) @@ -252,7 +254,9 @@ call_later = threaded_listener_factory(async_call_later) @callback @bind_hass -def async_track_time_interval(hass, action, interval): +def async_track_time_interval( + hass: HomeAssistant, action: Callable[..., None], interval: timedelta +) -> CALLBACK_TYPE: """Add a listener that fires repetitively at every timedelta interval.""" remove = None @@ -284,14 +288,14 @@ class SunListener: """Helper class to help listen to sun events.""" hass = attr.ib(type=HomeAssistant) - action = attr.ib(type=Callable) - event = attr.ib(type=str) - offset = attr.ib(type=timedelta) - _unsub_sun: CALLBACK_TYPE = attr.ib(default=None) - _unsub_config: CALLBACK_TYPE = attr.ib(default=None) + action: Callable[..., None] = attr.ib() + event: str = attr.ib() + offset: Optional[timedelta] = attr.ib() + _unsub_sun: Optional[CALLBACK_TYPE] = attr.ib(default=None) + _unsub_config: Optional[CALLBACK_TYPE] = attr.ib(default=None) @callback - def async_attach(self): + def async_attach(self) -> None: """Attach a sun listener.""" assert self._unsub_config is None @@ -302,7 +306,7 @@ class SunListener: self._listen_next_sun_event() @callback - def async_detach(self): + def async_detach(self) -> None: """Detach the sun listener.""" assert self._unsub_sun is not None assert self._unsub_config is not None @@ -313,7 +317,7 @@ class SunListener: self._unsub_config = None @callback - def _listen_next_sun_event(self): + def _listen_next_sun_event(self) -> None: """Set up the sun event listener.""" assert self._unsub_sun is None @@ -324,14 +328,14 @@ class SunListener: ) @callback - def _handle_sun_event(self, _now): + def _handle_sun_event(self, _now: Any) -> None: """Handle solar event.""" self._unsub_sun = None self._listen_next_sun_event() self.hass.async_run_job(self.action) @callback - def _handle_config_event(self, _event): + def _handle_config_event(self, _event: Any) -> None: """Handle core config update.""" assert self._unsub_sun is not None self._unsub_sun() @@ -341,7 +345,9 @@ class SunListener: @callback @bind_hass -def async_track_sunrise(hass, action, offset=None): +def async_track_sunrise( + hass: HomeAssistant, action: Callable[..., None], offset: Optional[timedelta] = None +) -> CALLBACK_TYPE: """Add a listener that will fire a specified offset from sunrise daily.""" listener = SunListener(hass, action, SUN_EVENT_SUNRISE, offset) listener.async_attach() @@ -353,7 +359,9 @@ track_sunrise = threaded_listener_factory(async_track_sunrise) @callback @bind_hass -def async_track_sunset(hass, action, offset=None): +def async_track_sunset( + hass: HomeAssistant, action: Callable[..., None], offset: Optional[timedelta] = None +) -> CALLBACK_TYPE: """Add a listener that will fire a specified offset from sunset daily.""" listener = SunListener(hass, action, SUN_EVENT_SUNSET, offset) listener.async_attach() @@ -366,8 +374,13 @@ track_sunset = threaded_listener_factory(async_track_sunset) @callback @bind_hass def async_track_utc_time_change( - hass, action, hour=None, minute=None, second=None, local=False -): + hass: HomeAssistant, + action: Callable[..., None], + hour: Optional[Any] = None, + minute: Optional[Any] = None, + second: Optional[Any] = None, + local: bool = False, +) -> CALLBACK_TYPE: """Add a listener that will fire if time matches a pattern.""" # We do not have to wrap the function with time pattern matching logic # if no pattern given @@ -386,7 +399,7 @@ def async_track_utc_time_change( next_time = None - def calculate_next(now): + def calculate_next(now: datetime) -> None: """Calculate and set the next time the trigger should fire.""" nonlocal next_time @@ -397,10 +410,10 @@ def async_track_utc_time_change( # Make sure rolling back the clock doesn't prevent the timer from # triggering. - last_now = None + last_now: Optional[datetime] = None @callback - def pattern_time_change_listener(event): + def pattern_time_change_listener(event: Event) -> None: """Listen for matching time_changed events.""" nonlocal next_time, last_now @@ -427,7 +440,13 @@ track_utc_time_change = threaded_listener_factory(async_track_utc_time_change) @callback @bind_hass -def async_track_time_change(hass, action, hour=None, minute=None, second=None): +def async_track_time_change( + hass: HomeAssistant, + action: Callable[..., None], + hour: Optional[Any] = None, + minute: Optional[Any] = None, + second: Optional[Any] = None, +) -> CALLBACK_TYPE: """Add a listener that will fire if UTC time matches a pattern.""" return async_track_utc_time_change(hass, action, hour, minute, second, local=True) @@ -435,7 +454,9 @@ def async_track_time_change(hass, action, hour=None, minute=None, second=None): track_time_change = threaded_listener_factory(async_track_time_change) -def _process_state_match(parameter): +def _process_state_match( + parameter: Union[None, str, Iterable[str]] +) -> Callable[[str], bool]: """Convert parameter to function that matches input against parameter.""" if parameter is None or parameter == MATCH_ALL: return lambda _: True @@ -443,5 +464,5 @@ def _process_state_match(parameter): if isinstance(parameter, str) or not hasattr(parameter, "__iter__"): return lambda state: state == parameter - parameter = tuple(parameter) - return lambda state: state in parameter + parameter_tuple = tuple(parameter) + return lambda state: state in parameter_tuple diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index fdf52c99075..5d47f34b002 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -164,23 +164,20 @@ class RestoreStateData: @callback def async_setup_dump(self, *args: Any) -> None: """Set up the restore state listeners.""" + + def _async_dump_states(*_: Any) -> None: + self.hass.async_create_task(self.async_dump_states()) + # Dump the initial states now. This helps minimize the risk of having # old states loaded by overwritting the last states once home assistant # has started and the old states have been read. - self.hass.async_create_task(self.async_dump_states()) + _async_dump_states() # Dump states periodically - async_track_time_interval( - self.hass, - lambda *_: self.hass.async_create_task(self.async_dump_states()), - STATE_DUMP_INTERVAL, - ) + async_track_time_interval(self.hass, _async_dump_states, STATE_DUMP_INTERVAL) # Dump states when stopping hass - self.hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_STOP, - lambda *_: self.hass.async_create_task(self.async_dump_states()), - ) + self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_dump_states) @callback def async_restore_entity_added(self, entity_id: str) -> None: diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index 72458d24c82..bd18eebfb25 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -6,7 +6,7 @@ import os from typing import Dict, List, Optional, Callable, Union, Any, Type from homeassistant.const import EVENT_HOMEASSISTANT_STOP -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant, callback, CALLBACK_TYPE from homeassistant.loader import bind_hass from homeassistant.util import json as json_util from homeassistant.helpers.event import async_call_later @@ -72,8 +72,8 @@ class Store: self.hass = hass self._private = private self._data: Optional[Dict[str, Any]] = None - self._unsub_delay_listener = None - self._unsub_stop_listener = None + self._unsub_delay_listener: Optional[CALLBACK_TYPE] = None + self._unsub_stop_listener: Optional[CALLBACK_TYPE] = None self._write_lock = asyncio.Lock() self._load_task: Optional[asyncio.Future] = None self._encoder = encoder @@ -137,9 +137,7 @@ class Store: await self._async_handle_write_data() @callback - def async_delay_save( - self, data_func: Callable[[], Dict], delay: Optional[int] = None - ) -> None: + def async_delay_save(self, data_func: Callable[[], Dict], delay: float = 0) -> None: """Save data with an optional delay.""" self._data = {"version": self.version, "key": self.key, "data_func": data_func}