Reputation: 40778
This is a small test program I wrote trying to understand how I can use the PyQt eventloop with asyncio
:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from PyQt5 import QtCore
import qasync
import asyncio
async def main():
app = QApplication(sys.argv)
asyncio.set_event_loop(qasync.QEventLoop(app))
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText('Run')
future = None
def run_action():
future.set_result('run clicked')
button.clicked.connect(run_action)
window.setWindowTitle('Testing async event loop')
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
asyncio.run(main())
This gives me the following error:
Traceback (most recent call last):
File "/home/hakon/test/python/async/./t.py", line 36, in <module>
asyncio.run(main())
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/home/hakon/test/python/async/./t.py", line 25, in main
await asyncio.sleep(1)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/tasks.py", line 654, in sleep
return await future
RuntimeError: Task <Task pending name='Task-1' coro=<main() running at /home/hakon/test/python/async/./t.py:25> cb=[_run_until_complete_cb() at /home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop
Any idea what I am missing here? How can I improve this code?
Upvotes: 3
Views: 1392
Reputation: 244132
The problem is that you are running an eventloop and then you have just created the Qt eventloop. There are 2 possible solutions:
Set the eventloop before executing the coroutine main:
import asyncio
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
import qasync
async def main():
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText("Run")
future = None
def run_action():
if future is not None:
future.set_result("run clicked")
button.clicked.connect(run_action)
window.setWindowTitle("Testing async event loop")
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
app = QApplication(sys.argv)
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)
with loop:
loop.run_until_complete(main())
Or use qasync.run():
import asyncio
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
import qasync
async def main():
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText("Run")
future = None
def run_action():
if future is not None:
future.set_result("run clicked")
button.clicked.connect(run_action)
window.setWindowTitle("Testing async event loop")
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
qasync.run(main())
Upvotes: 3