Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b7f067

Browse files
committed
Add pseudo sync mode
1 parent 9f6be15 commit 2b7f067

5 files changed

Lines changed: 47 additions & 15 deletions

File tree

IPython/core/async_helpers.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,33 @@ def _curio_runner(coroutine):
3434
return curio.run(coroutine)
3535

3636

37-
def _trio_runner(function):
37+
def _trio_runner(async_fn):
3838
import trio
3939
async def loc(coro):
4040
"""
4141
We need the dummy no-op async def to protect from
4242
trio's internal. See https://github.com/python-trio/trio/issues/89
4343
"""
4444
return await coro
45-
return trio.run(loc, function)
45+
return trio.run(loc, async_fn)
46+
47+
48+
def _pseudo_sync_runner(coro):
49+
"""
50+
A runner that does not really allow async execution, and just advance the coroutine.
51+
52+
See discussion in https://github.com/python-trio/trio/issues/608,
53+
54+
Credit to Nathaniel Smith
55+
56+
"""
57+
try:
58+
coro.send(None)
59+
except StopIteration as exc:
60+
return exc.value
61+
else:
62+
# TODO: do not raise but return an execution result with the right info.
63+
raise RuntimeError(f"{coro.__name__!r} needs a real async loop")
4664

4765

4866
def _asyncify(code: str) -> str:

IPython/core/interactiveshell.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def removed_co_newlocals(function:types.FunctionType) -> types.FunctionType:
152152

153153
# we still need to run things using the asyncio eventloop, but there is no
154154
# async integration
155-
from .async_helpers import (_asyncio_runner, _asyncify)
155+
from .async_helpers import (_asyncio_runner, _asyncify, _pseudo_sync_runner)
156156

157157
if sys.version_info > (3, 5):
158158
from .async_helpers import _curio_runner, _trio_runner, _should_be_async
@@ -365,9 +365,10 @@ class InteractiveShell(SingletonConfigurable):
365365
).tag(config=True)
366366

367367
loop_runner_map ={
368-
'asyncio':_asyncio_runner,
369-
'curio':_curio_runner,
370-
'trio':_trio_runner,
368+
'asyncio':(_asyncio_runner, True),
369+
'curio':(_curio_runner, True),
370+
'trio':(_trio_runner, True),
371+
'sync': (_pseudo_sync_runner, False)
371372
}
372373

373374
loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
@@ -383,7 +384,9 @@ def _default_loop_runner(self):
383384
def _import_runner(self, proposal):
384385
if isinstance(proposal.value, str):
385386
if proposal.value in self.loop_runner_map:
386-
return self.loop_runner_map[proposal.value]
387+
runner, autoawait = self.loop_runner_map[proposal.value]
388+
self.autoawait = autoawait
389+
return runner
387390
runner = import_item(proposal.value)
388391
if not callable(runner):
389392
raise ValueError('loop_runner must be callable')
@@ -2815,7 +2818,7 @@ def _run_cell(self, raw_cell, store_history, silent, shell_futures):
28152818
)
28162819

28172820
@asyncio.coroutine
2818-
def run_cell_async(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2821+
def run_cell_async(self, raw_cell:str, store_history=False, silent=False, shell_futures=True) -> ExecutionResult:
28192822
"""Run a complete IPython cell asynchronously.
28202823
28212824
Parameters

IPython/core/magics/basic.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,9 +622,14 @@ def autoawait(self, parameter_s):
622622
- asyncio/curio/trio activate autoawait integration and use integration
623623
with said library.
624624
625+
- `sync` turn on the pseudo-sync integration (mostly used for
626+
`IPython.embed()` which does not run IPython with a real eventloop and
627+
deactivate running asynchronous code. Turning on Asynchronous code with
628+
the pseudo sync loop is undefined behavior and may lead IPython to crash.
629+
625630
If the passed parameter does not match any of the above and is a python
626631
identifier, get said object from user namespace and set it as the
627-
runner, and activate autoawait.
632+
runner, and activate autoawait.
628633
629634
If the object is a fully qualified object name, attempt to import it and
630635
set it as the runner, and activate autoawait."""
@@ -647,8 +652,7 @@ def autoawait(self, parameter_s):
647652
return None
648653

649654
if param in self.shell.loop_runner_map:
650-
self.shell.loop_runner = param
651-
self.shell.autoawait = True
655+
self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
652656
return None
653657

654658
if param in self.shell.user_ns :

IPython/terminal/embed.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,9 +383,9 @@ def embed(**kwargs):
383383
config = load_default_config()
384384
config.InteractiveShellEmbed = config.TerminalInteractiveShell
385385
kwargs['config'] = config
386-
using = kwargs.get('using', 'trio')
386+
using = kwargs.get('using', 'sync')
387387
if using :
388-
kwargs['config'].update({'TerminalInteractiveShell':{'loop_runner':using, 'colors':'NoColor'}})
388+
kwargs['config'].update({'TerminalInteractiveShell':{'loop_runner':using, 'colors':'NoColor', 'autoawait': using!='sync'}})
389389
#save ps1/ps2 if defined
390390
ps1 = None
391391
ps2 = None

docs/source/interactive/autoawait.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,15 @@ no network request is done between ``In[1]`` and ``In[2]``.
121121
Effects on IPython.embed()
122122
==========================
123123

124-
IPython core being synchronous, the use of ``IPython.embed()`` will now require
125-
a loop to run. This affect the ability to nest ``IPython.embed()`` which may
124+
IPython core being asynchronous, the use of ``IPython.embed()`` will now require
125+
a loop to run. In order to allow ``IPython.embed()`` to be nested, as most event
126+
loops can't be nested, ``IPython.embed()`` default to a pseudo-synchronous mode,
127+
where async code is not allowed. This mode is available in classical IPython
128+
using ``%autoawait sync``
129+
130+
131+
132+
This affect the ability to nest ``IPython.embed()`` which may
126133
require you to install alternate IO libraries like ``curio`` and ``trio``
127134

128135

0 commit comments

Comments
 (0)