mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Introduce a singleton decorator (#34803)
This commit is contained in:
parent
76f392476b
commit
6056753a9c
@ -83,8 +83,8 @@ if TYPE_CHECKING:
|
||||
block_async_io.enable()
|
||||
fix_threading_exception_logging()
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
T = TypeVar("T")
|
||||
# pylint: disable=invalid-name
|
||||
CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable)
|
||||
CALLBACK_TYPE = Callable[[], None]
|
||||
# pylint: enable=invalid-name
|
||||
|
@ -1,8 +1,7 @@
|
||||
"""Provide a way to connect entities belonging to one device."""
|
||||
from asyncio import Event
|
||||
from collections import OrderedDict
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, cast
|
||||
from typing import Any, Dict, List, Optional
|
||||
import uuid
|
||||
|
||||
import attr
|
||||
@ -10,6 +9,7 @@ import attr
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.loader import bind_hass
|
||||
|
||||
from .singleton import singleton
|
||||
from .typing import HomeAssistantType
|
||||
|
||||
# mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs
|
||||
@ -356,27 +356,13 @@ class DeviceRegistry:
|
||||
|
||||
|
||||
@bind_hass
|
||||
@singleton(DATA_REGISTRY)
|
||||
async def async_get_registry(hass: HomeAssistantType) -> DeviceRegistry:
|
||||
"""Return device registry instance."""
|
||||
reg_or_evt = hass.data.get(DATA_REGISTRY)
|
||||
|
||||
if not reg_or_evt:
|
||||
evt = hass.data[DATA_REGISTRY] = Event()
|
||||
|
||||
"""Create entity registry."""
|
||||
reg = DeviceRegistry(hass)
|
||||
await reg.async_load()
|
||||
|
||||
hass.data[DATA_REGISTRY] = reg
|
||||
evt.set()
|
||||
return reg
|
||||
|
||||
if isinstance(reg_or_evt, Event):
|
||||
evt = reg_or_evt
|
||||
await evt.wait()
|
||||
return cast(DeviceRegistry, hass.data.get(DATA_REGISTRY))
|
||||
|
||||
return cast(DeviceRegistry, reg_or_evt)
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_area(registry: DeviceRegistry, area_id: str) -> List[DeviceEntry]:
|
||||
|
@ -7,7 +7,6 @@ The Entity Registry will persist itself 10 seconds after a new entity is
|
||||
registered. Registering a new entity while a timer is in progress resets the
|
||||
timer.
|
||||
"""
|
||||
import asyncio
|
||||
from collections import OrderedDict
|
||||
import logging
|
||||
from typing import (
|
||||
@ -39,6 +38,7 @@ from homeassistant.loader import bind_hass
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.util.yaml import load_yaml
|
||||
|
||||
from .singleton import singleton
|
||||
from .typing import HomeAssistantType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -492,27 +492,13 @@ class EntityRegistry:
|
||||
|
||||
|
||||
@bind_hass
|
||||
@singleton(DATA_REGISTRY)
|
||||
async def async_get_registry(hass: HomeAssistantType) -> EntityRegistry:
|
||||
"""Return entity registry instance."""
|
||||
reg_or_evt = hass.data.get(DATA_REGISTRY)
|
||||
|
||||
if not reg_or_evt:
|
||||
evt = hass.data[DATA_REGISTRY] = asyncio.Event()
|
||||
|
||||
"""Create entity registry."""
|
||||
reg = EntityRegistry(hass)
|
||||
await reg.async_load()
|
||||
|
||||
hass.data[DATA_REGISTRY] = reg
|
||||
evt.set()
|
||||
return reg
|
||||
|
||||
if isinstance(reg_or_evt, asyncio.Event):
|
||||
evt = reg_or_evt
|
||||
await evt.wait()
|
||||
return cast(EntityRegistry, hass.data.get(DATA_REGISTRY))
|
||||
|
||||
return cast(EntityRegistry, reg_or_evt)
|
||||
|
||||
|
||||
@callback
|
||||
def async_entries_for_device(
|
||||
@ -621,4 +607,4 @@ async def async_migrate_entries(
|
||||
updates = entry_callback(entry)
|
||||
|
||||
if updates is not None:
|
||||
ent_reg.async_update_entity(entry.entity_id, **updates) # type: ignore
|
||||
ent_reg.async_update_entity(entry.entity_id, **updates)
|
||||
|
44
homeassistant/helpers/singleton.py
Normal file
44
homeassistant/helpers/singleton.py
Normal file
@ -0,0 +1,44 @@
|
||||
"""Helper to help coordinating calls."""
|
||||
import asyncio
|
||||
import functools
|
||||
from typing import Awaitable, Callable, TypeVar, cast
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
FUNC = Callable[[HomeAssistant], Awaitable[T]]
|
||||
|
||||
|
||||
def singleton(data_key: str) -> Callable[[FUNC], FUNC]:
|
||||
"""Decorate a function that should be called once per instance.
|
||||
|
||||
Result will be cached and simultaneous calls will be handled.
|
||||
"""
|
||||
|
||||
def wrapper(func: FUNC) -> FUNC:
|
||||
"""Wrap a function with caching logic."""
|
||||
|
||||
@functools.wraps(func)
|
||||
async def wrapped(hass: HomeAssistant) -> T:
|
||||
obj_or_evt = hass.data.get(data_key)
|
||||
|
||||
if not obj_or_evt:
|
||||
evt = hass.data[data_key] = asyncio.Event()
|
||||
|
||||
result = await func(hass)
|
||||
|
||||
hass.data[data_key] = result
|
||||
evt.set()
|
||||
return cast(T, result)
|
||||
|
||||
if isinstance(obj_or_evt, asyncio.Event):
|
||||
evt = obj_or_evt
|
||||
await evt.wait()
|
||||
return cast(T, hass.data.get(data_key))
|
||||
|
||||
return cast(T, obj_or_evt)
|
||||
|
||||
return wrapped
|
||||
|
||||
return wrapper
|
Loading…
x
Reference in New Issue
Block a user