Deprecate passing add_helper_config_entry_to_device to async_handle_source_entity_changes (#176701)

This commit is contained in:
Erik Montnemery
2026-07-17 17:51:13 +02:00
committed by GitHub
parent 1917e8a877
commit a868b498e2
13 changed files with 84 additions and 31 deletions
@@ -27,7 +27,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -105,7 +105,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# humidifier's device.
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_humidifier_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -33,7 +33,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# heater's device.
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_humidifier_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -78,7 +78,6 @@ async def async_setup_entry(
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -29,7 +29,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -37,7 +37,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# to the humidity sensor's device.
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -35,7 +35,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -60,7 +60,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_get_parent_device_id(hass, entity_id),
@@ -27,7 +27,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -34,7 +34,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
@@ -205,7 +205,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(
async_handle_source_entity_changes(
hass,
add_helper_config_entry_to_device=False,
helper_config_entry_id=entry.entry_id,
set_source_entity_id_or_uuid=set_source_entity_id_or_uuid,
source_device_id=async_entity_id_to_device_id(
+22 -19
View File
@@ -7,17 +7,18 @@ from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, valid_entity
from . import device_registry as dr, entity_registry as er
from .event import async_track_entity_registry_updated_event
from .frame import ReportBehavior, report_usage
def async_handle_source_entity_changes(
hass: HomeAssistant,
*,
add_helper_config_entry_to_device: bool = True,
helper_config_entry_id: str,
set_source_entity_id_or_uuid: Callable[[str], None],
source_device_id: str | None,
source_entity_id_or_uuid: str,
source_entity_removed: Callable[[], Coroutine[Any, Any, None]] | None = None,
**kwargs: Any,
) -> CALLBACK_TYPE:
"""Handle changes to a helper entity's source entity.
@@ -31,11 +32,9 @@ def async_handle_source_entity_changes(
called. If the source entity is identified by a UUID, the helper config entry
is reloaded.
- Source entity moved to another device: The helper entity is updated to link
to the new device, and the helper config entry removed from the old device
and added to the new device. Then the helper config entry is reloaded.
to the new device. Then the helper config entry is reloaded.
- Source entity removed from the device: The helper entity is updated to link
to no device, and the helper config entry removed from the old device. Then
the helper config entry is reloaded.
to no device. Then the helper config entry is reloaded.
:param set_source_entity_id_or_uuid: A function which updates the source entity
ID or UUID, e.g., in the helper config entry options.
@@ -43,6 +42,22 @@ def async_handle_source_entity_changes(
is removed. This can be used to clean up any resources related to the source
entity or ask the user to select a new source entity.
"""
if "add_helper_config_entry_to_device" in kwargs:
del kwargs["add_helper_config_entry_to_device"]
# Adding the helper's config entry to the source device is no longer supported
# now that a device belongs to a single config entry; the helper entities link to
# the source device via their device_id instead.
report_usage(
"calls async_handle_source_entity_changes with "
"add_helper_config_entry_to_device, which no longer has any effect",
core_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2027.8.0",
)
if kwargs:
raise TypeError(
"async_handle_source_entity_changes() got unexpected keyword arguments "
f"{', '.join(map(repr, kwargs))}"
)
async def async_registry_updated(
event: Event[er.EventEntityRegistryUpdatedData],
@@ -89,9 +104,8 @@ def async_handle_source_entity_changes(
# No need to do any cleanup
return
# The source entity has been moved to a different device, update the helper
# entities to link to the new device and the helper device to include the
# helper config entry
# The source entity has been moved to a different device; relink the helper
# entities to the new device.
for helper_entity in entity_registry.entities.get_entries_for_config_entry_id(
helper_config_entry_id
):
@@ -100,17 +114,6 @@ def async_handle_source_entity_changes(
helper_entity.entity_id, device_id=source_entity_entry.device_id
)
if add_helper_config_entry_to_device:
if source_entity_entry.device_id is not None:
device_registry.async_update_device(
source_entity_entry.device_id,
add_config_entry_id=helper_config_entry_id,
)
device_registry.async_update_device(
source_device_id, remove_config_entry_id=helper_config_entry_id
)
source_device_id = source_entity_entry.device_id
# Reload the config entry so the helper entity is recreated with
+62 -1
View File
@@ -1,7 +1,7 @@
"""Tests for the helper entity helpers."""
from collections.abc import Generator
from unittest.mock import AsyncMock, Mock
from unittest.mock import AsyncMock, Mock, patch
import pytest
@@ -213,6 +213,67 @@ def listen_entity_registry_events(
return events
@pytest.mark.parametrize("add_helper_config_entry_to_device", [True, False])
async def test_async_handle_source_entity_changes_deprecated_kwarg(
hass: HomeAssistant,
add_helper_config_entry_to_device: bool,
) -> None:
"""The removed add_helper_config_entry_to_device kwarg is accepted but reported.
It is swallowed by **kwargs so callers still passing it don't raise, and reported on
its presence rather than its value, since it no longer has any effect either way.
"""
with patch("homeassistant.helpers.helper_integration.report_usage") as report_usage:
unsub = async_handle_source_entity_changes(
hass,
helper_config_entry_id="helper_config_entry_id",
set_source_entity_id_or_uuid=Mock(),
source_device_id=None,
source_entity_id_or_uuid="sensor.test",
add_helper_config_entry_to_device=add_helper_config_entry_to_device,
)
unsub()
report_usage.assert_called_once()
assert "add_helper_config_entry_to_device" in report_usage.call_args[0][0]
async def test_async_handle_source_entity_changes_rejects_unknown_kwarg(
hass: HomeAssistant,
) -> None:
"""An unknown keyword argument still raises, as it did before **kwargs was added.
**kwargs only exists to swallow the deprecated add_helper_config_entry_to_device;
anything else (e.g. a misspelling) must not be silently accepted.
"""
with pytest.raises(TypeError, match="unexpected keyword arguments 'unknown_kwarg'"):
async_handle_source_entity_changes(
hass,
helper_config_entry_id="helper_config_entry_id",
set_source_entity_id_or_uuid=Mock(),
source_device_id=None,
source_entity_id_or_uuid="sensor.test",
unknown_kwarg=True,
)
async def test_async_handle_source_entity_changes_without_deprecated_kwarg(
hass: HomeAssistant,
) -> None:
"""Not passing the removed add_helper_config_entry_to_device kwarg is not reported."""
with patch("homeassistant.helpers.helper_integration.report_usage") as report_usage:
unsub = async_handle_source_entity_changes(
hass,
helper_config_entry_id="helper_config_entry_id",
set_source_entity_id_or_uuid=Mock(),
source_device_id=None,
source_entity_id_or_uuid="sensor.test",
)
unsub()
report_usage.assert_not_called()
@pytest.mark.parametrize("source_entity_removed", [None])
@pytest.mark.parametrize("use_entity_registry_id", [True, False])
@pytest.mark.usefixtures("mock_helper_flow", "mock_helper_integration")