Skip to content

run_sync handles RuntimeError raised by coroutine incorrectly #424

Closed
@hugokerstens

Description

@hugokerstens

Problem

The function jupyter_core.utils.run_sync mistakenly catches a RuntimeError raised by a coroutine and assumes no event loop is running.

If a coroutine handled by run_sync raises a RuntimeError while an event loop is running, it assumes the RuntimeError comes from asyncio.get_running_loop(). This causes calling any coroutine that raises a RuntimeError to raise an error that no event loop is running, since run_sync will attempt to set a new event loop.

How to reproduce

Open a jupyter notebook, or any other context where an event loop is already running. Execute this code:

from jupyter_core.utils import run_sync
async def f():
    raise RuntimeError("My runtime error")

run_sync(f)()

Output

The code raises a RuntimeError: This event loop is already running

Full traceback
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[32], line 5
      2 async def f():
      3     raise RuntimeError
----> 5 run_sync(f)()

File [/opt/conda/lib/python3.9/site-packages/jupyter_core/utils/__init__.py:165](http://localhost:8888/opt/conda/lib/python3.9/site-packages/jupyter_core/utils/__init__.py#line=164), in run_sync.<locals>.wrapped(*args, **kwargs)
    163 # Run the loop for this thread.
    164 loop = ensure_event_loop()
--> 165 return loop.run_until_complete(inner)

File [/opt/conda/lib/python3.9/asyncio/base_events.py:623](http://localhost:8888/opt/conda/lib/python3.9/asyncio/base_events.py#line=622), in BaseEventLoop.run_until_complete(self, future)
    612 """Run until the Future is done.
    613 
    614 If the argument is a coroutine, it is wrapped in a Task.
   (...)
    620 Return the Future's result, or raise its exception.
    621 """
    622 self._check_closed()
--> 623 self._check_running()
    625 new_task = not futures.isfuture(future)
    626 future = tasks.ensure_future(future, loop=self)

File [/opt/conda/lib/python3.9/asyncio/base_events.py:583](http://localhost:8888/opt/conda/lib/python3.9/asyncio/base_events.py#line=582), in BaseEventLoop._check_running(self)
    581 def _check_running(self):
    582     if self.is_running():
--> 583         raise RuntimeError('This event loop is already running')
    584     if events._get_running_loop() is not None:
    585         raise RuntimeError(
    586             'Cannot run the event loop while another loop is running')

RuntimeError: This event loop is already running

Expected output

The code should raise RuntimeError: My runtime error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions