In the context of migrating away from nest_asyncio, I ended up using greenback. In order to support cases where the user 1. executes code (including imports) in a pre-existing asyncio Task (jupyterlab notebook) and 2. with non-stdlib event loops (uvloop when using gunicorn), the least intrusive setup seemed to be creating an internal thread running an event loop that:
The project has full control on (since it's not exposed directly)
Has a custom event loop that overrides create_task() to to wrap all coroutines with:
This way it can achieve a result similar to with_portal_run_tree() on asyncio, as all Tasks created by this event loop will be portaled appropriately.
If a turnkey high-level solution is in the scope of greenback, this makes it possible to provide an implementation of asyncio.run() that is re-entrant, achieving the same result as nest_asyncio (with an extra thread, but working for any asyncio event loop rather than just the stdlib implementations).
Note: wrapping an event loop into another class requires some __getattribute__ tricks, as asyncio.AbstractEventLoop provides a default implementation of all (?) methods that just raise. This makes it impossible to use __getattr__ to delegate non-overridden calls to the wrapped loop, see our _GreenbackEventLoop implementation.
Feature request
In the context of migrating away from
nest_asyncio
, I ended up usinggreenback
. In order to support cases where the user 1. executes code (including imports) in a pre-existing asyncio Task (jupyterlab notebook) and 2. with non-stdlib event loops (uvloop when using gunicorn), the least intrusive setup seemed to be creating an internal thread running an event loop that:create_task()
to to wrap all coroutines with:This way it can achieve a result similar to
with_portal_run_tree()
on asyncio, as all Tasks created by this event loop will be portaled appropriately.If a turnkey high-level solution is in the scope of greenback, this makes it possible to provide an implementation of
asyncio.run()
that is re-entrant, achieving the same result asnest_asyncio
(with an extra thread, but working for any asyncio event loop rather than just the stdlib implementations).An implementation (including the re-entrant
run()
function) is available here: https://github.com/ARM-software/devlib/pull/683/filesNote: wrapping an event loop into another class requires some
__getattribute__
tricks, asasyncio.AbstractEventLoop
provides a default implementation of all (?) methods that just raise. This makes it impossible to use__getattr__
to delegate non-overridden calls to the wrapped loop, see our_GreenbackEventLoop
implementation.