Speed up async_get_loaded_integrations (#117851)
* Speed up async_get_loaded_integrations Use a setcomp and difference to find the components to split to avoid the loop. A setcomp is inlined in python3.12 so its much faster * Speed up async_get_loaded_integrations Use a setcomp and difference to find the components to split to avoid the loop. A setcomp is inlined in python3.12 so its much faster * simplify * fix compat * bootstrap * fix testspull/116422/head
parent
266ce9e268
commit
e12d23bd48
|
@ -63,6 +63,7 @@ from .components import (
|
|||
)
|
||||
from .components.sensor import recorder as sensor_recorder # noqa: F401
|
||||
from .const import (
|
||||
BASE_PLATFORMS,
|
||||
FORMAT_DATETIME,
|
||||
KEY_DATA_LOGGING as DATA_LOGGING,
|
||||
REQUIRED_NEXT_PYTHON_HA_RELEASE,
|
||||
|
@ -90,7 +91,6 @@ from .helpers.storage import get_internal_store_manager
|
|||
from .helpers.system_info import async_get_system_info
|
||||
from .helpers.typing import ConfigType
|
||||
from .setup import (
|
||||
BASE_PLATFORMS,
|
||||
# _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
|
||||
|
|
|
@ -83,6 +83,9 @@ class Platform(StrEnum):
|
|||
WEATHER = "weather"
|
||||
|
||||
|
||||
BASE_PLATFORMS: Final = {platform.value for platform in Platform}
|
||||
|
||||
|
||||
# Can be used to specify a catch all when registering state or event listeners.
|
||||
MATCH_ALL: Final = "*"
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ from .const import (
|
|||
ATTR_FRIENDLY_NAME,
|
||||
ATTR_SERVICE,
|
||||
ATTR_SERVICE_DATA,
|
||||
BASE_PLATFORMS,
|
||||
COMPRESSED_STATE_ATTRIBUTES,
|
||||
COMPRESSED_STATE_CONTEXT,
|
||||
COMPRESSED_STATE_LAST_CHANGED,
|
||||
|
@ -2769,16 +2770,27 @@ class _ComponentSet(set[str]):
|
|||
|
||||
The top level components set only contains the top level components.
|
||||
|
||||
The all components set contains all components, including platform
|
||||
based components.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, top_level_components: set[str]) -> None:
|
||||
def __init__(
|
||||
self, top_level_components: set[str], all_components: set[str]
|
||||
) -> None:
|
||||
"""Initialize the component set."""
|
||||
self._top_level_components = top_level_components
|
||||
self._all_components = all_components
|
||||
|
||||
def add(self, component: str) -> None:
|
||||
"""Add a component to the store."""
|
||||
if "." not in component:
|
||||
self._top_level_components.add(component)
|
||||
self._all_components.add(component)
|
||||
else:
|
||||
platform, _, domain = component.partition(".")
|
||||
if domain in BASE_PLATFORMS:
|
||||
self._all_components.add(platform)
|
||||
return super().add(component)
|
||||
|
||||
def remove(self, component: str) -> None:
|
||||
|
@ -2831,8 +2843,14 @@ class Config:
|
|||
# and should not be modified directly
|
||||
self.top_level_components: set[str] = set()
|
||||
|
||||
# Set of all loaded components including platform
|
||||
# based components
|
||||
self.all_components: set[str] = set()
|
||||
|
||||
# Set of loaded components
|
||||
self.components: _ComponentSet = _ComponentSet(self.top_level_components)
|
||||
self.components: _ComponentSet = _ComponentSet(
|
||||
self.top_level_components, self.all_components
|
||||
)
|
||||
|
||||
# API (HTTP) server configuration
|
||||
self.api: ApiConfig | None = None
|
||||
|
|
|
@ -16,10 +16,10 @@ from typing import Any, Final, TypedDict
|
|||
|
||||
from . import config as conf_util, core, loader, requirements
|
||||
from .const import (
|
||||
BASE_PLATFORMS, # noqa: F401
|
||||
EVENT_COMPONENT_LOADED,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
PLATFORM_FORMAT,
|
||||
Platform,
|
||||
)
|
||||
from .core import (
|
||||
CALLBACK_TYPE,
|
||||
|
@ -44,7 +44,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
ATTR_COMPONENT: Final = "component"
|
||||
|
||||
BASE_PLATFORMS = {platform.value for platform in Platform}
|
||||
|
||||
# DATA_SETUP is a dict, indicating domains which are currently
|
||||
# being setup or which failed to setup:
|
||||
|
@ -637,15 +636,7 @@ def _async_when_setup(
|
|||
@core.callback
|
||||
def async_get_loaded_integrations(hass: core.HomeAssistant) -> set[str]:
|
||||
"""Return the complete list of loaded integrations."""
|
||||
integrations = set()
|
||||
for component in hass.config.components:
|
||||
if "." not in component:
|
||||
integrations.add(component)
|
||||
continue
|
||||
platform, _, domain = component.partition(".")
|
||||
if domain in BASE_PLATFORMS:
|
||||
integrations.add(platform)
|
||||
return integrations
|
||||
return hass.config.all_components
|
||||
|
||||
|
||||
class SetupPhases(StrEnum):
|
||||
|
|
|
@ -246,7 +246,7 @@ async def test_send_usage(
|
|||
|
||||
assert analytics.preferences[ATTR_BASE]
|
||||
assert analytics.preferences[ATTR_USAGE]
|
||||
hass.config.components = ["default_config"]
|
||||
hass.config.components.add("default_config")
|
||||
|
||||
with patch(
|
||||
"homeassistant.config.load_yaml_config_file",
|
||||
|
@ -280,7 +280,7 @@ async def test_send_usage_with_supervisor(
|
|||
await analytics.save_preferences({ATTR_BASE: True, ATTR_USAGE: True})
|
||||
assert analytics.preferences[ATTR_BASE]
|
||||
assert analytics.preferences[ATTR_USAGE]
|
||||
hass.config.components = ["default_config"]
|
||||
hass.config.components.add("default_config")
|
||||
|
||||
with (
|
||||
patch(
|
||||
|
@ -344,7 +344,7 @@ async def test_send_statistics(
|
|||
await analytics.save_preferences({ATTR_BASE: True, ATTR_STATISTICS: True})
|
||||
assert analytics.preferences[ATTR_BASE]
|
||||
assert analytics.preferences[ATTR_STATISTICS]
|
||||
hass.config.components = ["default_config"]
|
||||
hass.config.components.add("default_config")
|
||||
|
||||
with patch(
|
||||
"homeassistant.config.load_yaml_config_file",
|
||||
|
|
Loading…
Reference in New Issue