Install requirements of after_dependencies when loading integrations (#29491)

* Install requirements of after_dependencies when loading integrations

* Fix smartthings test
This commit is contained in:
Paulus Schoutsen 2019-12-05 00:28:56 -08:00 committed by Pascal Vizeli
parent 957e5018f4
commit e99184bf68
19 changed files with 57 additions and 98 deletions

View File

@ -3,10 +3,7 @@
"name": "Auth", "name": "Auth",
"documentation": "https://www.home-assistant.io/integrations/auth", "documentation": "https://www.home-assistant.io/integrations/auth",
"requirements": [], "requirements": [],
"dependencies": [ "dependencies": ["http"],
"http" "after_dependencies": ["onboarding"],
], "codeowners": ["@home-assistant/core"]
"codeowners": [
"@home-assistant/core"
]
} }

View File

@ -3,11 +3,6 @@
"name": "Camera", "name": "Camera",
"documentation": "https://www.home-assistant.io/integrations/camera", "documentation": "https://www.home-assistant.io/integrations/camera",
"requirements": [], "requirements": [],
"dependencies": [ "dependencies": ["http"],
"http"
],
"after_dependencies": [
"stream"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,6 +5,7 @@
"documentation": "https://www.home-assistant.io/integrations/cast", "documentation": "https://www.home-assistant.io/integrations/cast",
"requirements": ["pychromecast==4.0.1"], "requirements": ["pychromecast==4.0.1"],
"dependencies": [], "dependencies": [],
"after_dependencies": ["cloud"],
"zeroconf": ["_googlecast._tcp.local."], "zeroconf": ["_googlecast._tcp.local."],
"codeowners": [] "codeowners": []
} }

View File

@ -4,5 +4,6 @@
"documentation": "https://www.home-assistant.io/integrations/google_assistant", "documentation": "https://www.home-assistant.io/integrations/google_assistant",
"requirements": [], "requirements": [],
"dependencies": ["http"], "dependencies": ["http"],
"after_dependencies": ["camera"],
"codeowners": ["@home-assistant/cloud"] "codeowners": ["@home-assistant/cloud"]
} }

View File

@ -37,9 +37,7 @@ class RegistrationsView(HomeAssistantView):
webhook_id = generate_secret() webhook_id = generate_secret()
cloud_loaded = "cloud" in hass.config.components if hass.components.cloud.async_active_subscription():
if cloud_loaded and hass.components.cloud.async_active_subscription():
data[ data[
CONF_CLOUDHOOK_URL CONF_CLOUDHOOK_URL
] = await hass.components.cloud.async_create_cloudhook(webhook_id) ] = await hass.components.cloud.async_create_cloudhook(webhook_id)
@ -59,11 +57,10 @@ class RegistrationsView(HomeAssistantView):
) )
remote_ui_url = None remote_ui_url = None
if cloud_loaded: try:
try: remote_ui_url = hass.components.cloud.async_remote_ui_url()
remote_ui_url = hass.components.cloud.async_remote_ui_url() except hass.components.cloud.CloudNotAvailable:
except hass.components.cloud.CloudNotAvailable: pass
pass
return self.json( return self.json(
{ {

View File

@ -5,5 +5,6 @@
"documentation": "https://www.home-assistant.io/integrations/mobile_app", "documentation": "https://www.home-assistant.io/integrations/mobile_app",
"requirements": ["PyNaCl==1.3.0"], "requirements": ["PyNaCl==1.3.0"],
"dependencies": ["http", "webhook"], "dependencies": ["http", "webhook"],
"after_dependencies": ["cloud"],
"codeowners": ["@robbiet480"] "codeowners": ["@robbiet480"]
} }

View File

@ -309,10 +309,9 @@ async def handle_webhook(
if CONF_CLOUDHOOK_URL in registration: if CONF_CLOUDHOOK_URL in registration:
resp[CONF_CLOUDHOOK_URL] = registration[CONF_CLOUDHOOK_URL] resp[CONF_CLOUDHOOK_URL] = registration[CONF_CLOUDHOOK_URL]
if "cloud" in hass.config.components: try:
try: resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url()
resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url() except hass.components.cloud.CloudNotAvailable:
except hass.components.cloud.CloudNotAvailable: pass
pass
return webhook_response(resp, registration=registration, headers=headers) return webhook_response(resp, registration=registration, headers=headers)

View File

@ -115,7 +115,7 @@ async def websocket_delete_registration(
except HomeAssistantError: except HomeAssistantError:
return error_message(msg["id"], "internal_error", "Error deleting registration") 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) await hass.components.cloud.async_delete_cloudhook(webhook_id)
connection.send_message(result_message(msg["id"], "ok")) connection.send_message(result_message(msg["id"], "ok"))

View File

@ -3,11 +3,6 @@
"name": "Onboarding", "name": "Onboarding",
"documentation": "https://www.home-assistant.io/integrations/onboarding", "documentation": "https://www.home-assistant.io/integrations/onboarding",
"requirements": [], "requirements": [],
"dependencies": [ "dependencies": ["auth", "http", "person"],
"auth", "codeowners": ["@home-assistant/core"]
"http"
],
"codeowners": [
"@home-assistant/core"
]
} }

View File

@ -118,7 +118,7 @@ async def async_unload_entry(hass, entry):
async def async_remove_entry(hass, entry): async def async_remove_entry(hass, entry):
"""Remove an OwnTracks config 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 return
await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID]) await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID])

View File

@ -66,10 +66,7 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def _get_webhook_id(self): async def _get_webhook_id(self):
"""Generate webhook ID.""" """Generate webhook ID."""
webhook_id = self.hass.components.webhook.async_generate_id() webhook_id = self.hass.components.webhook.async_generate_id()
if ( if self.hass.components.cloud.async_active_subscription():
"cloud" in self.hass.config.components
and self.hass.components.cloud.async_active_subscription()
):
webhook_url = await self.hass.components.cloud.async_create_cloudhook( webhook_url = await self.hass.components.cloud.async_create_cloudhook(
webhook_id webhook_id
) )

View File

@ -3,14 +3,8 @@
"name": "Owntracks", "name": "Owntracks",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/owntracks", "documentation": "https://www.home-assistant.io/integrations/owntracks",
"requirements": [ "requirements": ["PyNaCl==1.3.0"],
"PyNaCl==1.3.0" "dependencies": ["webhook"],
], "after_dependencies": ["mqtt", "cloud"],
"dependencies": [
"webhook"
],
"after_dependencies": [
"mqtt"
],
"codeowners": [] "codeowners": []
} }

View File

@ -7,7 +7,13 @@ import logging
from PIL import Image from PIL import Image
import voluptuous as vol 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.const import CONF_ENTITY_ID, CONF_MODE, CONF_NAME
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
@ -227,7 +233,7 @@ class ProxyCamera(Camera):
return self._last_image return self._last_image
self._last_image_time = now 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: if not image:
_LOGGER.error("Error getting original camera image") _LOGGER.error("Error getting original camera image")
return self._last_image return self._last_image
@ -247,12 +253,12 @@ class ProxyCamera(Camera):
async def handle_async_mjpeg_stream(self, request): async def handle_async_mjpeg_stream(self, request):
"""Generate an HTTP MJPEG stream from camera images.""" """Generate an HTTP MJPEG stream from camera images."""
if not self._stream_opts: if not self._stream_opts:
return await self.hass.components.camera.async_get_mjpeg_stream( return await async_get_mjpeg_stream(
request, self._proxied_camera self.hass, request, self._proxied_camera
) )
return await self.hass.components.camera.async_get_still_stream( return await async_get_still_stream(
request, self._async_stream_image, self.content_type, self.frame_interval request, self._async_stream_image, self.content_type, self.frame_interval,
) )
@property @property
@ -263,9 +269,7 @@ class ProxyCamera(Camera):
async def _async_stream_image(self): async def _async_stream_image(self):
"""Return a still image response from the camera.""" """Return a still image response from the camera."""
try: try:
image = await self.hass.components.camera.async_get_image( image = await async_get_image(self.hass, self._proxied_camera)
self._proxied_camera
)
if not image: if not image:
return None return None
except HomeAssistantError: except HomeAssistantError:

View File

@ -2,9 +2,7 @@
"domain": "proxy", "domain": "proxy",
"name": "Proxy", "name": "Proxy",
"documentation": "https://www.home-assistant.io/integrations/proxy", "documentation": "https://www.home-assistant.io/integrations/proxy",
"requirements": [ "requirements": ["pillow==6.2.1"],
"pillow==6.2.1"
],
"dependencies": [], "dependencies": [],
"codeowners": [] "codeowners": []
} }

View File

@ -3,14 +3,8 @@
"name": "Smartthings", "name": "Smartthings",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/smartthings", "documentation": "https://www.home-assistant.io/integrations/smartthings",
"requirements": [ "requirements": ["pysmartapp==0.3.2", "pysmartthings==0.6.9"],
"pysmartapp==0.3.2", "dependencies": ["webhook"],
"pysmartthings==0.6.9" "after_dependencies": ["cloud"],
], "codeowners": ["@andrewsayre"]
"dependencies": [
"webhook"
],
"codeowners": [
"@andrewsayre"
]
} }

View File

@ -88,10 +88,7 @@ async def validate_installed_app(api, installed_app_id: str):
def validate_webhook_requirements(hass: HomeAssistantType) -> bool: def validate_webhook_requirements(hass: HomeAssistantType) -> bool:
"""Ensure HASS is setup properly to receive webhooks.""" """Ensure HASS is setup properly to receive webhooks."""
if ( if hass.components.cloud.async_active_subscription():
"cloud" in hass.config.components
and hass.components.cloud.async_active_subscription()
):
return True return True
if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None: if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None:
return True return True
@ -105,11 +102,7 @@ def get_webhook_url(hass: HomeAssistantType) -> str:
Return the cloudhook if available, otherwise local webhook. Return the cloudhook if available, otherwise local webhook.
""" """
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
if ( if hass.components.cloud.async_active_subscription() and cloudhook_url is not None:
"cloud" in hass.config.components
and hass.components.cloud.async_active_subscription()
and cloudhook_url is not None
):
return cloudhook_url return cloudhook_url
return webhook.async_generate_url(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID]) 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) cloudhook_url = config.get(CONF_CLOUDHOOK_URL)
if ( if (
cloudhook_url is None cloudhook_url is None
and "cloud" in hass.config.components
and hass.components.cloud.async_active_subscription() and hass.components.cloud.async_active_subscription()
and not hass.config_entries.async_entries(DOMAIN) and not hass.config_entries.async_entries(DOMAIN)
): ):
@ -281,11 +273,7 @@ async def unload_smartapp_endpoint(hass: HomeAssistantType):
return return
# Remove the cloudhook if it was created # Remove the cloudhook if it was created
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
if ( if cloudhook_url and hass.components.cloud.async_is_logged_in():
cloudhook_url
and "cloud" in hass.config.components
and hass.components.cloud.async_is_logged_in()
):
await hass.components.cloud.async_delete_cloudhook( await hass.components.cloud.async_delete_cloudhook(
hass.data[DOMAIN][CONF_WEBHOOK_ID] hass.data[DOMAIN][CONF_WEBHOOK_ID]
) )

View File

@ -288,8 +288,8 @@ async def async_process_deps_reqs(
raise HomeAssistantError("Could not set up all dependencies.") raise HomeAssistantError("Could not set up all dependencies.")
if not hass.config.skip_pip and integration.requirements: if not hass.config.skip_pip and integration.requirements:
await requirements.async_process_requirements( await requirements.async_get_integration_with_requirements(
hass, integration.domain, integration.requirements hass, integration.domain
) )
processed.add(integration.domain) processed.add(integration.domain)

View File

@ -43,15 +43,12 @@ def validate_dependencies(integration: Integration):
if referenced: if referenced:
for domain in sorted(referenced): for domain in sorted(referenced):
print( integration.add_error(
"Warning: {} references integration {} but it's not a " "dependencies",
"dependency".format(integration.domain, domain) "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): def validate(integrations: Dict[str, Integration], config):

View File

@ -7,7 +7,6 @@ from pysmartthings import APIResponseError
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.components import cloud
from homeassistant.components.smartthings import smartapp from homeassistant.components.smartthings import smartapp
from homeassistant.components.smartthings.config_flow import SmartThingsFlowHandler from homeassistant.components.smartthings.config_flow import SmartThingsFlowHandler
from homeassistant.components.smartthings.const import ( from homeassistant.components.smartthings.const import (
@ -18,7 +17,7 @@ from homeassistant.components.smartthings.const import (
DOMAIN, DOMAIN,
) )
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, mock_coro
async def test_step_user(hass): 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) await smartapp.unload_smartapp_endpoint(hass)
with patch.object( with patch.object(
cloud, "async_active_subscription", return_value=True hass.components.cloud, "async_active_subscription", return_value=True
), patch.object( ), 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: ) as mock_create_cloudhook:
await smartapp.setup_smartapp_endpoint(hass) await smartapp.setup_smartapp_endpoint(hass)