1 """Helper to help coordinating calls."""
3 from __future__
import annotations
6 from collections.abc
import Callable
8 from typing
import Any, cast, overload
14 type _FuncType[_T] = Callable[[HomeAssistant], _T]
19 data_key: HassKey[_T],
20 ) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ...
24 def singleton[_T](data_key: str) -> Callable[[_FuncType[_T]], _FuncType[_T]]: ...
27 def singleton[_T](data_key: Any) -> Callable[[_FuncType[_T]], _FuncType[_T]]:
28 """Decorate a function that should be called once per instance.
30 Result will be cached and simultaneous calls will be handled.
33 def wrapper(func: _FuncType[_T]) -> _FuncType[_T]:
34 """Wrap a function with caching logic."""
35 if not asyncio.iscoroutinefunction(func):
37 @functools.lru_cache(maxsize=1)
39 @functools.wraps(func)
40 def wrapped(hass: HomeAssistant) -> _T:
41 if data_key
not in hass.data:
42 hass.data[data_key] = func(hass)
43 return cast(_T, hass.data[data_key])
48 @functools.wraps(func)
49 async
def async_wrapped(hass: HomeAssistant) -> Any:
50 if data_key
not in hass.data:
51 evt = hass.data[data_key] = asyncio.Event()
52 result = await func(hass)
53 hass.data[data_key] = result
55 return cast(_T, result)
57 obj_or_evt = hass.data[data_key]
59 if isinstance(obj_or_evt, asyncio.Event):
60 await obj_or_evt.wait()
61 return cast(_T, hass.data[data_key])
63 return cast(_T, obj_or_evt)