Refactor async_listen_once to remove nonlocal (#108627)

This commit is contained in:
J. Nick Koston 2024-01-21 17:52:47 -10:00 committed by GitHub
parent 740209912c
commit a3f9fc45e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1153,6 +1153,23 @@ _FilterableJobType = tuple[
] ]
@dataclass(slots=True)
class _OneTimeListener:
hass: HomeAssistant
listener: Callable[[Event], Coroutine[Any, Any, None] | None]
remove: CALLBACK_TYPE | None = None
@callback
def async_call(self, event: Event) -> None:
"""Remove listener from event bus and then fire listener."""
if not self.remove:
# If the listener was already removed, we don't need to do anything
return
self.remove()
self.remove = None
self.hass.async_run_job(self.listener, event)
class EventBus: class EventBus:
"""Allow the firing of and listening for events.""" """Allow the firing of and listening for events."""
@ -1344,39 +1361,21 @@ class EventBus:
This method must be run in the event loop. This method must be run in the event loop.
""" """
filterable_job: _FilterableJobType | None = None one_time_listener = _OneTimeListener(self._hass, listener)
remove = self._async_listen_filterable_job(
@callback event_type,
def _onetime_listener(event: Event) -> None: (
"""Remove listener from event bus and then fire listener.""" HassJob(
nonlocal filterable_job one_time_listener.async_call,
if hasattr(_onetime_listener, "run"): f"onetime listen {event_type} {listener}",
return job_type=HassJobType.Callback,
# Set variable so that we will never run twice. ),
# Because the event bus loop might have async_fire queued multiple None,
# times, its possible this listener may already be lined up False,
# multiple times as well.
# This will make sure the second time it does nothing.
setattr(_onetime_listener, "run", True)
assert filterable_job is not None
self._async_remove_listener(event_type, filterable_job)
self._hass.async_run_job(listener, event)
functools.update_wrapper(
_onetime_listener, listener, ("__name__", "__qualname__", "__module__"), []
)
filterable_job = (
HassJob(
_onetime_listener,
f"onetime listen {event_type} {listener}",
job_type=HassJobType.Callback,
), ),
None,
False,
) )
one_time_listener.remove = remove
return self._async_listen_filterable_job(event_type, filterable_job) return remove
@callback @callback
def _async_remove_listener( def _async_remove_listener(