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 RuntimeWarning
s 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