Running other async libs with asyncio-tkinter
Hallo,
I just started this project: https://github.com/duk3luk3/faflauncher
Where I'm trying to use asyncio-tkinter and also aiohttp.
With the code as it is in the repo currently:
import tkinter as tk
from tkevents import TkEventLoop
import asyncio
import updater
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.create_widgets()
#asyncio.async(self.launch())
#self.do_github()
#asyncio.get_event_loop().run_until_complete(self.do_github())
...
def launch(self, loop):
f = asyncio.ensure_future(updater.fetch_tags('FAForever', 'client'), loop=loop)
f.add_done_callback(app.set_github)
def set_github(self, fut):
tag, zipball_url = fut.result()
self.label["text"] = "{} => {}".format(tag, zipball_url)
root = tk.Tk()
app = Application(master=root)
#app.mainloop()
loop = TkEventLoop(app)
app.launch(loop)
loop.mainloop()
I get this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python3.6/tkinter/__init__.py", line 1699, in __call__
return self.func(*args)
File "/usr/lib64/python3.6/tkinter/__init__.py", line 745, in callit
func(*args)
File "src/tkevents.py", line 46, in <lambda>
lambda cb, a : cb(*a),
File "src/__main__.py", line 44, in set_github
tag, zipball_url = fut.result()
File "src/updater.py", line 20, in fetch_tags
response = await fetch(session, url)
File "src/updater.py", line 13, in fetch
async with session.get(url) as response:
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/client.py", line 603, in __aenter__
self._resp = yield from self._coro
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/client.py", line 231, in _request
conn = yield from self._connector.connect(req)
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/connector.py", line 378, in connect
proto = yield from self._create_connection(req)
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/connector.py", line 687, in _create_connection
_, proto = yield from self._create_direct_connection(req)
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/connector.py", line 698, in _create_direct_connection
hosts = yield from self._resolve_host(req.url.raw_host, req.port)
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/connector.py", line 669, in _resolve_host
self._resolver.resolve(host, port, family=self._family)
File "/home/erlacher/git/faf/launcher/.venv/lib/python3.6/site-packages/aiohttp/resolver.py", line 31, in resolve
host, port, type=socket.SOCK_STREAM, family=family)
RuntimeError: Task <Task pending coro=<fetch_tags() running at src/updater.py:20> cb=[Application.set_github()]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib64/python3.6/asyncio/futures.py:408]> attached to a different loop
This seems to be a somewhat common problem when trying to merge two async projects.
Can you give me any insights into why that is and how to fix it?
It looks to me, the problem is that the TkEventLoop does not install itself as “the” event loop until you call its mainloop() method. So when you instantiated your Application object prior to that, the call to ensure_future() is using the default asyncio.BaseEventLoop instance.
I think that any wrapper attempting to provide an asyncio-compatible API for a third-party event loop should provide something like an explicit install() method that you call up-front before doing any asyncio calls. This should install an event-loop policy to ensure that henceforth, all event loops are created by the wrapper.
This is what I did in glibcoro, for example.