diff --git a/devlib/utils/asyn.py b/devlib/utils/asyn.py index c0e415612..1fac5fd94 100644 --- a/devlib/utils/asyn.py +++ b/devlib/utils/asyn.py @@ -27,17 +27,7 @@ import os.path import inspect -# Allow nesting asyncio loops, which is necessary for: -# * Being able to call the blocking variant of a function from an async -# function for backward compat -# * Critically, run the blocking variant of a function in a Jupyter notebook -# environment, since it also uses asyncio. -# -# Maybe there is still hope for future versions of Python though: -# https://bugs.python.org/issue22239 -import nest_asyncio -nest_asyncio.apply() - +import greenback def create_task(awaitable, name=None): if isinstance(awaitable, asyncio.Task): @@ -291,13 +281,26 @@ def __set__(self, obj, value): def __set_name__(self, owner, name): self.name = name - def run(coro): """ Similar to :func:`asyncio.run` but can be called while an event loop is running. """ - return asyncio.run(coro) + try: + asyncio.get_running_loop() + except RuntimeError: + # We are not currently running an event loop, so it's ok to just use + # asyncio.run() and let it create one + async def f(): + await greenback.ensure_portal() + return await coro + return asyncio.run(f()) + else: + # We are currently running an event loop, so we need greenback to + # re-enter the event loop, as this is not supported in the standard + # library: + # https://github.com/python/cpython/issues/66435 + return greenback.await_(coro) def asyncf(f): diff --git a/setup.py b/setup.py index e8b7d0fbe..7013128d6 100644 --- a/setup.py +++ b/setup.py @@ -104,7 +104,7 @@ def _load_path(filepath): 'pandas', 'pytest', 'lxml', # More robust xml parsing - 'nest_asyncio', # Allows running nested asyncio loops + 'greenback', # Allows running nested asyncio loops 'future', # for the "past" Python package 'ruamel.yaml >= 0.15.72', # YAML formatted config parsing ],