I am trying to create a new application based on PyQt5 and asyncio (since python 3.4, I look forward to eventually upgrading to 3.5 using async / await). My goal is to use asyncio so that the graphical interface remains responsive even when the application expects some connected equipment to complete the operation.
When you look at how to combine Qt5 and asyncio event loops, I found a mailing list offering to use quamash . However, when running this example (unmodified),
yield from fut
Nevers seems to be returning. I see the Timeout output, so the timer callback obviously works, but the future cannot wake the wait method. When manually closing a window, it tells me that there are unfinished futures:
Yielding until signal... Timeout Traceback (most recent call last): File "pyqt_asyncio_list.py", line 26, in <module> loop.run_until_complete(_go()) File "/usr/local/lib/python3.5/site-packages/quamash/__init__.py", line 291, in run_until_complete raise RuntimeError('Event loop stopped before Future completed.') RuntimeError: Event loop stopped before Future completed.
I tested this on Ubuntu with python 3.5 and on Windows 3.4, the same behavior on both platforms.
In any case, since this is not what I'm actually trying to achieve, I also checked another code:
import quamash import asyncio from PyQt5.QtWidgets import * from PyQt5.QtCore import * @asyncio.coroutine def op(): print('op()') @asyncio.coroutine def slow_operation(): print('clicked') yield from op() print('op done') yield from asyncio.sleep(0.1) print('timeout expired') yield from asyncio.sleep(2) print('second timeout expired') def coroCallHelper(coro): asyncio.ensure_future(coro(), loop=loop) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): def btnCallback(obj):
It is assumed that the program should display a window with a button in it (what it does), while the button calls slow_operation () without locking the GUI. When I run this example, I can click the button as often as I want, so the GUI is not blocked. But
yield from asyncio.sleep(0.1)
never transmitted, and the terminal output looks like this:
btnCallback returns... clicked op() op done btnCallback returns... clicked op() op done
No exception occurs when I close the window this time. The slow_operation () function basically works if I directly start an event loop with it:
#~ with quamash.QEventLoop(app=QApplication([])) as loop:
Now two questions:
Is this a smart way to get the long-running operations of the GUI decoupled? My intention is that the button callback sends the coroutine call to the event loop (with or without an additional nesting level, cf. coroCallHelper ()), where it is then scheduled and executed. I do not need separate threads, since in fact only I / O takes time, not the actual processing.
How can I fix this behavior?
Thanks Philipp