diff --git a/homeassistant/components/kitchen_sink/__init__.py b/homeassistant/components/kitchen_sink/__init__.py index 15f7314ee7a..5fc498cc94d 100644 --- a/homeassistant/components/kitchen_sink/__init__.py +++ b/homeassistant/components/kitchen_sink/__init__.py @@ -7,11 +7,16 @@ incorrect behavior, and are thus not wanted in the demo integration. from __future__ import annotations import datetime +from functools import partial from random import random import voluptuous as vol -from homeassistant.components.labs import async_is_preview_feature_enabled, async_listen +from homeassistant.components.labs import ( + EventLabsUpdatedData, + async_is_preview_feature_enabled, + async_subscribe_preview_feature, +) from homeassistant.components.recorder import DOMAIN as RECORDER_DOMAIN, get_instance from homeassistant.components.recorder.models import ( StatisticData, @@ -128,16 +133,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Subscribe to labs feature updates for kitchen_sink preview repair entry.async_on_unload( - async_listen( + async_subscribe_preview_feature( hass, domain=DOMAIN, preview_feature="special_repair", - listener=lambda: _async_update_special_repair(hass), + listener=partial(_async_update_special_repair, hass), ) ) # Check if lab feature is currently enabled and create repair if so - _async_update_special_repair(hass) + await _async_update_special_repair(hass) return True @@ -166,15 +171,22 @@ async def async_remove_config_entry_device( return True -@callback -def _async_update_special_repair(hass: HomeAssistant) -> None: +async def _async_update_special_repair( + hass: HomeAssistant, + event_data: EventLabsUpdatedData | None = None, +) -> None: """Create or delete the special repair issue. Creates a repair issue when the special_repair lab feature is enabled, and deletes it when disabled. This demonstrates how lab features can interact with Home Assistant's repair system. """ - if async_is_preview_feature_enabled(hass, DOMAIN, "special_repair"): + enabled = ( + event_data["enabled"] + if event_data is not None + else async_is_preview_feature_enabled(hass, DOMAIN, "special_repair") + ) + if enabled: async_create_issue( hass, DOMAIN, diff --git a/homeassistant/components/labs/helpers.py b/homeassistant/components/labs/helpers.py index 81454cbe811..2045487ec84 100644 --- a/homeassistant/components/labs/helpers.py +++ b/homeassistant/components/labs/helpers.py @@ -7,6 +7,7 @@ from typing import Any from homeassistant.const import EVENT_LABS_UPDATED from homeassistant.core import Event, HomeAssistant, callback +from homeassistant.helpers.frame import report_usage from .const import LABS_DATA from .models import EventLabsUpdatedData @@ -79,6 +80,8 @@ def async_listen( ) -> Callable[[], None]: """Listen for changes to a specific preview feature. + Deprecated: use async_subscribe_preview_feature instead. + Args: hass: HomeAssistant instance domain: Integration domain @@ -88,6 +91,11 @@ def async_listen( Returns: Callable to unsubscribe from the listener """ + report_usage( + "calls `async_listen` which is deprecated, " + "use `async_subscribe_preview_feature` instead", + breaks_in_ha_version="2027.3.0", + ) async def _listener(_event_data: EventLabsUpdatedData) -> None: listener() diff --git a/homeassistant/components/template/__init__.py b/homeassistant/components/template/__init__.py index 35c629c8af3..c1a136a29ef 100644 --- a/homeassistant/components/template/__init__.py +++ b/homeassistant/components/template/__init__.py @@ -4,7 +4,6 @@ from __future__ import annotations import asyncio from collections.abc import Coroutine -from functools import partial import logging from typing import Any @@ -13,7 +12,10 @@ from homeassistant.components.automation import ( DOMAIN as AUTOMATION_DOMAIN, NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG, ) -from homeassistant.components.labs import async_listen as async_labs_listen +from homeassistant.components.labs import ( + EventLabsUpdatedData, + async_subscribe_preview_feature, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_DEVICE_ID, @@ -22,7 +24,7 @@ from homeassistant.const import ( CONF_UNIQUE_ID, SERVICE_RELOAD, ) -from homeassistant.core import Event, HomeAssistant, ServiceCall, callback +from homeassistant.core import Event, HomeAssistant, ServiceCall from homeassistant.exceptions import ConfigEntryError, HomeAssistantError from homeassistant.helpers import discovery, issue_registry as ir from homeassistant.helpers.device import ( @@ -99,18 +101,19 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async_register_admin_service(hass, DOMAIN, SERVICE_RELOAD, _reload_config) - @callback - def new_triggers_conditions_listener() -> None: + async def _handle_new_triggers_conditions( + _event_data: EventLabsUpdatedData, + ) -> None: """Handle new_triggers_conditions flag change.""" hass.async_create_task( _reload_config(ServiceCall(hass, DOMAIN, SERVICE_RELOAD)) ) - async_labs_listen( + async_subscribe_preview_feature( hass, AUTOMATION_DOMAIN, NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG, - new_triggers_conditions_listener, + _handle_new_triggers_conditions, ) return True @@ -139,12 +142,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: entry, (entry.options["template_type"],) ) + async def _handle_entry_reload(_event_data: EventLabsUpdatedData) -> None: + hass.config_entries.async_schedule_reload(entry.entry_id) + entry.async_on_unload( - async_labs_listen( + async_subscribe_preview_feature( hass, AUTOMATION_DOMAIN, NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG, - partial(hass.config_entries.async_schedule_reload, entry.entry_id), + _handle_entry_reload, ) ) diff --git a/tests/components/labs/test_init.py b/tests/components/labs/test_init.py index 46f2ca01a23..889db785372 100644 --- a/tests/components/labs/test_init.py +++ b/tests/components/labs/test_init.py @@ -360,7 +360,9 @@ async def test_preview_feature_to_dict_is_built_in( assert result["is_built_in"] is expected_default -async def test_async_listen_helper(hass: HomeAssistant) -> None: +async def test_async_listen_helper( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture +) -> None: """Test the async_listen helper function for preview feature events.""" # Load kitchen_sink integration hass.config.components.add("kitchen_sink") @@ -383,6 +385,8 @@ async def test_async_listen_helper(hass: HomeAssistant) -> None: listener=test_listener, ) + assert ("calls `async_listen` which is deprecated") in caplog.text + # Fire event for the subscribed feature hass.bus.async_fire( EVENT_LABS_UPDATED,