diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 9a9ec98d0d6..558584d68ac 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -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 diff --git a/homeassistant/const.py b/homeassistant/const.py index 77de43f730f..bfbf7ca48a6 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -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 = "*" diff --git a/homeassistant/core.py b/homeassistant/core.py index 6aa0204d8b4..5d3433855df 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -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 diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 89848c1488e..1f71adaf486 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -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): diff --git a/tests/components/analytics/test_analytics.py b/tests/components/analytics/test_analytics.py index da8d45d41ad..587b8600f3f 100644 --- a/tests/components/analytics/test_analytics.py +++ b/tests/components/analytics/test_analytics.py @@ -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",