Helpers type hint additions and improvements (#27986)

* Helpers type hint additions and improvements

* Fix async setup dump callback signature
This commit is contained in:
Ville Skyttä 2019-10-21 17:54:59 +03:00 committed by GitHub
parent ba10d5d604
commit 70ddab2f3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 41 deletions

View file

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

View file

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

View file

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