DEV Community


Posted on

Universalasync – create sync and async libraries at the same time maintaining one codebase

I would like to show my new Python library universalasync:

The problem

Async/await is become more and more popular in python and it makes sense to use it quite often to do something useful when waiting on network I/O. But it is not possible to use blocking (sync) libraries as it would block the whole event loop and defeat the purpose of asynchronous programming. So specialized libraries need to be created. In the same time, async is not always required, so a sync interface is demanded often for all the libraries.
For the library maintainers (like me) it causes an issue what to do. Often we need to maintain two codebases which differ only a little bit.

Some libraries create async_* variants of functions, or create classes like AsyncClient or use other methods of creating sync versions (for example in my another library some time ago I was just removing async and await and publishing this as a separate package, mylib and mylib-async).
The solution

The universalasync library provides utilities to help library maintainers create so-called "universal" libraries. You need to create only asynchronous version of your library, and synchronous version will be created automatically, so that users could use it in their sync and async apps interchangeably.

The library has 0 dependencies of course, it wraps all public methods of a class to it's implementation. It basically does what you would have done if you needed to run a coroutine from your sync code, but automatically.


from universalasync import wrap

class Client:
    async def help(self):

    async def async_property(self):

client = Client()

def sync_call():

async def async_call():
    await client.async_property

# works in all cases
threading.Thread(, args=(async_call(),)).start()
Enter fullscreen mode Exit fullscreen mode

API reference can be found here:

Any feedback, testing and bugs found welcome!

Top comments (0)