Skip to content

Commit 21d914c

Browse files
authored
Disable experimental conditions according to labs flag setting (home-assistant#157345)
1 parent ec77add commit 21d914c

File tree

4 files changed

+228
-32
lines changed

4 files changed

+228
-32
lines changed

homeassistant/components/automation/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@
117117

118118
NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG = "new_triggers_conditions"
119119

120+
_EXPERIMENTAL_CONDITION_PLATFORMS = {
121+
"light",
122+
}
123+
120124
_EXPERIMENTAL_TRIGGER_PLATFORMS = {
121125
"alarm_control_panel",
122126
"assist_satellite",
@@ -131,6 +135,19 @@
131135
}
132136

133137

138+
@callback
139+
def is_disabled_experimental_condition(hass: HomeAssistant, platform: str) -> bool:
140+
"""Check if the platform is a disabled experimental condition platform."""
141+
return (
142+
platform in _EXPERIMENTAL_CONDITION_PLATFORMS
143+
and not labs.async_is_preview_feature_enabled(
144+
hass,
145+
DOMAIN,
146+
NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG,
147+
)
148+
)
149+
150+
134151
@callback
135152
def is_disabled_experimental_trigger(hass: HomeAssistant, platform: str) -> bool:
136153
"""Check if the platform is a disabled experimental trigger platform."""

homeassistant/helpers/condition.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@
110110
CONDITION_DESCRIPTION_CACHE: HassKey[dict[str, dict[str, Any] | None]] = HassKey(
111111
"condition_description_cache"
112112
)
113+
CONDITION_DISABLED_CONDITIONS: HassKey[set[str]] = HassKey(
114+
"condition_disabled_conditions"
115+
)
113116
CONDITION_PLATFORM_SUBSCRIPTIONS: HassKey[
114117
list[Callable[[set[str]], Coroutine[Any, Any, None]]]
115118
] = HassKey("condition_platform_subscriptions")
@@ -151,9 +154,27 @@ def starts_with_dot(key: str) -> str:
151154

152155
async def async_setup(hass: HomeAssistant) -> None:
153156
"""Set up the condition helper."""
157+
from homeassistant.components import automation, labs # noqa: PLC0415
158+
154159
hass.data[CONDITION_DESCRIPTION_CACHE] = {}
160+
hass.data[CONDITION_DISABLED_CONDITIONS] = set()
155161
hass.data[CONDITION_PLATFORM_SUBSCRIPTIONS] = []
156162
hass.data[CONDITIONS] = {}
163+
164+
@callback
165+
def new_triggers_conditions_listener() -> None:
166+
"""Handle new_triggers_conditions flag change."""
167+
# Invalidate the cache
168+
hass.data[CONDITION_DESCRIPTION_CACHE] = {}
169+
hass.data[CONDITION_DISABLED_CONDITIONS] = set()
170+
171+
labs.async_listen(
172+
hass,
173+
automation.DOMAIN,
174+
automation.NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG,
175+
new_triggers_conditions_listener,
176+
)
177+
157178
await async_process_integration_platforms(
158179
hass, "condition", _register_condition_platform, wait_for_platforms=True
159180
)
@@ -352,11 +373,21 @@ def wrapper(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool | N
352373
async def _async_get_condition_platform(
353374
hass: HomeAssistant, condition_key: str
354375
) -> tuple[str, ConditionProtocol | None]:
376+
from homeassistant.components import automation # noqa: PLC0415
377+
355378
platform_and_sub_type = condition_key.split(".")
356379
platform: str | None = platform_and_sub_type[0]
357380
platform = _PLATFORM_ALIASES.get(platform, platform)
358381
if platform is None:
359382
return "", None
383+
384+
if automation.is_disabled_experimental_condition(hass, platform):
385+
raise vol.Invalid(
386+
f"Condition '{condition_key}' requires the experimental 'New triggers and "
387+
"conditions' feature to be enabled in Home Assistant Labs settings "
388+
f"(feature flag: '{automation.NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG}')"
389+
)
390+
360391
try:
361392
integration = await async_get_integration(hass, platform)
362393
except IntegrationNotFound:
@@ -1209,6 +1240,8 @@ async def async_get_all_descriptions(
12091240
hass: HomeAssistant,
12101241
) -> dict[str, dict[str, Any] | None]:
12111242
"""Return descriptions (i.e. user documentation) for all conditions."""
1243+
from homeassistant.components import automation # noqa: PLC0415
1244+
12121245
descriptions_cache = hass.data[CONDITION_DESCRIPTION_CACHE]
12131246

12141247
conditions = hass.data[CONDITIONS]
@@ -1217,7 +1250,12 @@ async def async_get_all_descriptions(
12171250
all_conditions = set(conditions)
12181251
previous_all_conditions = set(descriptions_cache)
12191252
# If the conditions are the same, we can return the cache
1220-
if previous_all_conditions == all_conditions:
1253+
1254+
# mypy complains: Invalid index type "HassKey[set[str]]" for "HassDict"
1255+
if (
1256+
previous_all_conditions | hass.data[CONDITION_DISABLED_CONDITIONS] # type: ignore[index]
1257+
== all_conditions
1258+
):
12211259
return descriptions_cache
12221260

12231261
# Files we loaded for missing descriptions
@@ -1257,6 +1295,9 @@ async def async_get_all_descriptions(
12571295
new_descriptions_cache = descriptions_cache.copy()
12581296
for missing_condition in missing_conditions:
12591297
domain = conditions[missing_condition]
1298+
if automation.is_disabled_experimental_condition(hass, domain):
1299+
hass.data[CONDITION_DISABLED_CONDITIONS].add(missing_condition)
1300+
continue
12601301

12611302
if (
12621303
yaml_description := new_conditions_descriptions.get(domain, {}).get(

tests/components/light/test_condition.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"""Test light conditions."""
22

3+
from collections.abc import Generator
4+
from unittest.mock import patch
5+
36
import pytest
47

58
from homeassistant.components import automation
69
from homeassistant.const import (
10+
ATTR_LABEL_ID,
711
CONF_CONDITION,
812
CONF_OPTIONS,
913
CONF_TARGET,
@@ -83,6 +87,39 @@ async def has_call_after_trigger(
8387
return has_calls
8488

8589

90+
@pytest.fixture(name="enable_experimental_triggers_conditions")
91+
def enable_experimental_triggers_conditions() -> Generator[None]:
92+
"""Enable experimental triggers and conditions."""
93+
with patch(
94+
"homeassistant.components.labs.async_is_preview_feature_enabled",
95+
return_value=True,
96+
):
97+
yield
98+
99+
100+
@pytest.mark.parametrize(
101+
"condition",
102+
[
103+
"light.is_off",
104+
"light.is_on",
105+
],
106+
)
107+
async def test_light_conditions_gated_by_labs_flag(
108+
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str
109+
) -> None:
110+
"""Test the light conditions are gated by the labs flag."""
111+
await setup_automation_with_light_condition(
112+
hass, condition=condition, target={ATTR_LABEL_ID: "test_label"}, behavior="any"
113+
)
114+
assert (
115+
"Unnamed automation failed to setup conditions and has been disabled: "
116+
f"Condition '{condition}' requires the experimental 'New triggers and "
117+
"conditions' feature to be enabled in Home Assistant Labs settings "
118+
"(feature flag: 'new_triggers_conditions')"
119+
) in caplog.text
120+
121+
122+
@pytest.mark.usefixtures("enable_experimental_triggers_conditions")
86123
@pytest.mark.parametrize(
87124
("condition_target_config", "entity_id", "entities_in_target"),
88125
parametrize_target_entities("light"),
@@ -166,6 +203,7 @@ async def test_light_state_condition_behavior_any(
166203
assert not await has_call_after_trigger(hass, service_calls)
167204

168205

206+
@pytest.mark.usefixtures("enable_experimental_triggers_conditions")
169207
@pytest.mark.parametrize(
170208
("condition_target_config", "entity_id", "entities_in_target"),
171209
parametrize_target_entities("light"),

0 commit comments

Comments
 (0)