mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Refactor state_reported listener setup to avoid merge in async_fire_internal (#117953)
* Refactor state_reported listener setup to avoid merge in async_fire_internal Instead of merging the listeners in async_fire_internal, setup the listener for state_changed at the same time so async_fire_internal can avoid having to copy another list * Refactor state_reported listener setup to avoid merge in async_fire_internal Instead of merging the listeners in async_fire_internal, setup the listener for state_changed at the same time so async_fire_internal can avoid having to copy another list * tweak * tweak * tweak * tweak * tweak
This commit is contained in:
parent
1f7245ecf2
commit
e663d4f602
@ -1500,7 +1500,6 @@ class EventBus:
|
|||||||
|
|
||||||
This method must be run in the event loop.
|
This method must be run in the event loop.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self._debug:
|
if self._debug:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Bus:Handling %s", _event_repr(event_type, origin, event_data)
|
"Bus:Handling %s", _event_repr(event_type, origin, event_data)
|
||||||
@ -1511,17 +1510,9 @@ class EventBus:
|
|||||||
match_all_listeners = self._match_all_listeners
|
match_all_listeners = self._match_all_listeners
|
||||||
else:
|
else:
|
||||||
match_all_listeners = EMPTY_LIST
|
match_all_listeners = EMPTY_LIST
|
||||||
if event_type == EVENT_STATE_CHANGED:
|
|
||||||
aliased_listeners = self._listeners.get(EVENT_STATE_REPORTED, EMPTY_LIST)
|
|
||||||
else:
|
|
||||||
aliased_listeners = EMPTY_LIST
|
|
||||||
listeners = listeners + match_all_listeners + aliased_listeners
|
|
||||||
if not listeners:
|
|
||||||
return
|
|
||||||
|
|
||||||
event: Event[_DataT] | None = None
|
event: Event[_DataT] | None = None
|
||||||
|
for job, event_filter in listeners + match_all_listeners:
|
||||||
for job, event_filter in listeners:
|
|
||||||
if event_filter is not None:
|
if event_filter is not None:
|
||||||
try:
|
try:
|
||||||
if event_data is None or not event_filter(event_data):
|
if event_data is None or not event_filter(event_data):
|
||||||
@ -1599,18 +1590,32 @@ class EventBus:
|
|||||||
|
|
||||||
if event_filter is not None and not is_callback_check_partial(event_filter):
|
if event_filter is not None and not is_callback_check_partial(event_filter):
|
||||||
raise HomeAssistantError(f"Event filter {event_filter} is not a callback")
|
raise HomeAssistantError(f"Event filter {event_filter} is not a callback")
|
||||||
|
filterable_job = (HassJob(listener, f"listen {event_type}"), event_filter)
|
||||||
if event_type == EVENT_STATE_REPORTED:
|
if event_type == EVENT_STATE_REPORTED:
|
||||||
if not event_filter:
|
if not event_filter:
|
||||||
raise HomeAssistantError(
|
raise HomeAssistantError(
|
||||||
f"Event filter is required for event {event_type}"
|
f"Event filter is required for event {event_type}"
|
||||||
)
|
)
|
||||||
return self._async_listen_filterable_job(
|
# Special case for EVENT_STATE_REPORTED, we also want to listen to
|
||||||
event_type,
|
# EVENT_STATE_CHANGED
|
||||||
(
|
self._listeners[EVENT_STATE_REPORTED].append(filterable_job)
|
||||||
HassJob(listener, f"listen {event_type}"),
|
self._listeners[EVENT_STATE_CHANGED].append(filterable_job)
|
||||||
event_filter,
|
return functools.partial(
|
||||||
),
|
self._async_remove_multiple_listeners,
|
||||||
|
(EVENT_STATE_REPORTED, EVENT_STATE_CHANGED),
|
||||||
|
filterable_job,
|
||||||
)
|
)
|
||||||
|
return self._async_listen_filterable_job(event_type, filterable_job)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_remove_multiple_listeners(
|
||||||
|
self,
|
||||||
|
keys: Iterable[EventType[_DataT] | str],
|
||||||
|
filterable_job: _FilterableJobType[Any],
|
||||||
|
) -> None:
|
||||||
|
"""Remove multiple listeners for specific event_types."""
|
||||||
|
for key in keys:
|
||||||
|
self._async_remove_listener(key, filterable_job)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_listen_filterable_job(
|
def _async_listen_filterable_job(
|
||||||
@ -1618,6 +1623,7 @@ class EventBus:
|
|||||||
event_type: EventType[_DataT] | str,
|
event_type: EventType[_DataT] | str,
|
||||||
filterable_job: _FilterableJobType[_DataT],
|
filterable_job: _FilterableJobType[_DataT],
|
||||||
) -> CALLBACK_TYPE:
|
) -> CALLBACK_TYPE:
|
||||||
|
"""Listen for all events or events of a specific type."""
|
||||||
self._listeners[event_type].append(filterable_job)
|
self._listeners[event_type].append(filterable_job)
|
||||||
return functools.partial(
|
return functools.partial(
|
||||||
self._async_remove_listener, event_type, filterable_job
|
self._async_remove_listener, event_type, filterable_job
|
||||||
|
@ -3346,7 +3346,9 @@ async def test_statemachine_report_state(hass: HomeAssistant) -> None:
|
|||||||
hass.states.async_set("light.bowl", "on", {})
|
hass.states.async_set("light.bowl", "on", {})
|
||||||
state_changed_events = async_capture_events(hass, EVENT_STATE_CHANGED)
|
state_changed_events = async_capture_events(hass, EVENT_STATE_CHANGED)
|
||||||
state_reported_events = []
|
state_reported_events = []
|
||||||
hass.bus.async_listen(EVENT_STATE_REPORTED, listener, event_filter=mock_filter)
|
unsub = hass.bus.async_listen(
|
||||||
|
EVENT_STATE_REPORTED, listener, event_filter=mock_filter
|
||||||
|
)
|
||||||
|
|
||||||
hass.states.async_set("light.bowl", "on")
|
hass.states.async_set("light.bowl", "on")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -3368,6 +3370,13 @@ async def test_statemachine_report_state(hass: HomeAssistant) -> None:
|
|||||||
assert len(state_changed_events) == 3
|
assert len(state_changed_events) == 3
|
||||||
assert len(state_reported_events) == 4
|
assert len(state_reported_events) == 4
|
||||||
|
|
||||||
|
unsub()
|
||||||
|
|
||||||
|
hass.states.async_set("light.bowl", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(state_changed_events) == 4
|
||||||
|
assert len(state_reported_events) == 4
|
||||||
|
|
||||||
|
|
||||||
async def test_report_state_listener_restrictions(hass: HomeAssistant) -> None:
|
async def test_report_state_listener_restrictions(hass: HomeAssistant) -> None:
|
||||||
"""Test we enforce requirements for EVENT_STATE_REPORTED listeners."""
|
"""Test we enforce requirements for EVENT_STATE_REPORTED listeners."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user