diff --git a/homeassistant/components/intent/__init__.py b/homeassistant/components/intent/__init__.py index 53960851f6c..bdf612b2e83 100644 --- a/homeassistant/components/intent/__init__.py +++ b/homeassistant/components/intent/__init__.py @@ -1,16 +1,12 @@ """The Intent integration.""" -import asyncio import logging import voluptuous as vol from homeassistant.components import http from homeassistant.components.http.data_validator import RequestDataValidator -from homeassistant.const import EVENT_COMPONENT_LOADED from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv, intent -from homeassistant.loader import IntegrationNotFound, async_get_integration -from homeassistant.setup import ATTR_COMPONENT +from homeassistant.helpers import config_validation as cv, integration_platform, intent from .const import DOMAIN @@ -22,32 +18,16 @@ async def async_setup(hass: HomeAssistant, config: dict): """Set up the Intent component.""" hass.http.register_view(IntentHandleView()) - tasks = [_async_process_intent(hass, comp) for comp in hass.config.components] - - async def async_component_loaded(event): - """Handle a new component loaded.""" - await _async_process_intent(hass, event.data[ATTR_COMPONENT]) - - hass.bus.async_listen(EVENT_COMPONENT_LOADED, async_component_loaded) - - if tasks: - await asyncio.gather(*tasks) + await integration_platform.async_process_integration_platforms( + hass, DOMAIN, _async_process_intent + ) return True -async def _async_process_intent(hass: HomeAssistant, component_name: str): - """Process the intents of a component.""" - try: - integration = await async_get_integration(hass, component_name) - platform = integration.get_platform(DOMAIN) - except (IntegrationNotFound, ImportError): - return - - try: - await platform.async_setup_intents(hass) - except Exception: # pylint: disable=broad-except - _LOGGER.exception("Error setting up intents for %s", component_name) +async def _async_process_intent(hass: HomeAssistant, domain: str, platform): + """Process the intents of an integration.""" + await platform.async_setup_intents(hass) class IntentHandleView(http.HomeAssistantView): diff --git a/homeassistant/helpers/integration_platform.py b/homeassistant/helpers/integration_platform.py new file mode 100644 index 00000000000..01567c72c7b --- /dev/null +++ b/homeassistant/helpers/integration_platform.py @@ -0,0 +1,46 @@ +"""Helpers to help with integration platforms.""" +import asyncio +import logging +from typing import Any, Awaitable, Callable + +from homeassistant.core import Event, HomeAssistant +from homeassistant.loader import IntegrationNotFound, async_get_integration, bind_hass +from homeassistant.setup import ATTR_COMPONENT, EVENT_COMPONENT_LOADED + +_LOGGER = logging.getLogger(__name__) + + +@bind_hass +async def async_process_integration_platforms( + hass: HomeAssistant, + platform_name: str, + # Any = platform. + process_platform: Callable[[HomeAssistant, str, Any], Awaitable[None]], +) -> None: + """Process a specific platform for all current and future loaded integrations.""" + + async def _process(component_name: str) -> None: + """Process the intents of a component.""" + try: + integration = await async_get_integration(hass, component_name) + platform = integration.get_platform(platform_name) + except (IntegrationNotFound, ImportError): + return + + try: + await process_platform(hass, component_name, platform) + except Exception: # pylint: disable=broad-except + _LOGGER.exception( + "Error processing platform %s.%s", component_name, platform_name + ) + + async def async_component_loaded(event: Event) -> None: + """Handle a new component loaded.""" + await _process(event.data[ATTR_COMPONENT]) + + hass.bus.async_listen(EVENT_COMPONENT_LOADED, async_component_loaded) + + tasks = [_process(comp) for comp in hass.config.components] + + if tasks: + await asyncio.gather(*tasks) diff --git a/tests/helpers/test_integration_platform.py b/tests/helpers/test_integration_platform.py new file mode 100644 index 00000000000..d6c844c0d91 --- /dev/null +++ b/tests/helpers/test_integration_platform.py @@ -0,0 +1,37 @@ +"""Test integration platform helpers.""" +from unittest.mock import Mock + +from homeassistant.setup import ATTR_COMPONENT, EVENT_COMPONENT_LOADED + +from tests.common import mock_platform + + +async def test_process_integration_platforms(hass): + """Test processing integrations.""" + loaded_platform = Mock() + mock_platform(hass, "loaded.platform_to_check", loaded_platform) + 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 hass.helpers.integration_platform.async_process_integration_platforms( + "platform_to_check", _process_platform + ) + + assert len(processed) == 1 + assert processed[0][0] == "loaded" + assert processed[0][1] == loaded_platform + + hass.bus.async_fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: "event"}) + await hass.async_block_till_done() + + assert len(processed) == 2 + assert processed[1][0] == "event" + assert processed[1][1] == event_platform