qasync
qasync is a Python library for using asyncio in Qt-based applications, allowing developers to seamlessly integrate asynchronous code into their Qt GUI projects. It is currently at version 0.28.0 and maintains a regular release cadence with updates for new Python versions and performance improvements.
Warnings
- breaking Support for Python 3.6 and Python 3.7 was dropped starting with version 0.25.0. Ensure your project is using Python 3.8 or newer.
- gotcha qasync does not automatically install a Qt binding. You must explicitly install one (e.g., PyQt5, PyQt6, PySide2, or PySide6) in your environment for qasync to function.
- deprecated Version 0.27.0 was released with a critical bug. It is strongly recommended to use version 0.27.1 or any later version instead.
- gotcha The `asyncio.set_event_loop_policy(QEventLoopPolicy())` call MUST be made before instantiating the `QApplication` (or `QAsyncApplication`) object. Failing to do so will result in `asyncio` not being properly integrated with Qt's event loop, leading to unexpected behavior or errors.
- gotcha When connecting an asynchronous Python function (a coroutine) to a Qt signal, you must wrap it with the `@asyncSlot()` decorator. Connecting async functions directly without this decorator will raise a `TypeError`.
Install
-
pip install qasync
Imports
- QEventLoopPolicy
from qasync import QEventLoopPolicy
- asyncSlot
from qasync import asyncSlot
- asyncClose
from qasync import asyncClose
- QAsyncApplication
from qasync import QApplication
from qasync import QAsyncApplication
Quickstart
import asyncio
import sys
# Choose your Qt binding: PyQt5, PyQt6, PySide2, PySide6
# For this example, we'll use PyQt5
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, QPushButton
from qasync import QEventLoopPolicy, asyncSlot
async def long_running_task(duration_seconds: int = 2):
"""A mock asynchronous task."""
print(f"[Task] Starting long-running task for {duration_seconds} seconds...")
await asyncio.sleep(duration_seconds)
print("[Task] Long-running task finished!")
return "Task Completed!"
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("qasync Quickstart Demo")
self.setGeometry(100, 100, 400, 200)
self.layout = QVBoxLayout()
self.label = QLabel("Click the button to start an async task.")
self.button = QPushButton("Run Async Task")
# Connect a Qt signal to an asynchronous slot using @asyncSlot
self.button.clicked.connect(self.run_task)
self.layout.addWidget(self.label)
self.layout.addWidget(self.button)
self.setLayout(self.layout)
@asyncSlot()
async def run_task(self):
"""This slot runs an async task without blocking the GUI."""
self.label.setText("Task started, please wait...")
self.button.setEnabled(False) # Disable button while task is running
result = await long_running_task(3) # Await the async task
self.label.setText(f"Result: {result}")
self.button.setEnabled(True) # Re-enable button
if __name__ == "__main__":
# IMPORTANT: Set the asyncio event loop policy *before* creating QApplication
asyncio.set_event_loop_policy(QEventLoopPolicy())
app = QApplication(sys.argv)
window = MainWindow()
window.show()
# Run the Qt application
sys.exit(app.exec_())