From e99184bf68cf4d475624d4b77eccca74ae5fa267 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 5 Dec 2019 00:28:56 -0800 Subject: [PATCH] Install requirements of after_dependencies when loading integrations (#29491) * Install requirements of after_dependencies when loading integrations * Fix smartthings test --- homeassistant/components/auth/manifest.json | 9 +++----- homeassistant/components/camera/manifest.json | 7 +----- homeassistant/components/cast/manifest.json | 1 + .../components/google_assistant/manifest.json | 1 + .../components/mobile_app/http_api.py | 13 +++++------ .../components/mobile_app/manifest.json | 1 + .../components/mobile_app/webhook.py | 9 ++++---- .../components/mobile_app/websocket_api.py | 2 +- .../components/onboarding/manifest.json | 9 ++------ .../components/owntracks/__init__.py | 2 +- .../components/owntracks/config_flow.py | 5 +---- .../components/owntracks/manifest.json | 12 +++------- homeassistant/components/proxy/camera.py | 22 +++++++++++-------- homeassistant/components/proxy/manifest.json | 4 +--- .../components/smartthings/manifest.json | 14 ++++-------- .../components/smartthings/smartapp.py | 18 +++------------ homeassistant/setup.py | 4 ++-- script/hassfest/dependencies.py | 13 +++++------ .../smartthings/test_config_flow.py | 9 ++++---- 19 files changed, 57 insertions(+), 98 deletions(-) diff --git a/homeassistant/components/auth/manifest.json b/homeassistant/components/auth/manifest.json index 1b0ab33f3815..2f3e724b5831 100644 --- a/homeassistant/components/auth/manifest.json +++ b/homeassistant/components/auth/manifest.json @@ -3,10 +3,7 @@ "name": "Auth", "documentation": "https://www.home-assistant.io/integrations/auth", "requirements": [], - "dependencies": [ - "http" - ], - "codeowners": [ - "@home-assistant/core" - ] + "dependencies": ["http"], + "after_dependencies": ["onboarding"], + "codeowners": ["@home-assistant/core"] } diff --git a/homeassistant/components/camera/manifest.json b/homeassistant/components/camera/manifest.json index a3395965e4f7..1bd4bb7caeb0 100644 --- a/homeassistant/components/camera/manifest.json +++ b/homeassistant/components/camera/manifest.json @@ -3,11 +3,6 @@ "name": "Camera", "documentation": "https://www.home-assistant.io/integrations/camera", "requirements": [], - "dependencies": [ - "http" - ], - "after_dependencies": [ - "stream" - ], + "dependencies": ["http"], "codeowners": [] } diff --git a/homeassistant/components/cast/manifest.json b/homeassistant/components/cast/manifest.json index b6776a17f7cb..8ad6f8fdb8dc 100644 --- a/homeassistant/components/cast/manifest.json +++ b/homeassistant/components/cast/manifest.json @@ -5,6 +5,7 @@ "documentation": "https://www.home-assistant.io/integrations/cast", "requirements": ["pychromecast==4.0.1"], "dependencies": [], + "after_dependencies": ["cloud"], "zeroconf": ["_googlecast._tcp.local."], "codeowners": [] } diff --git a/homeassistant/components/google_assistant/manifest.json b/homeassistant/components/google_assistant/manifest.json index f97977a74001..94dd3b7f0790 100644 --- a/homeassistant/components/google_assistant/manifest.json +++ b/homeassistant/components/google_assistant/manifest.json @@ -4,5 +4,6 @@ "documentation": "https://www.home-assistant.io/integrations/google_assistant", "requirements": [], "dependencies": ["http"], + "after_dependencies": ["camera"], "codeowners": ["@home-assistant/cloud"] } diff --git a/homeassistant/components/mobile_app/http_api.py b/homeassistant/components/mobile_app/http_api.py index 11ca39e8b600..5be2d19789e4 100644 --- a/homeassistant/components/mobile_app/http_api.py +++ b/homeassistant/components/mobile_app/http_api.py @@ -37,9 +37,7 @@ class RegistrationsView(HomeAssistantView): webhook_id = generate_secret() - cloud_loaded = "cloud" in hass.config.components - - if cloud_loaded and hass.components.cloud.async_active_subscription(): + if hass.components.cloud.async_active_subscription(): data[ CONF_CLOUDHOOK_URL ] = await hass.components.cloud.async_create_cloudhook(webhook_id) @@ -59,11 +57,10 @@ class RegistrationsView(HomeAssistantView): ) remote_ui_url = None - if cloud_loaded: - try: - remote_ui_url = hass.components.cloud.async_remote_ui_url() - except hass.components.cloud.CloudNotAvailable: - pass + try: + remote_ui_url = hass.components.cloud.async_remote_ui_url() + except hass.components.cloud.CloudNotAvailable: + pass return self.json( { diff --git a/homeassistant/components/mobile_app/manifest.json b/homeassistant/components/mobile_app/manifest.json index 29ee35e002c0..230a60fdf256 100644 --- a/homeassistant/components/mobile_app/manifest.json +++ b/homeassistant/components/mobile_app/manifest.json @@ -5,5 +5,6 @@ "documentation": "https://www.home-assistant.io/integrations/mobile_app", "requirements": ["PyNaCl==1.3.0"], "dependencies": ["http", "webhook"], + "after_dependencies": ["cloud"], "codeowners": ["@robbiet480"] } diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index 98687e6658fd..46f17b401bcd 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -309,10 +309,9 @@ async def handle_webhook( if CONF_CLOUDHOOK_URL in registration: resp[CONF_CLOUDHOOK_URL] = registration[CONF_CLOUDHOOK_URL] - if "cloud" in hass.config.components: - try: - resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url() - except hass.components.cloud.CloudNotAvailable: - pass + try: + resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url() + except hass.components.cloud.CloudNotAvailable: + pass return webhook_response(resp, registration=registration, headers=headers) diff --git a/homeassistant/components/mobile_app/websocket_api.py b/homeassistant/components/mobile_app/websocket_api.py index bc5305c36fa6..a18e5247bfa5 100644 --- a/homeassistant/components/mobile_app/websocket_api.py +++ b/homeassistant/components/mobile_app/websocket_api.py @@ -115,7 +115,7 @@ async def websocket_delete_registration( except HomeAssistantError: return error_message(msg["id"], "internal_error", "Error deleting registration") - if CONF_CLOUDHOOK_URL in registration and "cloud" in hass.config.components: + if CONF_CLOUDHOOK_URL in registration: await hass.components.cloud.async_delete_cloudhook(webhook_id) connection.send_message(result_message(msg["id"], "ok")) diff --git a/homeassistant/components/onboarding/manifest.json b/homeassistant/components/onboarding/manifest.json index 2febfc481e01..8e525ff0baad 100644 --- a/homeassistant/components/onboarding/manifest.json +++ b/homeassistant/components/onboarding/manifest.json @@ -3,11 +3,6 @@ "name": "Onboarding", "documentation": "https://www.home-assistant.io/integrations/onboarding", "requirements": [], - "dependencies": [ - "auth", - "http" - ], - "codeowners": [ - "@home-assistant/core" - ] + "dependencies": ["auth", "http", "person"], + "codeowners": ["@home-assistant/core"] } diff --git a/homeassistant/components/owntracks/__init__.py b/homeassistant/components/owntracks/__init__.py index d30e667f368e..8556e8a75560 100644 --- a/homeassistant/components/owntracks/__init__.py +++ b/homeassistant/components/owntracks/__init__.py @@ -118,7 +118,7 @@ async def async_unload_entry(hass, entry): async def async_remove_entry(hass, entry): """Remove an OwnTracks config entry.""" - if not entry.data.get("cloudhook") or "cloud" not in hass.config.components: + if not entry.data.get("cloudhook"): return await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID]) diff --git a/homeassistant/components/owntracks/config_flow.py b/homeassistant/components/owntracks/config_flow.py index ff4a649e0ce7..1a8bb838e181 100644 --- a/homeassistant/components/owntracks/config_flow.py +++ b/homeassistant/components/owntracks/config_flow.py @@ -66,10 +66,7 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN): async def _get_webhook_id(self): """Generate webhook ID.""" webhook_id = self.hass.components.webhook.async_generate_id() - if ( - "cloud" in self.hass.config.components - and self.hass.components.cloud.async_active_subscription() - ): + if self.hass.components.cloud.async_active_subscription(): webhook_url = await self.hass.components.cloud.async_create_cloudhook( webhook_id ) diff --git a/homeassistant/components/owntracks/manifest.json b/homeassistant/components/owntracks/manifest.json index 529d7990a864..63fdfb94cf77 100644 --- a/homeassistant/components/owntracks/manifest.json +++ b/homeassistant/components/owntracks/manifest.json @@ -3,14 +3,8 @@ "name": "Owntracks", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/owntracks", - "requirements": [ - "PyNaCl==1.3.0" - ], - "dependencies": [ - "webhook" - ], - "after_dependencies": [ - "mqtt" - ], + "requirements": ["PyNaCl==1.3.0"], + "dependencies": ["webhook"], + "after_dependencies": ["mqtt", "cloud"], "codeowners": [] } diff --git a/homeassistant/components/proxy/camera.py b/homeassistant/components/proxy/camera.py index 90487120ffe0..893fadfe178a 100644 --- a/homeassistant/components/proxy/camera.py +++ b/homeassistant/components/proxy/camera.py @@ -7,7 +7,13 @@ import logging from PIL import Image import voluptuous as vol -from homeassistant.components.camera import PLATFORM_SCHEMA, Camera +from homeassistant.components.camera import ( + PLATFORM_SCHEMA, + Camera, + async_get_image, + async_get_mjpeg_stream, + async_get_still_stream, +) from homeassistant.const import CONF_ENTITY_ID, CONF_MODE, CONF_NAME from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_validation as cv @@ -227,7 +233,7 @@ class ProxyCamera(Camera): return self._last_image self._last_image_time = now - image = await self.hass.components.camera.async_get_image(self._proxied_camera) + image = await async_get_image(self.hass, self._proxied_camera) if not image: _LOGGER.error("Error getting original camera image") return self._last_image @@ -247,12 +253,12 @@ class ProxyCamera(Camera): async def handle_async_mjpeg_stream(self, request): """Generate an HTTP MJPEG stream from camera images.""" if not self._stream_opts: - return await self.hass.components.camera.async_get_mjpeg_stream( - request, self._proxied_camera + return await async_get_mjpeg_stream( + self.hass, request, self._proxied_camera ) - return await self.hass.components.camera.async_get_still_stream( - request, self._async_stream_image, self.content_type, self.frame_interval + return await async_get_still_stream( + request, self._async_stream_image, self.content_type, self.frame_interval, ) @property @@ -263,9 +269,7 @@ class ProxyCamera(Camera): async def _async_stream_image(self): """Return a still image response from the camera.""" try: - image = await self.hass.components.camera.async_get_image( - self._proxied_camera - ) + image = await async_get_image(self.hass, self._proxied_camera) if not image: return None except HomeAssistantError: diff --git a/homeassistant/components/proxy/manifest.json b/homeassistant/components/proxy/manifest.json index 39f7b9064fc6..5344ea6fe835 100644 --- a/homeassistant/components/proxy/manifest.json +++ b/homeassistant/components/proxy/manifest.json @@ -2,9 +2,7 @@ "domain": "proxy", "name": "Proxy", "documentation": "https://www.home-assistant.io/integrations/proxy", - "requirements": [ - "pillow==6.2.1" - ], + "requirements": ["pillow==6.2.1"], "dependencies": [], "codeowners": [] } diff --git a/homeassistant/components/smartthings/manifest.json b/homeassistant/components/smartthings/manifest.json index 8b5bf65afa13..0ab71382fad5 100644 --- a/homeassistant/components/smartthings/manifest.json +++ b/homeassistant/components/smartthings/manifest.json @@ -3,14 +3,8 @@ "name": "Smartthings", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/smartthings", - "requirements": [ - "pysmartapp==0.3.2", - "pysmartthings==0.6.9" - ], - "dependencies": [ - "webhook" - ], - "codeowners": [ - "@andrewsayre" - ] + "requirements": ["pysmartapp==0.3.2", "pysmartthings==0.6.9"], + "dependencies": ["webhook"], + "after_dependencies": ["cloud"], + "codeowners": ["@andrewsayre"] } diff --git a/homeassistant/components/smartthings/smartapp.py b/homeassistant/components/smartthings/smartapp.py index 6acd29397ae6..9b67df214910 100644 --- a/homeassistant/components/smartthings/smartapp.py +++ b/homeassistant/components/smartthings/smartapp.py @@ -88,10 +88,7 @@ async def validate_installed_app(api, installed_app_id: str): def validate_webhook_requirements(hass: HomeAssistantType) -> bool: """Ensure HASS is setup properly to receive webhooks.""" - if ( - "cloud" in hass.config.components - and hass.components.cloud.async_active_subscription() - ): + if hass.components.cloud.async_active_subscription(): return True if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None: return True @@ -105,11 +102,7 @@ def get_webhook_url(hass: HomeAssistantType) -> str: Return the cloudhook if available, otherwise local webhook. """ cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] - if ( - "cloud" in hass.config.components - and hass.components.cloud.async_active_subscription() - and cloudhook_url is not None - ): + if hass.components.cloud.async_active_subscription() and cloudhook_url is not None: return cloudhook_url return webhook.async_generate_url(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID]) @@ -229,7 +222,6 @@ async def setup_smartapp_endpoint(hass: HomeAssistantType): cloudhook_url = config.get(CONF_CLOUDHOOK_URL) if ( cloudhook_url is None - and "cloud" in hass.config.components and hass.components.cloud.async_active_subscription() and not hass.config_entries.async_entries(DOMAIN) ): @@ -281,11 +273,7 @@ async def unload_smartapp_endpoint(hass: HomeAssistantType): return # Remove the cloudhook if it was created cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] - if ( - cloudhook_url - and "cloud" in hass.config.components - and hass.components.cloud.async_is_logged_in() - ): + if cloudhook_url and hass.components.cloud.async_is_logged_in(): await hass.components.cloud.async_delete_cloudhook( hass.data[DOMAIN][CONF_WEBHOOK_ID] ) diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 314938feeed4..42296a4935d6 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -288,8 +288,8 @@ async def async_process_deps_reqs( raise HomeAssistantError("Could not set up all dependencies.") if not hass.config.skip_pip and integration.requirements: - await requirements.async_process_requirements( - hass, integration.domain, integration.requirements + await requirements.async_get_integration_with_requirements( + hass, integration.domain ) processed.add(integration.domain) diff --git a/script/hassfest/dependencies.py b/script/hassfest/dependencies.py index e99339957154..e47deb76ad5f 100644 --- a/script/hassfest/dependencies.py +++ b/script/hassfest/dependencies.py @@ -43,15 +43,12 @@ def validate_dependencies(integration: Integration): if referenced: for domain in sorted(referenced): - print( - "Warning: {} references integration {} but it's not a " - "dependency".format(integration.domain, domain) + integration.add_error( + "dependencies", + "Using component {} but it's not in 'dependencies' or 'after_dependencies'".format( + domain + ), ) - # Not enforced yet. - # integration.add_error( - # 'dependencies', - # "Using component {} but it's not a dependency".format(domain) - # ) def validate(integrations: Dict[str, Integration], config): diff --git a/tests/components/smartthings/test_config_flow.py b/tests/components/smartthings/test_config_flow.py index 521f1c6a6a89..82a24f382871 100644 --- a/tests/components/smartthings/test_config_flow.py +++ b/tests/components/smartthings/test_config_flow.py @@ -7,7 +7,6 @@ from pysmartthings import APIResponseError from homeassistant import data_entry_flow from homeassistant.setup import async_setup_component -from homeassistant.components import cloud from homeassistant.components.smartthings import smartapp from homeassistant.components.smartthings.config_flow import SmartThingsFlowHandler from homeassistant.components.smartthings.const import ( @@ -18,7 +17,7 @@ from homeassistant.components.smartthings.const import ( DOMAIN, ) -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, mock_coro async def test_step_user(hass): @@ -211,9 +210,11 @@ async def test_cloudhook_app_created_then_show_wait_form( await smartapp.unload_smartapp_endpoint(hass) with patch.object( - cloud, "async_active_subscription", return_value=True + hass.components.cloud, "async_active_subscription", return_value=True ), patch.object( - cloud, "async_create_cloudhook", return_value="http://cloud.test" + hass.components.cloud, + "async_create_cloudhook", + return_value=mock_coro("http://cloud.test"), ) as mock_create_cloudhook: await smartapp.setup_smartapp_endpoint(hass)