From 1fb90084884c0dae1c18aec7ef590c06b33b1193 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 29 Mar 2021 00:51:48 -1000 Subject: [PATCH] Include platform only integrations in the manifest list api (#48269) --- .../components/device_tracker/legacy.py | 9 +++-- .../components/websocket_api/commands.py | 9 ++--- homeassistant/setup.py | 36 +++++++++++++++++++ script/hassfest/dependencies.py | 19 ++-------- tests/test_setup.py | 18 ++++++++++ 5 files changed, 65 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/device_tracker/legacy.py b/homeassistant/components/device_tracker/legacy.py index 7ab8df1de87..1649c51b1ae 100644 --- a/homeassistant/components/device_tracker/legacy.py +++ b/homeassistant/components/device_tracker/legacy.py @@ -221,7 +221,7 @@ class DeviceTrackerPlatform: async def async_setup_legacy(self, hass, tracker, discovery_info=None): """Set up a legacy platform.""" - LOGGER.info("Setting up %s.%s", DOMAIN, self.type) + LOGGER.info("Setting up %s.%s", DOMAIN, self.name) try: scanner = None setup = None @@ -248,6 +248,9 @@ class DeviceTrackerPlatform: else: raise HomeAssistantError("Invalid legacy device_tracker platform.") + if setup: + hass.config.components.add(f"{DOMAIN}.{self.name}") + if scanner: async_setup_scanner_platform( hass, self.config, scanner, tracker.async_see, self.type @@ -255,11 +258,11 @@ class DeviceTrackerPlatform: return if not setup: - LOGGER.error("Error setting up platform %s", self.type) + LOGGER.error("Error setting up platform %s %s", self.type, self.name) return except Exception: # pylint: disable=broad-except - LOGGER.exception("Error setting up platform %s", self.type) + LOGGER.exception("Error setting up platform %s %s", self.type, self.name) async def async_extract_config(hass, config): diff --git a/homeassistant/components/websocket_api/commands.py b/homeassistant/components/websocket_api/commands.py index f85281d10c1..74251e1bf24 100644 --- a/homeassistant/components/websocket_api/commands.py +++ b/homeassistant/components/websocket_api/commands.py @@ -17,6 +17,7 @@ from homeassistant.helpers import config_validation as cv, entity, template from homeassistant.helpers.event import TrackTemplate, async_track_template_result from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.loader import IntegrationNotFound, async_get_integration +from homeassistant.setup import async_get_loaded_integrations from . import const, decorators, messages @@ -215,13 +216,9 @@ def handle_get_config(hass, connection, msg): @decorators.async_response async def handle_manifest_list(hass, connection, msg): """Handle integrations command.""" + loaded_integrations = async_get_loaded_integrations(hass) integrations = await asyncio.gather( - *[ - async_get_integration(hass, domain) - for domain in hass.config.components - # Filter out platforms. - if "." not in domain - ] + *[async_get_integration(hass, domain) for domain in loaded_integrations] ) connection.send_result( msg["id"], [integration.manifest for integration in integrations] diff --git a/homeassistant/setup.py b/homeassistant/setup.py index c22e660e553..288f9d0847b 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -18,6 +18,28 @@ _LOGGER = logging.getLogger(__name__) ATTR_COMPONENT = "component" +BASE_PLATFORMS = { + "air_quality", + "alarm_control_panel", + "binary_sensor", + "climate", + "cover", + "device_tracker", + "fan", + "humidifier", + "image_processing", + "light", + "lock", + "media_player", + "notify", + "remote", + "scene", + "sensor", + "switch", + "vacuum", + "water_heater", +} + DATA_SETUP_DONE = "setup_done" DATA_SETUP_STARTED = "setup_started" DATA_SETUP = "setup_tasks" @@ -381,3 +403,17 @@ def async_when_setup( await when_setup() unsub = hass.bus.async_listen(EVENT_COMPONENT_LOADED, loaded_event) + + +@core.callback +def async_get_loaded_integrations(hass: core.HomeAssistant) -> set: + """Return the complete list of loaded integrations.""" + integrations = set() + for component in hass.config.components: + if "." not in component: + integrations.add(component) + continue + domain, platform = component.split(".", 1) + if domain in BASE_PLATFORMS: + integrations.add(platform) + return integrations diff --git a/script/hassfest/dependencies.py b/script/hassfest/dependencies.py index 5f885c59a1d..cb7458af154 100644 --- a/script/hassfest/dependencies.py +++ b/script/hassfest/dependencies.py @@ -5,6 +5,7 @@ import ast from pathlib import Path from homeassistant.requirements import DISCOVERY_INTEGRATIONS +from homeassistant.setup import BASE_PLATFORMS from .model import Integration @@ -107,7 +108,6 @@ ALLOWED_USED_COMPONENTS = { "onboarding", "persistent_notification", "person", - "remote", "script", "shopping_list", "sun", @@ -118,22 +118,7 @@ ALLOWED_USED_COMPONENTS = { "websocket_api", "zone", # Entity integrations with platforms - "alarm_control_panel", - "binary_sensor", - "climate", - "cover", - "device_tracker", - "fan", - "humidifier", - "image_processing", - "light", - "lock", - "media_player", - "scene", - "sensor", - "switch", - "vacuum", - "water_heater", + *BASE_PLATFORMS, # Other "mjpeg", # base class, has no reqs or component to load. "stream", # Stream cannot install on all systems, can be imported without reqs. diff --git a/tests/test_setup.py b/tests/test_setup.py index abb8f756989..c2cbc3d6ea8 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -600,3 +600,21 @@ async def test_integration_disabled(hass, caplog): result = await setup.async_setup_component(hass, "test_component1", {}) assert not result assert disabled_reason in caplog.text + + +async def test_async_get_loaded_integrations(hass): + """Test we can enumerate loaded integations.""" + hass.config.components.add("notbase") + hass.config.components.add("switch") + hass.config.components.add("notbase.switch") + hass.config.components.add("myintegration") + hass.config.components.add("device_tracker") + hass.config.components.add("device_tracker.other") + hass.config.components.add("myintegration.light") + assert setup.async_get_loaded_integrations(hass) == { + "other", + "switch", + "notbase", + "myintegration", + "device_tracker", + }