Find referenced labels in automations & scripts (#113812)
parent
ea443af557
commit
670bd97777
|
@ -245,6 +245,18 @@ def floors_in_automation(hass: HomeAssistant, entity_id: str) -> list[str]:
|
|||
return _x_in_automation(hass, entity_id, "referenced_floors")
|
||||
|
||||
|
||||
@callback
|
||||
def automations_with_label(hass: HomeAssistant, label_id: str) -> list[str]:
|
||||
"""Return all automations that reference the label."""
|
||||
return _automations_with_x(hass, label_id, "referenced_labels")
|
||||
|
||||
|
||||
@callback
|
||||
def labels_in_automation(hass: HomeAssistant, entity_id: str) -> list[str]:
|
||||
"""Return all labels in an automation."""
|
||||
return _x_in_automation(hass, entity_id, "referenced_labels")
|
||||
|
||||
|
||||
@callback
|
||||
def automations_with_blueprint(hass: HomeAssistant, blueprint_path: str) -> list[str]:
|
||||
"""Return all automations that reference the blueprint."""
|
||||
|
@ -353,6 +365,11 @@ class BaseAutomationEntity(ToggleEntity, ABC):
|
|||
return {CONF_ID: self.unique_id}
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
@abstractmethod
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
|
||||
@cached_property
|
||||
@abstractmethod
|
||||
def referenced_floors(self) -> set[str]:
|
||||
|
@ -413,6 +430,11 @@ class UnavailableAutomationEntity(BaseAutomationEntity):
|
|||
"""Return the name of the entity."""
|
||||
return self._name
|
||||
|
||||
@cached_property
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
return set()
|
||||
|
||||
@cached_property
|
||||
def referenced_floors(self) -> set[str]:
|
||||
"""Return a set of referenced floors."""
|
||||
|
@ -505,6 +527,11 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity):
|
|||
"""Return True if entity is on."""
|
||||
return self._async_detach_triggers is not None or self._is_enabled
|
||||
|
||||
@property
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
return self.action_script.referenced_labels
|
||||
|
||||
@property
|
||||
def referenced_floors(self) -> set[str]:
|
||||
"""Return a set of referenced floors."""
|
||||
|
|
|
@ -170,6 +170,18 @@ def floors_in_script(hass: HomeAssistant, entity_id: str) -> list[str]:
|
|||
return _x_in_script(hass, entity_id, "referenced_floors")
|
||||
|
||||
|
||||
@callback
|
||||
def scripts_with_label(hass: HomeAssistant, label_id: str) -> list[str]:
|
||||
"""Return all scripts that reference the label."""
|
||||
return _scripts_with_x(hass, label_id, "referenced_labels")
|
||||
|
||||
|
||||
@callback
|
||||
def labels_in_script(hass: HomeAssistant, entity_id: str) -> list[str]:
|
||||
"""Return all labels in a script."""
|
||||
return _x_in_script(hass, entity_id, "referenced_labels")
|
||||
|
||||
|
||||
@callback
|
||||
def scripts_with_blueprint(hass: HomeAssistant, blueprint_path: str) -> list[str]:
|
||||
"""Return all scripts that reference the blueprint."""
|
||||
|
@ -401,6 +413,11 @@ class BaseScriptEntity(ToggleEntity, ABC):
|
|||
|
||||
raw_config: ConfigType | None
|
||||
|
||||
@cached_property
|
||||
@abstractmethod
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
|
||||
@cached_property
|
||||
@abstractmethod
|
||||
def referenced_floors(self) -> set[str]:
|
||||
|
@ -451,6 +468,11 @@ class UnavailableScriptEntity(BaseScriptEntity):
|
|||
"""Return the name of the entity."""
|
||||
return self._name
|
||||
|
||||
@cached_property
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
return set()
|
||||
|
||||
@cached_property
|
||||
def referenced_floors(self) -> set[str]:
|
||||
"""Return a set of referenced floors."""
|
||||
|
@ -539,6 +561,11 @@ class ScriptEntity(BaseScriptEntity, RestoreEntity):
|
|||
"""Return true if script is on."""
|
||||
return self.script.is_running
|
||||
|
||||
@cached_property
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
return self.script.referenced_labels
|
||||
|
||||
@cached_property
|
||||
def referenced_floors(self) -> set[str]:
|
||||
"""Return a set of referenced floors."""
|
||||
|
|
|
@ -27,6 +27,7 @@ from homeassistant.const import (
|
|||
ATTR_DEVICE_ID,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_FLOOR_ID,
|
||||
ATTR_LABEL_ID,
|
||||
CONF_ALIAS,
|
||||
CONF_CHOOSE,
|
||||
CONF_CONDITION,
|
||||
|
@ -1381,6 +1382,13 @@ class Script:
|
|||
"""Return true if the current mode support max."""
|
||||
return self.script_mode in (SCRIPT_MODE_PARALLEL, SCRIPT_MODE_QUEUED)
|
||||
|
||||
@cached_property
|
||||
def referenced_labels(self) -> set[str]:
|
||||
"""Return a set of referenced labels."""
|
||||
referenced_labels: set[str] = set()
|
||||
Script._find_referenced_target(ATTR_LABEL_ID, referenced_labels, self.sequence)
|
||||
return referenced_labels
|
||||
|
||||
@cached_property
|
||||
def referenced_floors(self) -> set[str]:
|
||||
"""Return a set of referenced fooors."""
|
||||
|
@ -1397,7 +1405,7 @@ class Script:
|
|||
|
||||
@staticmethod
|
||||
def _find_referenced_target(
|
||||
target: Literal["area_id", "floor_id"],
|
||||
target: Literal["area_id", "floor_id", "label_id"],
|
||||
referenced: set[str],
|
||||
sequence: Sequence[dict[str, Any]],
|
||||
) -> None:
|
||||
|
|
|
@ -1563,6 +1563,8 @@ async def test_extraction_functions_not_setup(hass: HomeAssistant) -> None:
|
|||
assert automation.entities_in_automation(hass, "automation.test") == []
|
||||
assert automation.automations_with_floor(hass, "floor-in-both") == []
|
||||
assert automation.floors_in_automation(hass, "automation.test") == []
|
||||
assert automation.automations_with_label(hass, "label-in-both") == []
|
||||
assert automation.labels_in_automation(hass, "automation.test") == []
|
||||
|
||||
|
||||
async def test_extraction_functions_unknown_automation(hass: HomeAssistant) -> None:
|
||||
|
@ -1573,6 +1575,7 @@ async def test_extraction_functions_unknown_automation(hass: HomeAssistant) -> N
|
|||
assert automation.devices_in_automation(hass, "automation.unknown") == []
|
||||
assert automation.entities_in_automation(hass, "automation.unknown") == []
|
||||
assert automation.floors_in_automation(hass, "automation.unknown") == []
|
||||
assert automation.labels_in_automation(hass, "automation.unknown") == []
|
||||
|
||||
|
||||
async def test_extraction_functions_unavailable_automation(hass: HomeAssistant) -> None:
|
||||
|
@ -1600,6 +1603,8 @@ async def test_extraction_functions_unavailable_automation(hass: HomeAssistant)
|
|||
assert automation.entities_in_automation(hass, entity_id) == []
|
||||
assert automation.automations_with_floor(hass, "floor-in-both") == []
|
||||
assert automation.floors_in_automation(hass, entity_id) == []
|
||||
assert automation.automations_with_label(hass, "label-in-both") == []
|
||||
assert automation.labels_in_automation(hass, entity_id) == []
|
||||
|
||||
|
||||
async def test_extraction_functions(
|
||||
|
@ -1703,6 +1708,10 @@ async def test_extraction_functions(
|
|||
"service": "test.test",
|
||||
"target": {"floor_id": "floor-in-both"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-both"},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1830,6 +1839,14 @@ async def test_extraction_functions(
|
|||
"service": "test.test",
|
||||
"target": {"floor_id": "floor-in-last"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-both"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-last"},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
@ -1880,6 +1897,14 @@ async def test_extraction_functions(
|
|||
"floor-in-both",
|
||||
"floor-in-last",
|
||||
}
|
||||
assert set(automation.automations_with_label(hass, "label-in-both")) == {
|
||||
"automation.test1",
|
||||
"automation.test3",
|
||||
}
|
||||
assert set(automation.labels_in_automation(hass, "automation.test3")) == {
|
||||
"label-in-both",
|
||||
"label-in-last",
|
||||
}
|
||||
assert automation.blueprint_in_automation(hass, "automation.test3") is None
|
||||
|
||||
|
||||
|
|
|
@ -686,11 +686,14 @@ async def test_extraction_functions_not_setup(hass: HomeAssistant) -> None:
|
|||
assert script.entities_in_script(hass, "script.test") == []
|
||||
assert script.scripts_with_floor(hass, "floor-in-both") == []
|
||||
assert script.floors_in_script(hass, "script.test") == []
|
||||
assert script.scripts_with_label(hass, "label-in-both") == []
|
||||
assert script.labels_in_script(hass, "script.test") == []
|
||||
|
||||
|
||||
async def test_extraction_functions_unknown_script(hass: HomeAssistant) -> None:
|
||||
"""Test extraction functions for an unknown script."""
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
assert script.labels_in_script(hass, "script.unknown") == []
|
||||
assert script.floors_in_script(hass, "script.unknown") == []
|
||||
assert script.areas_in_script(hass, "script.unknown") == []
|
||||
assert script.blueprint_in_script(hass, "script.unknown") is None
|
||||
|
@ -717,6 +720,8 @@ async def test_extraction_functions_unavailable_script(hass: HomeAssistant) -> N
|
|||
assert script.entities_in_script(hass, entity_id) == []
|
||||
assert script.scripts_with_floor(hass, "floor-in-both") == []
|
||||
assert script.floors_in_script(hass, entity_id) == []
|
||||
assert script.scripts_with_label(hass, "label-in-both") == []
|
||||
assert script.labels_in_script(hass, entity_id) == []
|
||||
|
||||
|
||||
async def test_extraction_functions(
|
||||
|
@ -765,6 +770,10 @@ async def test_extraction_functions(
|
|||
"service": "test.test",
|
||||
"target": {"floor_id": "floor-in-both"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-both"},
|
||||
},
|
||||
]
|
||||
},
|
||||
"test2": {
|
||||
|
@ -821,6 +830,14 @@ async def test_extraction_functions(
|
|||
"service": "test.test",
|
||||
"target": {"floor_id": "floor-in-last"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-both"},
|
||||
},
|
||||
{
|
||||
"service": "test.test",
|
||||
"target": {"label_id": "label-in-last"},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
@ -860,6 +877,14 @@ async def test_extraction_functions(
|
|||
"floor-in-both",
|
||||
"floor-in-last",
|
||||
}
|
||||
assert set(script.scripts_with_label(hass, "label-in-both")) == {
|
||||
"script.test1",
|
||||
"script.test3",
|
||||
}
|
||||
assert set(script.labels_in_script(hass, "script.test3")) == {
|
||||
"label-in-both",
|
||||
"label-in-last",
|
||||
}
|
||||
assert script.blueprint_in_script(hass, "script.test3") is None
|
||||
|
||||
|
||||
|
|
|
@ -3695,6 +3695,110 @@ async def test_propagate_error_service_exception(hass: HomeAssistant) -> None:
|
|||
assert_action_trace(expected_trace, expected_script_execution="error")
|
||||
|
||||
|
||||
async def test_referenced_labels(hass: HomeAssistant) -> None:
|
||||
"""Test referenced labels."""
|
||||
script_obj = script.Script(
|
||||
hass,
|
||||
cv.SCRIPT_SCHEMA(
|
||||
[
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_service_not_list"},
|
||||
},
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {
|
||||
"label_id": ["label_service_list_1", "label_service_list_2"]
|
||||
},
|
||||
},
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "{{ 'label_service_template' }}"},
|
||||
},
|
||||
{
|
||||
"service": "test.script",
|
||||
"target": {"label_id": "label_in_target"},
|
||||
},
|
||||
{
|
||||
"service": "test.script",
|
||||
"data_template": {"label_id": "label_in_data_template"},
|
||||
},
|
||||
{"service": "test.script", "data": {"without": "label_id"}},
|
||||
{
|
||||
"choose": [
|
||||
{
|
||||
"conditions": "{{ true == false }}",
|
||||
"sequence": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_choice_1_seq"},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"conditions": "{{ true == false }}",
|
||||
"sequence": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_choice_2_seq"},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
"default": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_default_seq"},
|
||||
}
|
||||
],
|
||||
},
|
||||
{"event": "test_event"},
|
||||
{"delay": "{{ delay_period }}"},
|
||||
{
|
||||
"if": [],
|
||||
"then": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_if_then"},
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_if_else"},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"parallel": [
|
||||
{
|
||||
"service": "test.script",
|
||||
"data": {"label_id": "label_parallel"},
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
),
|
||||
"Test Name",
|
||||
"test_domain",
|
||||
)
|
||||
assert script_obj.referenced_labels == {
|
||||
"label_choice_1_seq",
|
||||
"label_choice_2_seq",
|
||||
"label_default_seq",
|
||||
"label_in_data_template",
|
||||
"label_in_target",
|
||||
"label_service_list_1",
|
||||
"label_service_list_2",
|
||||
"label_service_not_list",
|
||||
"label_if_then",
|
||||
"label_if_else",
|
||||
"label_parallel",
|
||||
}
|
||||
# Test we cache results.
|
||||
assert script_obj.referenced_labels is script_obj.referenced_labels
|
||||
|
||||
|
||||
async def test_referenced_floors(hass: HomeAssistant) -> None:
|
||||
"""Test referenced floors."""
|
||||
script_obj = script.Script(
|
||||
|
|
Loading…
Reference in New Issue