Add command to get integration manifests (#34262)

* Add command to get integration manifests

* Add is_built_in value to manifest

* Update APIs
This commit is contained in:
Paulus Schoutsen 2020-04-15 13:36:16 -07:00 committed by GitHub
parent e41753556c
commit 9f1bffe3be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 32 deletions

View file

@ -1,4 +1,6 @@
"""Commands part of Websocket API."""
import asyncio
import voluptuous as vol
from homeassistant.auth.permissions.const import POLICY_READ
@ -8,6 +10,7 @@ from homeassistant.exceptions import HomeAssistantError, ServiceNotFound, Unauth
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.service import async_get_all_descriptions
from homeassistant.loader import IntegrationNotFound, async_get_integration
from . import const, decorators, messages
@ -25,6 +28,8 @@ def async_register_commands(hass, async_reg):
async_reg(hass, handle_get_config)
async_reg(hass, handle_ping)
async_reg(hass, handle_render_template)
async_reg(hass, handle_manifest_list)
async_reg(hass, handle_manifest_get)
def pong_message(iden):
@ -40,10 +45,7 @@ def pong_message(iden):
}
)
def handle_subscribe_events(hass, connection, msg):
"""Handle subscribe events command.
Async friendly.
"""
"""Handle subscribe events command."""
# Circular dep
# pylint: disable=import-outside-toplevel
from .permissions import SUBSCRIBE_WHITELIST
@ -90,10 +92,7 @@ def handle_subscribe_events(hass, connection, msg):
}
)
def handle_unsubscribe_events(hass, connection, msg):
"""Handle unsubscribe events command.
Async friendly.
"""
"""Handle unsubscribe events command."""
subscription = msg["subscription"]
if subscription in connection.subscriptions:
@ -117,10 +116,7 @@ def handle_unsubscribe_events(hass, connection, msg):
)
@decorators.async_response
async def handle_call_service(hass, connection, msg):
"""Handle call service command.
Async friendly.
"""
"""Handle call service command."""
blocking = True
if msg["domain"] == HASS_DOMAIN and msg["service"] in ["restart", "stop"]:
blocking = False
@ -164,10 +160,7 @@ async def handle_call_service(hass, connection, msg):
@callback
@decorators.websocket_command({vol.Required("type"): "get_states"})
def handle_get_states(hass, connection, msg):
"""Handle get states command.
Async friendly.
"""
"""Handle get states command."""
if connection.user.permissions.access_all_entities("read"):
states = hass.states.async_all()
else:
@ -184,10 +177,7 @@ def handle_get_states(hass, connection, msg):
@decorators.websocket_command({vol.Required("type"): "get_services"})
@decorators.async_response
async def handle_get_services(hass, connection, msg):
"""Handle get services command.
Async friendly.
"""
"""Handle get services command."""
descriptions = await async_get_all_descriptions(hass)
connection.send_message(messages.result_message(msg["id"], descriptions))
@ -195,20 +185,44 @@ async def handle_get_services(hass, connection, msg):
@callback
@decorators.websocket_command({vol.Required("type"): "get_config"})
def handle_get_config(hass, connection, msg):
"""Handle get config command.
Async friendly.
"""
"""Handle get config command."""
connection.send_message(messages.result_message(msg["id"], hass.config.as_dict()))
@decorators.websocket_command({vol.Required("type"): "manifest/list"})
@decorators.async_response
async def handle_manifest_list(hass, connection, msg):
"""Handle integrations command."""
integrations = await asyncio.gather(
*[
async_get_integration(hass, domain)
for domain in hass.config.components
# Filter out platforms.
if "." not in domain
]
)
connection.send_result(
msg["id"], [integration.manifest for integration in integrations]
)
@decorators.websocket_command(
{vol.Required("type"): "manifest/get", vol.Required("integration"): str}
)
@decorators.async_response
async def handle_manifest_get(hass, connection, msg):
"""Handle integrations command."""
try:
integration = await async_get_integration(hass, msg["integration"])
connection.send_result(msg["id"], integration.manifest)
except IntegrationNotFound:
connection.send_error(msg["id"], const.ERR_NOT_FOUND, "Integration not found")
@callback
@decorators.websocket_command({vol.Required("type"): "ping"})
def handle_ping(hass, connection, msg):
"""Handle ping command.
Async friendly.
"""
"""Handle ping command."""
connection.send_message(pong_message(msg["id"]))
@ -222,10 +236,7 @@ def handle_ping(hass, connection, msg):
}
)
def handle_render_template(hass, connection, msg):
"""Handle render_template command.
Async friendly.
"""
"""Handle render_template command."""
template = msg["template"]
template.hass = hass

View file

@ -205,6 +205,7 @@ class Integration:
self.pkg_path = pkg_path
self.file_path = file_path
self.manifest = manifest
manifest["is_built_in"] = self.is_built_in
_LOGGER.info("Loaded %s from %s", self.domain, pkg_path)
@property

View file

@ -10,6 +10,7 @@ from homeassistant.components.websocket_api.auth import (
from homeassistant.components.websocket_api.const import URL
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import async_get_integration
from homeassistant.setup import async_setup_component
from tests.common import async_mock_service
@ -467,3 +468,46 @@ async def test_render_template_returns_with_match_all(
assert msg["id"] == 5
assert msg["type"] == const.TYPE_RESULT
assert msg["success"]
async def test_manifest_list(hass, websocket_client):
"""Test loading manifests."""
http = await async_get_integration(hass, "http")
websocket_api = await async_get_integration(hass, "websocket_api")
await websocket_client.send_json({"id": 5, "type": "manifest/list"})
msg = await websocket_client.receive_json()
assert msg["id"] == 5
assert msg["type"] == const.TYPE_RESULT
assert msg["success"]
assert sorted(msg["result"], key=lambda manifest: manifest["domain"]) == [
http.manifest,
websocket_api.manifest,
]
async def test_manifest_get(hass, websocket_client):
"""Test getting a manifest."""
hue = await async_get_integration(hass, "hue")
await websocket_client.send_json(
{"id": 6, "type": "manifest/get", "integration": "hue"}
)
msg = await websocket_client.receive_json()
assert msg["id"] == 6
assert msg["type"] == const.TYPE_RESULT
assert msg["success"]
assert msg["result"] == hue.manifest
# Non existing
await websocket_client.send_json(
{"id": 7, "type": "manifest/get", "integration": "non_existing"}
)
msg = await websocket_client.receive_json()
assert msg["id"] == 7
assert msg["type"] == const.TYPE_RESULT
assert not msg["success"]
assert msg["error"]["code"] == "not_found"