##// END OF EJS Templates
Add pseudo sync mode
Matthias Bussonnier -
Show More
@@ -34,7 +34,7 b' def _curio_runner(coroutine):'
34 return curio.run(coroutine)
34 return curio.run(coroutine)
35
35
36
36
37 def _trio_runner(function):
37 def _trio_runner(async_fn):
38 import trio
38 import trio
39 async def loc(coro):
39 async def loc(coro):
40 """
40 """
@@ -42,7 +42,25 b' def _trio_runner(function):'
42 trio's internal. See https://github.com/python-trio/trio/issues/89
42 trio's internal. See https://github.com/python-trio/trio/issues/89
43 """
43 """
44 return await coro
44 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")
46
64
47
65
48 def _asyncify(code: str) -> str:
66 def _asyncify(code: str) -> str:
@@ -152,7 +152,7 b' def removed_co_newlocals(function:types.FunctionType) -> types.FunctionType:'
152
152
153 # we still need to run things using the asyncio eventloop, but there is no
153 # we still need to run things using the asyncio eventloop, but there is no
154 # async integration
154 # async integration
155 from .async_helpers import (_asyncio_runner, _asyncify)
155 from .async_helpers import (_asyncio_runner, _asyncify, _pseudo_sync_runner)
156
156
157 if sys.version_info > (3, 5):
157 if sys.version_info > (3, 5):
158 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
158 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
@@ -365,9 +365,10 b' class InteractiveShell(SingletonConfigurable):'
365 ).tag(config=True)
365 ).tag(config=True)
366
366
367 loop_runner_map ={
367 loop_runner_map ={
368 'asyncio':_asyncio_runner,
368 'asyncio':(_asyncio_runner, True),
369 'curio':_curio_runner,
369 'curio':(_curio_runner, True),
370 'trio':_trio_runner,
370 'trio':(_trio_runner, True),
371 'sync': (_pseudo_sync_runner, False)
371 }
372 }
372
373
373 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
374 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
@@ -383,7 +384,9 b' class InteractiveShell(SingletonConfigurable):'
383 def _import_runner(self, proposal):
384 def _import_runner(self, proposal):
384 if isinstance(proposal.value, str):
385 if isinstance(proposal.value, str):
385 if proposal.value in self.loop_runner_map:
386 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
387 runner = import_item(proposal.value)
390 runner = import_item(proposal.value)
388 if not callable(runner):
391 if not callable(runner):
389 raise ValueError('loop_runner must be callable')
392 raise ValueError('loop_runner must be callable')
@@ -2815,7 +2818,7 b' class InteractiveShell(SingletonConfigurable):'
2815 )
2818 )
2816
2819
2817 @asyncio.coroutine
2820 @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:
2819 """Run a complete IPython cell asynchronously.
2822 """Run a complete IPython cell asynchronously.
2820
2823
2821 Parameters
2824 Parameters
@@ -622,9 +622,14 b' class AsyncMagics(BasicMagics):'
622 - asyncio/curio/trio activate autoawait integration and use integration
622 - asyncio/curio/trio activate autoawait integration and use integration
623 with said library.
623 with said library.
624
624
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
625 If the passed parameter does not match any of the above and is a python
630 If the passed parameter does not match any of the above and is a python
626 identifier, get said object from user namespace and set it as the
631 identifier, get said object from user namespace and set it as the
627 runner, and activate autoawait.
632 runner, and activate autoawait.
628
633
629 If the object is a fully qualified object name, attempt to import it and
634 If the object is a fully qualified object name, attempt to import it and
630 set it as the runner, and activate autoawait."""
635 set it as the runner, and activate autoawait."""
@@ -647,8 +652,7 b' class AsyncMagics(BasicMagics):'
647 return None
652 return None
648
653
649 if param in self.shell.loop_runner_map:
654 if param in self.shell.loop_runner_map:
650 self.shell.loop_runner = param
655 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
651 self.shell.autoawait = True
652 return None
656 return None
653
657
654 if param in self.shell.user_ns :
658 if param in self.shell.user_ns :
@@ -383,9 +383,9 b' def embed(**kwargs):'
383 config = load_default_config()
383 config = load_default_config()
384 config.InteractiveShellEmbed = config.TerminalInteractiveShell
384 config.InteractiveShellEmbed = config.TerminalInteractiveShell
385 kwargs['config'] = config
385 kwargs['config'] = config
386 using = kwargs.get('using', 'trio')
386 using = kwargs.get('using', 'sync')
387 if using :
387 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'}})
389 #save ps1/ps2 if defined
389 #save ps1/ps2 if defined
390 ps1 = None
390 ps1 = None
391 ps2 = None
391 ps2 = None
@@ -121,8 +121,15 b' no network request is done between ``In[1]`` and ``In[2]``.'
121 Effects on IPython.embed()
121 Effects on IPython.embed()
122 ==========================
122 ==========================
123
123
124 IPython core being synchronous, the use of ``IPython.embed()`` will now require
124 IPython core being asynchronous, the use of ``IPython.embed()`` will now require
125 a loop to run. This affect the ability to nest ``IPython.embed()`` which may
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
126 require you to install alternate IO libraries like ``curio`` and ``trio``
133 require you to install alternate IO libraries like ``curio`` and ``trio``
127
134
128
135
General Comments 0
You need to be logged in to leave comments. Login now