QtAsyncio developer notes

QtAsyncio is a module that provides integration between Qt and Python’s asyncio module. It allows you to run asyncio event loops in a Qt application, and to use Qt APIs from asyncio coroutines.

As a pure Python module that integrates deeply with another Python module, developing for QtAsyncio has some interesting aspects that differ from other parts of Qt for Python.

QtAsyncio vs asyncio

QtAsyncio has an interesting property from a developer perspective. As one of its purposes is to be a transparent replacement to asyncio’s own event loop, for any given code that uses asyncio APIs, QtAsyncio will (or should!) behave identically to asyncio. (Note that the reverse does not apply if we also have Qt code). This is especially handy when debugging, as one can run the asyncio code to compare and to check the expected behavior. It also helps to debug both QtAsyncio and asyncio step by step and compare the program flow to find where QtAsyncio might go wrong (as far as their code differences allow). Often, one will also be able to implement a unit test by asserting that QtAsyncio’s output is identical to asyncio’s. (Note that a limitation to this is the fact that Qt’s event loop does not guarantee the order of execution of callbacks, while asyncio does.)

The step function

When debugging, a significant amount of time will likely be spent inside the _step method of the QAsyncioTask class, as it is called often and it is where coroutines are executed. You will find that it is similar to asyncio’s equivalent method, but with some differences. Read the in-line comments carefully. Some variables and associated lines of code might seem innocuous or even unnecessary, but provide important bug fixes.

Keeping QtAsyncio in sync with asyncio

QtAsyncio implements asyncio’s API, which can change with new releases. As it is part of the standard library, this lines up with new Python versions. It is therefore good practice to check whether the API has changed for every new Python version. This can include new classes or methods, changed signatures for existing functions, deprecations or outright removals. For example, event loop policies are expected to be deprecated with Python 3.13, with subsequent removal in Python 3.15. This removal will in turn require a small refactoring to make sure the QtAsyncio.run() function no longer uses the policy mechanism.

asyncio developer guidance

asyncio’s resources go beyond the pure API documentation. E.g., asyncio provides its own developer guidance that is worth following when developing for QtAsyncio. In addition, there is documentation for extending asyncio that details a few essential points to keep in mind when building your own event loop.