diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index db86d24c667..beb04b50021 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -675,6 +675,9 @@ async def _async_resolve_domains_to_setup( base_platforms_loaded = False domains_to_setup = _get_domains(hass, config) needed_requirements: set[str] = set() + platform_integrations = conf_util.extract_platform_integrations( + config, BASE_PLATFORMS + ) # Resolve all dependencies so we know all integrations # that will have to be loaded and start rightaway @@ -691,7 +694,7 @@ async def _async_resolve_domains_to_setup( # to avoid the lock contention when multiple # integrations try to resolve them at once base_platforms_loaded = True - to_get = {*old_to_resolve, *BASE_PLATFORMS} + to_get = {*old_to_resolve, *BASE_PLATFORMS, *platform_integrations} else: to_get = old_to_resolve @@ -700,13 +703,16 @@ async def _async_resolve_domains_to_setup( integrations_to_process: list[loader.Integration] = [] for domain, itg in (await loader.async_get_integrations(hass, to_get)).items(): - if not isinstance(itg, loader.Integration) or domain not in old_to_resolve: + if not isinstance(itg, loader.Integration): continue - integrations_to_process.append(itg) integration_cache[domain] = itg + needed_requirements.update(itg.requirements) + if domain not in old_to_resolve: + continue + + integrations_to_process.append(itg) manifest_deps.update(itg.dependencies) manifest_deps.update(itg.after_dependencies) - needed_requirements.update(itg.requirements) if not itg.all_dependencies_resolved: resolve_dependencies_tasks.append( create_eager_task( @@ -760,7 +766,9 @@ async def _async_resolve_domains_to_setup( # wait for the translation load lock, loading will be done by the # time it gets to it. hass.async_create_background_task( - translation.async_load_integrations(hass, {*BASE_PLATFORMS, *domains_to_setup}), + translation.async_load_integrations( + hass, {*BASE_PLATFORMS, *platform_integrations, *domains_to_setup} + ), "load translations", eager_start=True, ) diff --git a/homeassistant/config.py b/homeassistant/config.py index 36ac3843b3a..a72bd00ed44 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -1388,6 +1388,30 @@ def config_per_platform( yield platform, item +def extract_platform_integrations(config: ConfigType, domains: set[str]) -> set[str]: + """Find all the platforms in a configuration.""" + platform_integrations: set[str] = set() + for key, domain_config in config.items(): + try: + domain = cv.domain_key(key) + except vol.Invalid: + continue + if domain not in domains: + continue + + if not isinstance(domain_config, list): + domain_config = [domain_config] + + for item in domain_config: + try: + platform = item.get(CONF_PLATFORM) + except AttributeError: + continue + if platform: + platform_integrations.add(platform) + return platform_integrations + + def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]: """Extract keys from config for given domain name. diff --git a/tests/test_config.py b/tests/test_config.py index 5726c515dc3..73c541bc7e1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2339,3 +2339,34 @@ def test_config_per_platform() -> None: (None, 1), ("hello 2", config["zone Hallo"][1]), ] == list(config_util.config_per_platform(config, "zone")) + + +def test_extract_platform_integrations() -> None: + """Test extract_platform_integrations.""" + config = OrderedDict( + [ + (b"zone", {"platform": "not str"}), + ("zone", {"platform": "hello"}), + ("zonex", []), + ("zoney", ""), + ("notzone", {"platform": "nothello"}), + ("zoner", None), + ("zone Hallo", [1, {"platform": "hello 2"}]), + ("zone 100", None), + ("i n v a-@@", None), + ("i n v a-@@", {"platform": "hello"}), + ("zoneq", "pig"), + ("zoneempty", {"platform": ""}), + ] + ) + assert config_util.extract_platform_integrations(config, {"zone"}) == { + "hello", + "hello 2", + } + assert config_util.extract_platform_integrations(config, {"zonex"}) == set() + assert config_util.extract_platform_integrations(config, {"zoney"}) == set() + assert config_util.extract_platform_integrations( + config, {"zone", "not_valid", "notzone"} + ) == {"hello", "hello 2", "nothello"} + assert config_util.extract_platform_integrations(config, {"zoneq"}) == set() + assert config_util.extract_platform_integrations(config, {"zoneempty"}) == set()