aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/terminal/pt_inputhooks/asyncio.py
blob: 44d480527d6b076c58d013138c9d0934366100d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
""" 
Inputhook for running the original asyncio event loop while we're waiting for 
input. 
 
By default, in IPython, we run the prompt with a different asyncio event loop, 
because otherwise we risk that people are freezing the prompt by scheduling bad 
coroutines. E.g., a coroutine that does a while/true and never yield back 
control to the loop. We can't cancel that. 
 
However, sometimes we want the asyncio loop to keep running while waiting for 
a prompt. 
 
The following example will print the numbers from 1 to 10 above the prompt, 
while we are waiting for input. (This works also because we use 
prompt_toolkit`s `patch_stdout`):: 
 
    In [1]: import asyncio 
 
    In [2]: %gui asyncio 
 
    In [3]: async def f(): 
       ...:     for i in range(10): 
       ...:         await asyncio.sleep(1) 
       ...:         print(i) 
 
 
    In [4]: asyncio.ensure_future(f()) 
 
""" 
import asyncio 
from prompt_toolkit import __version__ as ptk_version 
 
PTK3 = ptk_version.startswith('3.') 
 
 
# Keep reference to the original asyncio loop, because getting the event loop 
# within the input hook would return the other loop. 
loop = asyncio.get_event_loop() 
 
 
def inputhook(context): 
    """ 
    Inputhook for asyncio event loop integration. 
    """ 
    # For prompt_toolkit 3.0, this input hook literally doesn't do anything. 
    # The event loop integration here is implemented in `interactiveshell.py` 
    # by running the prompt itself in the current asyncio loop. The main reason 
    # for this is that nesting asyncio event loops is unreliable. 
    if PTK3: 
        return 
 
    # For prompt_toolkit 2.0, we can run the current asyncio event loop, 
    # because prompt_toolkit 2.0 uses a different event loop internally. 
 
    def stop(): 
        loop.stop() 
 
    fileno = context.fileno() 
    loop.add_reader(fileno, stop) 
    try: 
        loop.run_forever() 
    finally: 
        loop.remove_reader(fileno)