Welcome to awaitlet’s documentation!

Welcome to awaitlet’s documentation!#

Awaitlet allows non-async defs that invoke awaitables inside of asyncio applications.

awaitlet allows existing programs written to use threads and blocking APIs to be ported to asyncio, by replacing frontend and backend code with asyncio compatible approaches, but allowing intermediary code to remain completely unchanged, with no addition of async or await keywords throughout the entire codebase needed. Its primary use is to support code that is cross-compatible with asyncio and non-asyncio runtime environments.

Awaitlet is a direct extract of SQLAlchemy’s own asyncio mediation layer, with no dependencies on SQLAlchemy (but is also fully cross-compatible with SQLAlchemy’s mediation layer). This code has been in widespread production use in thousands of environments for several years, starting in 2020 with SQLAlchemy 1.4’s first release. The library provides for the identical use case as another library that was first released around the same time as SQLAlchemy 1.4 called greenback, but as part of the SQLAlchemy project is guaranteed to remain cross-compatible with non-blocking SQLAlchemy code.

awaitlet without any dependency or use of SQLAlchemy includes API patterns for:

  • Converting any threaded program (no SQLAlchemy dependency necessary) to use asyncio patterns for front facing APIs and backends, without modifying intermediary code

For applications that do use SQLAlchemy, awaitlet provides additional API patterns for:

  • Converting threaded database-enabled programs to use asyncio patterns for front facing APIs and backends, where those backends use SQLAlchemy’s asyncio API for database access

  • Converting threaded database-enabled programs to use asyncio patterns for front facing APIs and backends, without modifying intermediary code that uses SQLAlchemy’s synchronous API for database access

The two functions provided are async_def() and awaitlet(). Using these, we can create an asyncio program using intermediary defs that do not use the async or await keywords, but instead use functions:

import asyncio

import awaitlet

def asyncio_sleep():
    return awaitlet.awaitlet(asyncio.sleep(5, result='hello'))

print(asyncio.run(awaitlet.async_def(asyncio_sleep)))

Above, the asyncio_sleep() def is run directly in asyncio and calls upon the asyncio.sleep() async API call, but the function itself does not declare itself as async; instead, this is applied functionally using the async_def() function. Through this approach, a program can be made to use asyncio for its front-facing API, talking to asyncio libraries for non-blocking IO patterns, while not impacting intermediary code, which remains compatible with non-asyncio use as well.

For a more complete example see Synopsis.

How does this work?#

The context shift feature of the Python await keyword is made available in a functional way using the greenlet library. The source code for async_def() and awaitlet() are a only a few dozen lines of code, using greenlet to adapt awaitlet() function calls to real Python await keywords.

Contents in this Document#

Indices and tables#