frawau / aiozeroconf

An asyncio/pure python implementation of multicast DNS service discovery
GNU Lesser General Public License v2.1
25 stars 6 forks source link

Task was destroyed but it is pending #10

Open MikhailMS opened 5 years ago

MikhailMS commented 5 years ago

Hello there. Thanks for making an effort and writing this extension to the old-fashioned thread-style Zeroconfig package.

However at the moment, when I'm trying to run an example from the README

import asyncio
import logging

from aiozeroconf import ServiceBrowser, Zeroconf

logging.basicConfig(level = logging.DEBUG)

async def do_close(zc):
    await zc.close()

class MyListener:

    def remove_service(self, zeroconf, type_, name):
        print("Service %s removed" % (name,))

    def add_service(self, zeroconf, type_, name):
        asyncio.ensure_future(self.found_service(zeroconf, type_, name))

    async def found_service(self, zeroconf, type_, name):
        info = await zeroconf.get_service_info(type_, name)
        print("Adding {}".format(info))

loop     = asyncio.get_event_loop()
# loop.set_debug(True)

zeroconf = Zeroconf(loop)
listener = MyListener()
browser  = ServiceBrowser(zeroconf, "_googlecast._tcp.local.", listener) # searching for google chromecast

try:
    loop.run_forever()
except KeyboardInterrupt:
    print("Unregistering...")
    loop.run_until_complete(do_close(zeroconf))
finally:
    loop.close()

and after I close it, it fails with following error trace

ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<ServiceBrowser.run() running at /user/miniconda2/envs/development/lib/python3.6/site-packages/aiozeroconf/aiozeroconf.py:1231> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x17b468>()]>>

Seems to me that may happen because when you try to cancell the ServiceBrowser.run task here it is not cancelled straightaway - Python docs outlines this behaviour here

frawau commented 5 years ago

Hi,

Thanks for your message.

Try running,

    python3 -m aiozeroconf -s _googlecast._tcp.local.

And see if you get that error. I do not. I may need to uipdate the Readme file ;) Have a look at main.py for way to avoid that error.

MikhailMS commented 5 years ago

I can see that there is some difference between example in README and main.py file you refer to. Probably it is a good idea to update README file ;)

But I'll check if it works for me later today :)

MikhailMS commented 5 years ago

Well, if I change my script to

import argparse
import asyncio
import logging
import socket

from aiozeroconf import ServiceBrowser, ServiceStateChange, Zeroconf, ZeroconfServiceTypes

import netifaces

def on_service_state_change(zc: Zeroconf, service_type: str, name: str, state_change) -> None:
    if state_change is ServiceStateChange.Added:
        asyncio.ensure_future(on_service_state_change_process(zc, service_type, name))
    else:
        print(f'Service {name} of type {service_type} state changed: {state_change}')

async def on_service_state_change_process(zc: Zeroconf, service_type: str, name: str) -> None:
    info = await zc.get_service_info(service_type, name)
    print(f'Service {name} of type {service_type} state changed: {ServiceStateChange.Added}')
    if info:
        if info.address:
            print(f'  IPv4 Address: {socket.inet_ntoa(info.address)}:{info.port}')
        if info.address6:
            print(f'  IPv6 Address: {socket.inet_ntop(netifaces.AF_INET6,info.address6)}:{info.port}')
        print(f'  Weight: {info.weight}, priority: {info.priority}')
        print(f'  Server: {info.server}')
        if info.properties:
            print('  Properties are:')
            for key, value in info.properties.items():
                print(f'    {key.decode()}: {value.decode()}')
        else:
            print('  No properties')
    else:
        print('  No info')
    print('\n')

async def do_close(zc):
    await zc.close()

proto = [netifaces.AF_INET]
loop  = asyncio.get_event_loop()
zc    = Zeroconf(loop, proto, iface = '')

logging.basicConfig(level = logging.CRITICAL)

logging.getLogger('zeroconf').setLevel(logging.DEBUG)
loop.set_debug(True)

print('Browsing services, press Ctrl-C to exit...\n')

try:
    ServiceBrowser(zc, '_googlecast._tcp.local.', handlers=[on_service_state_change])
    loop.run_forever()
except KeyboardInterrupt:
    print('Unregistering...')
    loop.run_until_complete(do_close(zc))
finally:
    loop.close()

it works nicely with no excpetions. The only real difference I see here is that instead of passing listener class, I pass function as handlers parameter :/

Unless I am too tired and missing out something else here