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:
parent
e41753556c
commit
9f1bffe3be
3 changed files with 88 additions and 32 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue