Migrate integration_platform helper to use async_get_integrations (#89303)
* Migrate integration_platform helper to use async_get_integrations We were fetching integrations inside the gather one at a time. This is inefficent. * cleanup * cleanup * add task name * small tweaks * gather only if we have taskspull/88942/head^2
parent
4f11344bc3
commit
e1d62b554a
|
@ -8,8 +8,8 @@ import logging
|
|||
from typing import Any
|
||||
|
||||
from homeassistant.const import EVENT_COMPONENT_LOADED
|
||||
from homeassistant.core import Event, HomeAssistant
|
||||
from homeassistant.loader import async_get_integration, bind_hass
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.loader import Integration, async_get_integrations, bind_hass
|
||||
from homeassistant.setup import ATTR_COMPONENT
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -26,14 +26,24 @@ class IntegrationPlatform:
|
|||
|
||||
|
||||
async def _async_process_single_integration_platform_component(
|
||||
hass: HomeAssistant, component_name: str, integration_platform: IntegrationPlatform
|
||||
hass: HomeAssistant,
|
||||
component_name: str,
|
||||
integration: Integration | Exception,
|
||||
integration_platform: IntegrationPlatform,
|
||||
) -> None:
|
||||
"""Process a single integration platform."""
|
||||
if component_name in integration_platform.seen_components:
|
||||
return
|
||||
integration_platform.seen_components.add(component_name)
|
||||
|
||||
integration = await async_get_integration(hass, component_name)
|
||||
if isinstance(integration, Exception):
|
||||
_LOGGER.exception(
|
||||
"Error importing integration %s for %s",
|
||||
component_name,
|
||||
integration_platform.platform_name,
|
||||
)
|
||||
return
|
||||
|
||||
platform_name = integration_platform.platform_name
|
||||
|
||||
try:
|
||||
|
@ -75,14 +85,22 @@ async def async_process_integration_platform_for_component(
|
|||
integration_platforms: list[IntegrationPlatform] = hass.data[
|
||||
DATA_INTEGRATION_PLATFORMS
|
||||
]
|
||||
await asyncio.gather(
|
||||
*[
|
||||
integrations = await async_get_integrations(hass, (component_name,))
|
||||
tasks = [
|
||||
asyncio.create_task(
|
||||
_async_process_single_integration_platform_component(
|
||||
hass, component_name, integration_platform
|
||||
)
|
||||
for integration_platform in integration_platforms
|
||||
]
|
||||
)
|
||||
hass,
|
||||
component_name,
|
||||
integrations[component_name],
|
||||
integration_platform,
|
||||
),
|
||||
name=f"process integration platform {integration_platform.platform_name} for {component_name}",
|
||||
)
|
||||
for integration_platform in integration_platforms
|
||||
if component_name not in integration_platform.seen_components
|
||||
]
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
@bind_hass
|
||||
|
@ -98,25 +116,39 @@ async def async_process_integration_platforms(
|
|||
|
||||
async def _async_component_loaded(event: Event) -> None:
|
||||
"""Handle a new component loaded."""
|
||||
comp = event.data[ATTR_COMPONENT]
|
||||
if "." not in comp:
|
||||
await async_process_integration_platform_for_component(hass, comp)
|
||||
await async_process_integration_platform_for_component(
|
||||
hass, event.data[ATTR_COMPONENT]
|
||||
)
|
||||
|
||||
hass.bus.async_listen(EVENT_COMPONENT_LOADED, _async_component_loaded)
|
||||
@callback
|
||||
def _async_component_loaded_filter(event: Event) -> bool:
|
||||
"""Handle integration platforms loaded."""
|
||||
return "." not in event.data[ATTR_COMPONENT]
|
||||
|
||||
hass.bus.async_listen(
|
||||
EVENT_COMPONENT_LOADED,
|
||||
_async_component_loaded,
|
||||
event_filter=_async_component_loaded_filter,
|
||||
)
|
||||
|
||||
integration_platforms: list[IntegrationPlatform] = hass.data[
|
||||
DATA_INTEGRATION_PLATFORMS
|
||||
]
|
||||
integration_platform = IntegrationPlatform(platform_name, process_platform, set())
|
||||
integration_platforms.append(integration_platform)
|
||||
if top_level_components := (
|
||||
if top_level_components := [
|
||||
comp for comp in hass.config.components if "." not in comp
|
||||
):
|
||||
await asyncio.gather(
|
||||
*[
|
||||
]:
|
||||
integrations = await async_get_integrations(hass, top_level_components)
|
||||
tasks = [
|
||||
asyncio.create_task(
|
||||
_async_process_single_integration_platform_component(
|
||||
hass, comp, integration_platform
|
||||
)
|
||||
for comp in top_level_components
|
||||
]
|
||||
)
|
||||
hass, comp, integrations[comp], integration_platform
|
||||
),
|
||||
name=f"process integration platform {platform_name} for {comp}",
|
||||
)
|
||||
for comp in top_level_components
|
||||
if comp not in integration_platform.seen_components
|
||||
]
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Test integration platform helpers."""
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.integration_platform import (
|
||||
async_process_integration_platform_for_component,
|
||||
|
@ -51,3 +53,27 @@ async def test_process_integration_platforms_none_loaded(hass: HomeAssistant) ->
|
|||
# Verify we can call async_process_integration_platform_for_component
|
||||
# when there are none loaded and it does not throw
|
||||
await async_process_integration_platform_for_component(hass, "any")
|
||||
|
||||
|
||||
async def test_broken_integration(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test handling an integration with a broken or missing manifest."""
|
||||
Mock()
|
||||
hass.config.components.add("loaded")
|
||||
|
||||
event_platform = Mock()
|
||||
mock_platform(hass, "event.platform_to_check", event_platform)
|
||||
|
||||
processed = []
|
||||
|
||||
async def _process_platform(hass, domain, platform):
|
||||
"""Process platform."""
|
||||
processed.append((domain, platform))
|
||||
|
||||
await async_process_integration_platforms(
|
||||
hass, "platform_to_check", _process_platform
|
||||
)
|
||||
|
||||
assert len(processed) == 0
|
||||
assert "Error importing integration loaded for platform_to_check" in caplog.text
|
||||
|
|
Loading…
Reference in New Issue