##// END OF EJS Templates
fix docs
Matthias Bussonnier -
Show More
@@ -1,186 +1,185 b''
1
1 .. _autoawait:
2 .. autoawait:
3
2
4 Asynchronous in REPL: Autoawait
3 Asynchronous in REPL: Autoawait
5 ===============================
4 ===============================
6
5
7 Starting with IPython 6.0, and when user Python 3.6 and above, IPython offer the
6 Starting with IPython 6.0, and when user Python 3.6 and above, IPython offer the
8 ability to run asynchronous code from the REPL. constructs which are
7 ability to run asynchronous code from the REPL. constructs which are
9 :exc:`SyntaxError` s in the Python REPL can be used seamlessly in IPython.
8 :exc:`SyntaxError` s in the Python REPL can be used seamlessly in IPython.
10
9
11 When a supported libray is used, IPython will automatically `await` Futures
10 When a supported libray is used, IPython will automatically `await` Futures
12 and Coroutines in the REPL. This will happen if an :ref:`await <await>` (or `async`) is
11 and Coroutines in the REPL. This will happen if an :ref:`await <await>` (or `async`) is
13 use at top level scope, or if any structure valid only in `async def
12 use at top level scope, or if any structure valid only in `async def
14 <https://docs.python.org/3/reference/compound_stmts.html#async-def>`_ function
13 <https://docs.python.org/3/reference/compound_stmts.html#async-def>`_ function
15 context are present. For example, the following being a syntax error in the
14 context are present. For example, the following being a syntax error in the
16 Python REPL::
15 Python REPL::
17
16
18 Python 3.6.0
17 Python 3.6.0
19 [GCC 4.2.1]
18 [GCC 4.2.1]
20 Type "help", "copyright", "credits" or "license" for more information.
19 Type "help", "copyright", "credits" or "license" for more information.
21 >>> import aiohttp
20 >>> import aiohttp
22 >>> result = aiohttp.get('https://api.github.com')
21 >>> result = aiohttp.get('https://api.github.com')
23 >>> response = await result
22 >>> response = await result
24 File "<stdin>", line 1
23 File "<stdin>", line 1
25 response = await result
24 response = await result
26 ^
25 ^
27 SyntaxError: invalid syntax
26 SyntaxError: invalid syntax
28
27
29 Should behave as expected in the IPython REPL::
28 Should behave as expected in the IPython REPL::
30
29
31 Python 3.6.0
30 Python 3.6.0
32 Type 'copyright', 'credits' or 'license' for more information
31 Type 'copyright', 'credits' or 'license' for more information
33 IPython 6.0.0.dev -- An enhanced Interactive Python. Type '?' for help.
32 IPython 6.0.0.dev -- An enhanced Interactive Python. Type '?' for help.
34
33
35 In [1]: import aiohttp
34 In [1]: import aiohttp
36 ...: result = aiohttp.get('https://api.github.com')
35 ...: result = aiohttp.get('https://api.github.com')
37
36
38 In [2]: response = await result
37 In [2]: response = await result
39 <pause for a few 100s ms>
38 <pause for a few 100s ms>
40
39
41 In [3]: await response.json()
40 In [3]: await response.json()
42 Out[3]:
41 Out[3]:
43 {'authorizations_url': 'https://api.github.com/authorizations',
42 {'authorizations_url': 'https://api.github.com/authorizations',
44 'code_search_url': 'https://api.github.com/search/code?q={query}...',
43 'code_search_url': 'https://api.github.com/search/code?q={query}...',
45 ...
44 ...
46 }
45 }
47
46
48
47
49 You can use the ``c.InteractiveShell.autoawait`` configuration option and set it
48 You can use the ``c.InteractiveShell.autoawait`` configuration option and set it
50 to :any:`False` to deactivate automatic wrapping of asynchronous code. You can also
49 to :any:`False` to deactivate automatic wrapping of asynchronous code. You can also
51 use the :magic:`%autoawait` magic to toggle the behavior at runtime::
50 use the :magic:`%autoawait` magic to toggle the behavior at runtime::
52
51
53 In [1]: %autoawait False
52 In [1]: %autoawait False
54
53
55 In [2]: %autoawait
54 In [2]: %autoawait
56 IPython autoawait is `Off`, and set to use `IPython.core.interactiveshell._asyncio_runner`
55 IPython autoawait is `Off`, and set to use `IPython.core.interactiveshell._asyncio_runner`
57
56
58
57
59
58
60 By default IPython will assume integration with Python's provided
59 By default IPython will assume integration with Python's provided
61 :mod:`asyncio`, but integration with other libraries is provided. In particular
60 :mod:`asyncio`, but integration with other libraries is provided. In particular
62 we provide experimental integration with the ``curio`` and ``trio`` library.
61 we provide experimental integration with the ``curio`` and ``trio`` library.
63
62
64 You can switch current integration by using the
63 You can switch current integration by using the
65 ``c.InteractiveShell.loop_runner`` option or the ``autoawait <name
64 ``c.InteractiveShell.loop_runner`` option or the ``autoawait <name
66 integration>`` magic.
65 integration>`` magic.
67
66
68 For example::
67 For example::
69
68
70 In [1]: %autoawait trio
69 In [1]: %autoawait trio
71
70
72 In [2]: import trio
71 In [2]: import trio
73
72
74 In [3]: async def child(i):
73 In [3]: async def child(i):
75 ...: print(" child %s goes to sleep"%i)
74 ...: print(" child %s goes to sleep"%i)
76 ...: await trio.sleep(2)
75 ...: await trio.sleep(2)
77 ...: print(" child %s wakes up"%i)
76 ...: print(" child %s wakes up"%i)
78
77
79 In [4]: print('parent start')
78 In [4]: print('parent start')
80 ...: async with trio.open_nursery() as n:
79 ...: async with trio.open_nursery() as n:
81 ...: for i in range(5):
80 ...: for i in range(5):
82 ...: n.spawn(child, i)
81 ...: n.spawn(child, i)
83 ...: print('parent end')
82 ...: print('parent end')
84 parent start
83 parent start
85 child 2 goes to sleep
84 child 2 goes to sleep
86 child 0 goes to sleep
85 child 0 goes to sleep
87 child 3 goes to sleep
86 child 3 goes to sleep
88 child 1 goes to sleep
87 child 1 goes to sleep
89 child 4 goes to sleep
88 child 4 goes to sleep
90 <about 2 seconds pause>
89 <about 2 seconds pause>
91 child 2 wakes up
90 child 2 wakes up
92 child 1 wakes up
91 child 1 wakes up
93 child 0 wakes up
92 child 0 wakes up
94 child 3 wakes up
93 child 3 wakes up
95 child 4 wakes up
94 child 4 wakes up
96 parent end
95 parent end
97
96
98
97
99 In the above example, ``async with`` at top level scope is a syntax error in
98 In the above example, ``async with`` at top level scope is a syntax error in
100 Python.
99 Python.
101
100
102 Using this mode can have unexpected consequences if used in interaction with
101 Using this mode can have unexpected consequences if used in interaction with
103 other features of IPython and various registered extensions. In particular if you
102 other features of IPython and various registered extensions. In particular if you
104 are a direct or indirect user of the AST transformers, these may not apply to
103 are a direct or indirect user of the AST transformers, these may not apply to
105 your code.
104 your code.
106
105
107 The default loop, or runner does not run in the background, so top level
106 The default loop, or runner does not run in the background, so top level
108 asynchronous code must finish for the REPL to allow you to enter more code. As
107 asynchronous code must finish for the REPL to allow you to enter more code. As
109 with usual Python semantic, the awaitables are started only when awaited for the
108 with usual Python semantic, the awaitables are started only when awaited for the
110 first time. That is to say, in first example, no network request is done between
109 first time. That is to say, in first example, no network request is done between
111 ``In[1]`` and ``In[2]``.
110 ``In[1]`` and ``In[2]``.
112
111
113
112
114 Internals
113 Internals
115 =========
114 =========
116
115
117 As running asynchronous code is not supported in interactive REPL as of Python
116 As running asynchronous code is not supported in interactive REPL as of Python
118 3.6 we have to rely to a number of complex workaround to allow this to happen.
117 3.6 we have to rely to a number of complex workaround to allow this to happen.
119 It is interesting to understand how this works in order to understand potential
118 It is interesting to understand how this works in order to understand potential
120 bugs, or provide a custom runner.
119 bugs, or provide a custom runner.
121
120
122 Among the many approaches that are at our disposition, we find only one that
121 Among the many approaches that are at our disposition, we find only one that
123 suited out need. Under the hood we :ct the code object from a async-def function
122 suited out need. Under the hood we :ct the code object from a async-def function
124 and run it in global namesapace after modifying the ``__code__`` object.::
123 and run it in global namesapace after modifying the ``__code__`` object.::
125
124
126 async def inner_async():
125 async def inner_async():
127 locals().update(**global_namespace)
126 locals().update(**global_namespace)
128 #
127 #
129 # here is user code
128 # here is user code
130 #
129 #
131 return last_user_statement
130 return last_user_statement
132 codeobj = modify(inner_async.__code__)
131 codeobj = modify(inner_async.__code__)
133 coroutine = eval(codeobj, user_ns)
132 coroutine = eval(codeobj, user_ns)
134 display(loop_runner(coroutine))
133 display(loop_runner(coroutine))
135
134
136
135
137
136
138 The first thing you'll notice is that unlike classical ``exec``, there is only
137 The first thing you'll notice is that unlike classical ``exec``, there is only
139 one name space. Second, user code runs in a function scope, and not a module
138 one name space. Second, user code runs in a function scope, and not a module
140 scope.
139 scope.
141
140
142 On top of the above there are significant modification to the AST of
141 On top of the above there are significant modification to the AST of
143 ``function``, and ``loop_runner`` can be arbitrary complex. So there is a
142 ``function``, and ``loop_runner`` can be arbitrary complex. So there is a
144 significant overhead to this kind of code.
143 significant overhead to this kind of code.
145
144
146 By default the generated coroutine function will be consumed by Asyncio's
145 By default the generated coroutine function will be consumed by Asyncio's
147 ``loop_runner = asyncio.get_evenloop().run_until_complete()`` method. It is
146 ``loop_runner = asyncio.get_evenloop().run_until_complete()`` method. It is
148 though possible to provide your own.
147 though possible to provide your own.
149
148
150 A loop runner is a *synchronous* function responsible from running a coroutine
149 A loop runner is a *synchronous* function responsible from running a coroutine
151 object.
150 object.
152
151
153 The runner is responsible from ensuring that ``coroutine`` run to completion,
152 The runner is responsible from ensuring that ``coroutine`` run to completion,
154 and should return the result of executing the coroutine. Let's write a
153 and should return the result of executing the coroutine. Let's write a
155 runner for ``trio`` that print a message when used as an exercise, ``trio`` is
154 runner for ``trio`` that print a message when used as an exercise, ``trio`` is
156 special as it usually prefer to run a function object and make a coroutine by
155 special as it usually prefer to run a function object and make a coroutine by
157 itself, we can get around this limitation by wrapping it in an async-def without
156 itself, we can get around this limitation by wrapping it in an async-def without
158 parameters and passing this value to ``trio``::
157 parameters and passing this value to ``trio``::
159
158
160
159
161 In [1]: import trio
160 In [1]: import trio
162 ...: from types import CoroutineType
161 ...: from types import CoroutineType
163 ...:
162 ...:
164 ...: def trio_runner(coro:CoroutineType):
163 ...: def trio_runner(coro:CoroutineType):
165 ...: print('running asynchronous code')
164 ...: print('running asynchronous code')
166 ...: async def corowrap(coro):
165 ...: async def corowrap(coro):
167 ...: return await coro
166 ...: return await coro
168 ...: return trio.run(corowrap, coro)
167 ...: return trio.run(corowrap, coro)
169
168
170 We can set it up by passing it to ``%autoawait``::
169 We can set it up by passing it to ``%autoawait``::
171
170
172 In [2]: %autoawait trio_runner
171 In [2]: %autoawait trio_runner
173
172
174 In [3]: async def async_hello(name):
173 In [3]: async def async_hello(name):
175 ...: await trio.sleep(1)
174 ...: await trio.sleep(1)
176 ...: print(f'Hello {name} world !')
175 ...: print(f'Hello {name} world !')
177 ...: await trio.sleep(1)
176 ...: await trio.sleep(1)
178
177
179 In [4]: await async_hello('async')
178 In [4]: await async_hello('async')
180 running asynchronous code
179 running asynchronous code
181 Hello async world !
180 Hello async world !
182
181
183
182
184 Asynchronous programming in python (and in particular in the REPL) is still a
183 Asynchronous programming in python (and in particular in the REPL) is still a
185 relatively young subject. Feel free to contribute improvements to this codebase
184 relatively young subject. Feel free to contribute improvements to this codebase
186 and give us feedback.
185 and give us feedback.
General Comments 0
You need to be logged in to leave comments. Login now