I would like to show my new Python library universalasync: https://github.com/bitcartcc/universalasync
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,
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 @wrap class Client: async def help(self): ... @property async def async_property(self): ... client = Client() def sync_call(): client.help() client.async_property async def async_call(): await client.help() await client.async_property # works in all cases sync_call() asyncio.run(async_call()) threading.Thread(target=sync_call).start() threading.Thread(target=asyncio.run, args=(async_call(),)).start()
API reference can be found here: https://universalasync.bitcartcc.com/en/latest/api.html
Any feedback, testing and bugs found welcome!