forked from home-assistant/core
Exclude triggers without description from WS command response
This commit is contained in:
@@ -536,7 +536,13 @@ async def _async_get_all_trigger_descriptions_json(hass: HomeAssistant) -> bytes
|
||||
# If the descriptions are the same, return the cached JSON payload
|
||||
if cached_descriptions is descriptions:
|
||||
return cast(bytes, cached_json_payload)
|
||||
json_payload = json_bytes(descriptions)
|
||||
json_payload = json_bytes(
|
||||
{
|
||||
trigger: description
|
||||
for trigger, description in descriptions.items()
|
||||
if description is not None
|
||||
}
|
||||
)
|
||||
hass.data[ALL_TRIGGER_DESCRIPTIONS_JSON_CACHE] = (descriptions, json_payload)
|
||||
return json_payload
|
||||
|
||||
@@ -553,8 +559,10 @@ async def handle_subscribe_trigger_platforms(
|
||||
descriptions = await async_get_all_trigger_descriptions(hass)
|
||||
new_trigger_descriptions = {}
|
||||
for trigger in new_triggers:
|
||||
if trigger in descriptions:
|
||||
new_trigger_descriptions[trigger] = descriptions[trigger]
|
||||
if (description := descriptions[trigger]) is not None:
|
||||
new_trigger_descriptions[trigger] = description
|
||||
if not new_trigger_descriptions:
|
||||
return
|
||||
connection.send_event(msg["id"], new_trigger_descriptions)
|
||||
|
||||
connection.subscriptions[msg["id"]] = async_subscribe_trigger_platform_events(
|
||||
|
@@ -60,7 +60,7 @@ DATA_PLUGGABLE_ACTIONS: HassKey[defaultdict[tuple, PluggableActionsEntry]] = Has
|
||||
"pluggable_actions"
|
||||
)
|
||||
|
||||
TRIGGER_DESCRIPTION_CACHE: HassKey[dict[str, dict[str, Any]]] = HassKey(
|
||||
TRIGGER_DESCRIPTION_CACHE: HassKey[dict[str, dict[str, Any] | None]] = HassKey(
|
||||
"trigger_description_cache"
|
||||
)
|
||||
TRIGGER_PLATFORM_SUBSCRIPTIONS: HassKey[
|
||||
@@ -550,7 +550,7 @@ def _load_triggers_files(
|
||||
|
||||
async def async_get_all_descriptions(
|
||||
hass: HomeAssistant,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
) -> dict[str, dict[str, Any] | None]:
|
||||
"""Return descriptions (i.e. user documentation) for all triggers."""
|
||||
descriptions_cache = hass.data[TRIGGER_DESCRIPTION_CACHE]
|
||||
|
||||
@@ -599,12 +599,17 @@ async def async_get_all_descriptions(
|
||||
for missing_trigger in missing_triggers:
|
||||
domain = triggers[missing_trigger]
|
||||
|
||||
# Cache missing descriptions
|
||||
domain_yaml = new_triggers_descriptions.get(domain) or {}
|
||||
|
||||
yaml_description = (
|
||||
domain_yaml.get(missing_trigger) or {} # type: ignore[union-attr]
|
||||
)
|
||||
if (
|
||||
yaml_description := new_triggers_descriptions.get(domain, {}).get( # type: ignore[union-attr]
|
||||
missing_trigger
|
||||
)
|
||||
) is None:
|
||||
_LOGGER.debug(
|
||||
"No trigger descriptions found for trigger %s, skipping",
|
||||
missing_trigger,
|
||||
)
|
||||
new_descriptions_cache[missing_trigger] = None
|
||||
continue
|
||||
|
||||
description = {"fields": yaml_description.get("fields", {})}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from copy import deepcopy
|
||||
import io
|
||||
import logging
|
||||
from typing import Any
|
||||
from unittest.mock import ANY, AsyncMock, Mock, patch
|
||||
@@ -28,9 +29,10 @@ from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.event import async_track_state_change_event
|
||||
from homeassistant.loader import async_get_integration
|
||||
from homeassistant.loader import Integration, async_get_integration
|
||||
from homeassistant.setup import async_set_domains_to_be_loaded, async_setup_component
|
||||
from homeassistant.util.json import json_loads
|
||||
from homeassistant.util.yaml.loader import parse_yaml
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
@@ -680,10 +682,34 @@ async def test_get_services(
|
||||
assert msg["result"].keys() == hass.services.async_services().keys()
|
||||
|
||||
|
||||
@patch("annotatedyaml.loader.load_yaml")
|
||||
@patch.object(Integration, "has_triggers", return_value=True)
|
||||
async def test_subscribe_triggers(
|
||||
hass: HomeAssistant, websocket_client: MockHAClientWebSocket
|
||||
mock_has_triggers: Mock,
|
||||
mock_load_yaml: Mock,
|
||||
hass: HomeAssistant,
|
||||
websocket_client: MockHAClientWebSocket,
|
||||
) -> None:
|
||||
"""Test get_triggers command."""
|
||||
sun_service_descriptions = """
|
||||
sun: {}
|
||||
"""
|
||||
tag_service_descriptions = """
|
||||
tag: {}
|
||||
"""
|
||||
|
||||
def _load_yaml(fname, secrets=None):
|
||||
if fname.endswith("sun/triggers.yaml"):
|
||||
service_descriptions = sun_service_descriptions
|
||||
elif fname.endswith("tag/triggers.yaml"):
|
||||
service_descriptions = tag_service_descriptions
|
||||
else:
|
||||
raise FileNotFoundError
|
||||
with io.StringIO(service_descriptions) as file:
|
||||
return parse_yaml(file)
|
||||
|
||||
mock_load_yaml.side_effect = _load_yaml
|
||||
|
||||
assert await async_setup_component(hass, "sun", {})
|
||||
assert await async_setup_component(hass, "system_health", {})
|
||||
await hass.async_block_till_done()
|
||||
@@ -700,8 +726,10 @@ async def test_subscribe_triggers(
|
||||
|
||||
old_cache = hass.data[ALL_TRIGGER_DESCRIPTIONS_JSON_CACHE]
|
||||
|
||||
# Test we receive an event when a new platform is loaded
|
||||
# Test we receive an event when a new platform is loaded, if it has descriptions
|
||||
assert await async_setup_component(hass, "calendar", {})
|
||||
assert await async_setup_component(hass, "tag", {})
|
||||
await hass.async_block_till_done()
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg == {
|
||||
"event": {"tag": {"fields": {}}},
|
||||
|
@@ -478,8 +478,6 @@ async def test_async_get_all_descriptions(
|
||||
hass: HomeAssistant, sun_service_descriptions: str
|
||||
) -> None:
|
||||
"""Test async_get_all_descriptions."""
|
||||
await trigger.async_setup(hass) # Move to hass fixture
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN_SUN, {})
|
||||
assert await async_setup_component(hass, DOMAIN_SYSTEM_HEALTH, {})
|
||||
await hass.async_block_till_done()
|
||||
@@ -546,8 +544,6 @@ async def test_async_get_all_descriptions_with_yaml_error(
|
||||
expected_message: str,
|
||||
) -> None:
|
||||
"""Test async_get_all_descriptions."""
|
||||
await trigger.async_setup(hass) # Move to hass fixture
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN_SUN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -563,7 +559,7 @@ async def test_async_get_all_descriptions_with_yaml_error(
|
||||
):
|
||||
descriptions = await trigger.async_get_all_descriptions(hass)
|
||||
|
||||
assert descriptions == {DOMAIN_SUN: {"fields": {}}}
|
||||
assert descriptions == {DOMAIN_SUN: None}
|
||||
|
||||
assert expected_message in caplog.text
|
||||
|
||||
@@ -578,8 +574,6 @@ async def test_async_get_all_descriptions_with_bad_description(
|
||||
fields: not_a_dict
|
||||
"""
|
||||
|
||||
await trigger.async_setup(hass) # Move to hass fixture
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN_SUN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -596,7 +590,7 @@ async def test_async_get_all_descriptions_with_bad_description(
|
||||
):
|
||||
descriptions = await trigger.async_get_all_descriptions(hass)
|
||||
|
||||
assert descriptions == {DOMAIN_SUN: {"fields": {}}}
|
||||
assert descriptions == {DOMAIN_SUN: None}
|
||||
|
||||
assert (
|
||||
"Unable to parse triggers.yaml for the sun integration: "
|
||||
|
Reference in New Issue
Block a user