Here's a minimal reproducible example demonstrating the problem:
import asyncio
from zeroconf import Zeroconf, ServiceStateChange
from zeroconf.asyncio import AsyncServiceBrowser
def on_service_state_change(zeroconf, service_type, name, state_change):
if state_change == ServiceStateChange.Added:
info = zeroconf.get_service_info(service_type, name)
print(info)
async def browse_services():
zeroconf = Zeroconf()
service_type = "_http._tcp.local."
browser = AsyncServiceBrowser(zeroconf, service_type, handlers=[on_service_state_change])
try:
await asyncio.Event().wait()
finally:
zeroconf.close()
if __name__ == "__main__":
asyncio.run(browse_services())
This fails, like this:
Exception in callback _SelectorDatagramTransport._read_ready()
handle: <Handle _SelectorDatagramTransport._read_ready()>
Traceback (most recent call last):
File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/usr/lib/python3.10/asyncio/selector_events.py", line 1035, in _read_ready
self._protocol.datagram_received(data, addr)
File "src/zeroconf/_listener.py", line 80, in zeroconf._listener.AsyncListener.datagram_received
File "src/zeroconf/_listener.py", line 161, in zeroconf._listener.AsyncListener.datagram_received
File "src/zeroconf/_handlers/record_manager.py", line 162, in zeroconf._handlers.record_manager.RecordManager.async_updates_from_response
File "src/zeroconf/_handlers/record_manager.py", line 71, in zeroconf._handlers.record_manager.RecordManager.async_updates_complete
File "src/zeroconf/_services/browser.py", line 441, in zeroconf._services.browser._ServiceBrowserBase.async_update_records_complete
File "src/zeroconf/_services/browser.py", line 451, in zeroconf._services.browser._ServiceBrowserBase.async_update_records_complete
File "src/zeroconf/_services/browser.py", line 454, in zeroconf._services.browser._ServiceBrowserBase._fire_service_state_changed_event
File "src/zeroconf/_services/browser.py", line 454, in zeroconf._services.browser._ServiceBrowserBase._fire_service_state_changed_event
File "src/zeroconf/_services/browser.py", line 464, in zeroconf._services.browser._ServiceBrowserBase._fire_service_state_changed_event
File "/home/tkcook/.virtualenvs/veeahub/lib/python3.10/site-packages/zeroconf/_services/__init__.py", line 56, in fire
h(**kwargs)
File "/home/tkcook/Scratch/zeroconf_test.py", line 7, in on_service_state_change
info = zeroconf.get_service_info(service_type, name)
File "/home/tkcook/.virtualenvs/veeahub/lib/python3.10/site-packages/zeroconf/_core.py", line 270, in get_service_info
if info.request(self, timeout, question_type):
File "src/zeroconf/_services/info.py", line 752, in zeroconf._services.info.ServiceInfo.request
RuntimeError: Use AsyncServiceInfo.async_request from the event loop
I can't use async_request()
here (and by implication async_get_service_info()
) because the service listener is not async and so the resulting coroutine can't be awaited. As far as I can tell, there is no way to add an async service listener. AsyncZeroconf.async_add_service_listener
does not result in the callback functions being awaited and therefore doesn't help with this.
Am I missing something? Is there some way to do this that I'm missing?