Speed up singleton decorator so it can be used more places (#116292)

This commit is contained in:
J. Nick Koston 2024-04-28 12:11:08 -05:00 committed by GitHub
parent 48b1678075
commit ab2ea6100c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 25 additions and 28 deletions

View file

@ -90,7 +90,11 @@ from .helpers.system_info import async_get_system_info
from .helpers.typing import ConfigType
from .setup import (
BASE_PLATFORMS,
DATA_SETUP_STARTED,
# _setup_started is marked as protected to make it clear
# that it is not part of the public API and should not be used
# by integrations. It is only used for internal tracking of
# which integrations are being set up.
_setup_started,
async_get_setup_timings,
async_notify_setup_error,
async_set_domains_to_be_loaded,
@ -913,9 +917,7 @@ async def _async_set_up_integrations(
hass: core.HomeAssistant, config: dict[str, Any]
) -> None:
"""Set up all the integrations."""
setup_started: dict[tuple[str, str | None], float] = {}
hass.data[DATA_SETUP_STARTED] = setup_started
watcher = _WatchPendingSetups(hass, setup_started)
watcher = _WatchPendingSetups(hass, _setup_started(hass))
watcher.async_start()
domains_to_setup, integration_cache = await _async_resolve_domains_to_setup(

View file

@ -66,7 +66,7 @@ from homeassistant.loader import async_suggest_report_issue, bind_hass
from homeassistant.util import ensure_unique_string, slugify
from homeassistant.util.frozen_dataclass_compat import FrozenOrThawed
from . import device_registry as dr, entity_registry as er
from . import device_registry as dr, entity_registry as er, singleton
from .device_registry import DeviceInfo, EventDeviceRegistryUpdatedData
from .event import (
async_track_device_registry_updated_event,
@ -98,15 +98,15 @@ CONTEXT_RECENT_TIME_SECONDS = 5 # Time that a context is considered recent
@callback
def async_setup(hass: HomeAssistant) -> None:
"""Set up entity sources."""
hass.data[DATA_ENTITY_SOURCE] = {}
entity_sources(hass)
@callback
@bind_hass
@singleton.singleton(DATA_ENTITY_SOURCE)
def entity_sources(hass: HomeAssistant) -> dict[str, EntityInfo]:
"""Get the entity sources."""
_entity_sources: dict[str, EntityInfo] = hass.data[DATA_ENTITY_SOURCE]
return _entity_sources
return {}
def generate_entity_id(
@ -1486,7 +1486,7 @@ class Entity(
# The check for self.platform guards against integrations not using an
# EntityComponent and can be removed in HA Core 2024.1
if self.platform:
self.hass.data[DATA_ENTITY_SOURCE].pop(self.entity_id)
entity_sources(self.hass).pop(self.entity_id)
@callback
def _async_registry_updated(

View file

@ -25,6 +25,7 @@ def singleton(data_key: str) -> Callable[[_FuncType[_T]], _FuncType[_T]]:
"""Wrap a function with caching logic."""
if not asyncio.iscoroutinefunction(func):
@functools.lru_cache(maxsize=1)
@bind_hass
@functools.wraps(func)
def wrapped(hass: HomeAssistant) -> _T:

View file

@ -24,6 +24,8 @@ from homeassistant.loader import (
)
from homeassistant.util.json import load_json
from . import singleton
_LOGGER = logging.getLogger(__name__)
TRANSLATION_FLATTEN_CACHE = "translation_flatten_cache"
@ -370,11 +372,10 @@ def async_get_cached_translations(
)
@callback
@singleton.singleton(TRANSLATION_FLATTEN_CACHE)
def _async_get_translations_cache(hass: HomeAssistant) -> _TranslationCache:
"""Return the translation cache."""
cache: _TranslationCache = hass.data[TRANSLATION_FLATTEN_CACHE]
return cache
return _TranslationCache(hass)
@callback
@ -385,7 +386,7 @@ def async_setup(hass: HomeAssistant) -> None:
"""
cache = _TranslationCache(hass)
current_language = hass.config.language
hass.data[TRANSLATION_FLATTEN_CACHE] = cache
_async_get_translations_cache(hass)
@callback
def _async_load_translations_filter(event_data: Mapping[str, Any]) -> bool:

View file

@ -12,6 +12,7 @@ from packaging.requirements import Requirement
from .core import HomeAssistant, callback
from .exceptions import HomeAssistantError
from .helpers import singleton
from .helpers.typing import UNDEFINED, UndefinedType
from .loader import Integration, IntegrationNotFound, async_get_integration
from .util import package as pkg_util
@ -72,14 +73,10 @@ async def async_load_installed_versions(
@callback
@singleton.singleton(DATA_REQUIREMENTS_MANAGER)
def _async_get_manager(hass: HomeAssistant) -> RequirementsManager:
"""Get the requirements manager."""
if DATA_REQUIREMENTS_MANAGER in hass.data:
manager: RequirementsManager = hass.data[DATA_REQUIREMENTS_MANAGER]
return manager
manager = hass.data[DATA_REQUIREMENTS_MANAGER] = RequirementsManager(hass)
return manager
return RequirementsManager(hass)
@callback

View file

@ -29,7 +29,7 @@ from .core import (
callback,
)
from .exceptions import DependencyError, HomeAssistantError
from .helpers import translation
from .helpers import singleton, translation
from .helpers.issue_registry import IssueSeverity, async_create_issue
from .helpers.typing import ConfigType
from .util.async_ import create_eager_task
@ -671,13 +671,12 @@ class SetupPhases(StrEnum):
"""Wait time for the packages to import."""
@singleton.singleton(DATA_SETUP_STARTED)
def _setup_started(
hass: core.HomeAssistant,
) -> dict[tuple[str, str | None], float]:
"""Return the setup started dict."""
if DATA_SETUP_STARTED not in hass.data:
hass.data[DATA_SETUP_STARTED] = {}
return hass.data[DATA_SETUP_STARTED] # type: ignore[no-any-return]
return {}
@contextlib.contextmanager
@ -717,15 +716,12 @@ def async_pause_setup(
)
@singleton.singleton(DATA_SETUP_TIME)
def _setup_times(
hass: core.HomeAssistant,
) -> defaultdict[str, defaultdict[str | None, defaultdict[SetupPhases, float]]]:
"""Return the setup timings default dict."""
if DATA_SETUP_TIME not in hass.data:
hass.data[DATA_SETUP_TIME] = defaultdict(
lambda: defaultdict(lambda: defaultdict(float))
)
return hass.data[DATA_SETUP_TIME] # type: ignore[no-any-return]
return defaultdict(lambda: defaultdict(lambda: defaultdict(float)))
@contextlib.contextmanager