diff --git a/IPython/core/async_helpers.py b/IPython/core/async_helpers.py index 1a7d889..fbaae70 100644 --- a/IPython/core/async_helpers.py +++ b/IPython/core/async_helpers.py @@ -42,9 +42,44 @@ def _curio_runner(coroutine): return curio.run(coroutine) +_TRIO_TOKEN = None +_TRIO_NURSERY = None + + +def _init_trio(trio): + global _TRIO_TOKEN + import traceback + import builtins + import threading + + async def trio_entry(): + global _TRIO_TOKEN, _TRIO_NURSERY + _TRIO_TOKEN = trio.hazmat.current_trio_token() + async with trio.open_nursery() as nursery: + _TRIO_NURSERY = nursery + builtins.GLOBAL_NURSERY = nursery + await trio.sleep_forever() + + def trio_entry_sync(): + while True: + try: + trio.run(trio_entry) + except Exception: + print("Exception in trio event loop:", traceback.format_exc()) + + threading.Thread(target=trio_entry_sync).start() + #TODO fix this race condition + import time + while not _TRIO_TOKEN: + time.sleep(0.1) + + def _trio_runner(async_fn): import trio + if not _TRIO_TOKEN: + _init_trio(trio) + async def loc(coro): """ We need the dummy no-op async def to protect from @@ -52,7 +87,7 @@ def _trio_runner(async_fn): """ return await coro - return trio.run(loc, async_fn) + return trio.from_thread.run(loc, async_fn, trio_token=_TRIO_TOKEN) def _pseudo_sync_runner(coro): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index d8bb3e5..6a4fc43 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2865,7 +2865,7 @@ class InteractiveShell(SingletonConfigurable): # when this is the case, we want to run it using the pseudo_sync_runner # so that code can invoke eventloops (for example via the %run , and # `%paste` magic. - if self.should_run_async(raw_cell): + if self.should_run_async(raw_cell) or self.loop_runner is _trio_runner: runner = self.loop_runner else: runner = _pseudo_sync_runner