I\'m trying to create a new application based on PyQt5 and asyncio (with python 3.4, looking forward to eventually upgrade to 3.5 with async/await). My goal is to use asyncio so
Ok, that's one plus of SO: Writing down a question makes you think again about everything. Somehow I just figured it out:
Looking again at the example from the quamash repo, I found that the event loop to use is obtained somewhat differently:
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop) # NEW must set the event loop
# ...
with loop:
loop.run_until_complete(master())
The key seems to be the asyncio.set_event_loop(). It is also important to note that the QEventLoop mentioned there is the one from the quamash package, NOT from Qt5. So my example now looks like this:
import sys
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')
loop.stop()
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):
#~ loop.call_soon(coroCallHelper, slow_operation)
asyncio.ensure_future(slow_operation(), loop=loop)
print('btnCallback returns...')
btn = QPushButton('Button', self)
btn.resize(btn.sizeHint())
btn.move(50, 50)
btn.clicked.connect(btnCallback)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Async')
self.show()
app = QApplication(sys.argv)
loop = quamash.QEventLoop(app)
asyncio.set_event_loop(loop) # NEW must set the event loop
with loop:
w = Example()
w.show()
loop.run_forever()
print('Coroutine has ended')
And it 'just works' now:
btnCallback returns...
clicked
op()
op done
timeout expired
second timeout expired
Coroutine has ended
Maybe this is of some help for others. I'm happy with it at least ;) Comments on the general pattern are still welcome, of course!
Addendum: Please note that this works with recent Python versions up to Python 3.7.x if quamash is replaced by asyncqt. However, using the same code with Python 3.8 causes the @coroutine decorators to generate RuntimeWarnings and eventually fails with a RuntimeError: no running event loop in asyncio.sleep(). Maybe someone else knows what to change to get this working again. It might just be that asyncqt is not yet compatible with Python 3.8.
Regards, Philipp