##// END OF EJS Templates
doc, remove appveyor 3.4
Matthias Bussonnier -
Show More
@@ -1,95 +1,96 b''
1 """
1 """
2 Async helper function that are invalid syntax on Python 3.5 and below.
2 Async helper function that are invalid syntax on Python 3.5 and below.
3
3
4 Known limitation and possible improvement.
4 Known limitation and possible improvement.
5
5
6 Top level code that contain a return statement (instead of, or in addition to
6 Top level code that contain a return statement (instead of, or in addition to
7 await) will be detected as requiring being wrapped in async calls. This should
7 await) will be detected as requiring being wrapped in async calls. This should
8 be prevented as early return will not work.
8 be prevented as early return will not work.
9 """
9 """
10
10
11
11
12 import ast
12 import ast
13 import sys
13 import sys
14 import inspect
14 import inspect
15 from textwrap import dedent, indent
15 from textwrap import dedent, indent
16 from types import CodeType
16 from types import CodeType
17
17
18
18
19 def _asyncio_runner(coro):
19 def _asyncio_runner(coro):
20 """
20 """
21 Handler for asyncio autoawait
21 Handler for asyncio autoawait
22 """
22 """
23 import asyncio
23 import asyncio
24
24
25 return asyncio.get_event_loop().run_until_complete(coro)
25 return asyncio.get_event_loop().run_until_complete(coro)
26
26
27
27
28 def _curio_runner(coroutine):
28 def _curio_runner(coroutine):
29 """
29 """
30 handler for curio autoawait
30 handler for curio autoawait
31 """
31 """
32 import curio
32 import curio
33
33
34 return curio.run(coroutine)
34 return curio.run(coroutine)
35
35
36
36
37 if sys.version_info > (3, 5):
37 if sys.version_info > (3, 5):
38 # nose refuses to avoid this file and async def is invalidsyntax
38 # nose refuses to avoid this file and async def is invalidsyntax
39 s = dedent(
39 s = dedent(
40 '''
40 '''
41 def _trio_runner(function):
41 def _trio_runner(function):
42 import trio
42 import trio
43 async def loc(coro):
43 async def loc(coro):
44 """
44 """
45 We need the dummy no-op async def to protect from
45 We need the dummy no-op async def to protect from
46 trio's internal. See https://github.com/python-trio/trio/issues/89
46 trio's internal. See https://github.com/python-trio/trio/issues/89
47 """
47 """
48 return await coro
48 return await coro
49 return trio.run(loc, function)
49 return trio.run(loc, function)
50 '''
50 '''
51 )
51 )
52 exec(s, globals(), locals())
52 exec(s, globals(), locals())
53
53
54
54
55 def _asyncify(code: str) -> str:
55 def _asyncify(code: str) -> str:
56 """wrap code in async def definition.
56 """wrap code in async def definition.
57
57
58 And setup a bit of context to run it later.
58 And setup a bit of context to run it later.
59 """
59 """
60 res = dedent(
60 res = dedent(
61 """
61 """
62 async def __wrapper__():
62 async def __wrapper__():
63 try:
63 try:
64 {usercode}
64 {usercode}
65 finally:
65 finally:
66 locals()
66 locals()
67 """
67 """
68 ).format(usercode=indent(code, " " * 8)[8:])
68 ).format(usercode=indent(code, " " * 8)[8:])
69 return res
69 return res
70
70
71
71
72 def _should_be_async(cell: str) -> bool:
72 def _should_be_async(cell: str) -> bool:
73 """Detect if a block of code need to be wrapped in an `async def`
73 """Detect if a block of code need to be wrapped in an `async def`
74
74
75 Attempt to parse the block of code, it it compile we're fine.
75 Attempt to parse the block of code, it it compile we're fine.
76 Otherwise we wrap if and try to compile.
76 Otherwise we wrap if and try to compile.
77
77
78 If it works, assume it should be async. Otherwise Return False.
78 If it works, assume it should be async. Otherwise Return False.
79
79
80 Not handled yet: If the block of code has a return statement as the top
80 Not handled yet: If the block of code has a return statement as the top
81 level, it will be seen as async. This is a know limitation.
81 level, it will be seen as async. This is a know limitation.
82 """
82 """
83
83
84 try:
84 try:
85 # we can't limit ourself to ast.parse, as it __accepts__ to parse on
85 # we can't limit ourself to ast.parse, as it __accepts__ to parse on
86 # 3.7+, but just does not _compile_
86 # 3.7+, but just does not _compile_
87 compile(cell, "<>", "exec")
87 compile(cell, "<>", "exec")
88 return False
88 return False
89 except SyntaxError:
89 except SyntaxError:
90 try:
90 try:
91 ast.parse(_asyncify(cell))
91 ast.parse(_asyncify(cell))
92 # TODO verify ast has not "top level" return or yield.
92 except SyntaxError:
93 except SyntaxError:
93 return False
94 return False
94 return True
95 return True
95 return False
96 return False
1 NO CONTENT: modified file
NO CONTENT: modified file
@@ -1,31 +1,27 b''
1 build: false
1 build: false
2 matrix:
2 matrix:
3 fast_finish: true # immediately finish build once one of the jobs fails.
3 fast_finish: true # immediately finish build once one of the jobs fails.
4
4
5 environment:
5 environment:
6 matrix:
6 matrix:
7 - PYTHON: "C:\\Python36"
7 - PYTHON: "C:\\Python36"
8 PYTHON_VERSION: "3.6.x"
8 PYTHON_VERSION: "3.6.x"
9 PYTHON_ARCH: "32"
9 PYTHON_ARCH: "32"
10
10
11 - PYTHON: "C:\\Python34-x64"
12 PYTHON_VERSION: "3.4.x"
13 PYTHON_ARCH: "64"
14
15 - PYTHON: "C:\\Python36-x64"
11 - PYTHON: "C:\\Python36-x64"
16 PYTHON_VERSION: "3.6.x"
12 PYTHON_VERSION: "3.6.x"
17 PYTHON_ARCH: "64"
13 PYTHON_ARCH: "64"
18
14
19 init:
15 init:
20 - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%"
16 - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%"
21
17
22 install:
18 install:
23 - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
19 - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
24 - "%CMD_IN_ENV% python -m pip install --upgrade setuptools pip"
20 - "%CMD_IN_ENV% python -m pip install --upgrade setuptools pip"
25 - "%CMD_IN_ENV% pip install nose coverage"
21 - "%CMD_IN_ENV% pip install nose coverage"
26 - "%CMD_IN_ENV% pip install .[test]"
22 - "%CMD_IN_ENV% pip install .[test]"
27 - "%CMD_IN_ENV% mkdir results"
23 - "%CMD_IN_ENV% mkdir results"
28 - "%CMD_IN_ENV% cd results"
24 - "%CMD_IN_ENV% cd results"
29 test_script:
25 test_script:
30 - "%CMD_IN_ENV% iptest --coverage xml"
26 - "%CMD_IN_ENV% iptest --coverage xml"
31
27
@@ -1,185 +1,193 b''
1 .. _autoawait:
1 .. _autoawait:
2
2
3 Asynchronous in REPL: Autoawait
3 Asynchronous in REPL: Autoawait
4 ===============================
4 ===============================
5
5
6 Starting with IPython 6.0, and when user Python 3.6 and above, IPython offer the
6 Starting with IPython 7.0, and when user Python 3.6 and above, IPython offer the
7 ability to run asynchronous code from the REPL. constructs which are
7 ability to run asynchronous code from the REPL. Constructs which are
8 :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.
9
9
10 When a supported libray is used, IPython will automatically `await` Futures
10 The example given here are for terminal IPython, running async code in a
11 and Coroutines in the REPL. This will happen if an :ref:`await <await>` (or `async`) is
11 notebook interface or any other frontend using the Jupyter protocol will need to
12 use a newer version of IPykernel. The details of how async code runs in
13 IPykernel will differ between IPython, IPykernel and their versions.
14
15 When a supported library is used, IPython will automatically `await` Futures
16 and Coroutines in the REPL. This will happen if an :ref:`await <await>` is
12 use at top level scope, or if any structure valid only in `async def
17 use at top level scope, or if any structure valid only in `async def
13 <https://docs.python.org/3/reference/compound_stmts.html#async-def>`_ function
18 <https://docs.python.org/3/reference/compound_stmts.html#async-def>`_ function
14 context are present. For example, the following being a syntax error in the
19 context are present. For example, the following being a syntax error in the
15 Python REPL::
20 Python REPL::
16
21
17 Python 3.6.0
22 Python 3.6.0
18 [GCC 4.2.1]
23 [GCC 4.2.1]
19 Type "help", "copyright", "credits" or "license" for more information.
24 Type "help", "copyright", "credits" or "license" for more information.
20 >>> import aiohttp
25 >>> import aiohttp
21 >>> result = aiohttp.get('https://api.github.com')
26 >>> result = aiohttp.get('https://api.github.com')
22 >>> response = await result
27 >>> response = await result
23 File "<stdin>", line 1
28 File "<stdin>", line 1
24 response = await result
29 response = await result
25 ^
30 ^
26 SyntaxError: invalid syntax
31 SyntaxError: invalid syntax
27
32
28 Should behave as expected in the IPython REPL::
33 Should behave as expected in the IPython REPL::
29
34
30 Python 3.6.0
35 Python 3.6.0
31 Type 'copyright', 'credits' or 'license' for more information
36 Type 'copyright', 'credits' or 'license' for more information
32 IPython 6.0.0.dev -- An enhanced Interactive Python. Type '?' for help.
37 IPython 7.0.0 -- An enhanced Interactive Python. Type '?' for help.
33
38
34 In [1]: import aiohttp
39 In [1]: import aiohttp
35 ...: result = aiohttp.get('https://api.github.com')
40 ...: result = aiohttp.get('https://api.github.com')
36
41
37 In [2]: response = await result
42 In [2]: response = await result
38 <pause for a few 100s ms>
43 <pause for a few 100s ms>
39
44
40 In [3]: await response.json()
45 In [3]: await response.json()
41 Out[3]:
46 Out[3]:
42 {'authorizations_url': 'https://api.github.com/authorizations',
47 {'authorizations_url': 'https://api.github.com/authorizations',
43 'code_search_url': 'https://api.github.com/search/code?q={query}...',
48 'code_search_url': 'https://api.github.com/search/code?q={query}...',
44 ...
49 ...
45 }
50 }
46
51
47
52
48 You can use the ``c.InteractiveShell.autoawait`` configuration option and set it
53 You can use the ``c.InteractiveShell.autoawait`` configuration option and set it
49 to :any:`False` to deactivate automatic wrapping of asynchronous code. You can also
54 to :any:`False` to deactivate automatic wrapping of asynchronous code. You can also
50 use the :magic:`%autoawait` magic to toggle the behavior at runtime::
55 use the :magic:`%autoawait` magic to toggle the behavior at runtime::
51
56
52 In [1]: %autoawait False
57 In [1]: %autoawait False
53
58
54 In [2]: %autoawait
59 In [2]: %autoawait
55 IPython autoawait is `Off`, and set to use `IPython.core.interactiveshell._asyncio_runner`
60 IPython autoawait is `Off`, and set to use `IPython.core.interactiveshell._asyncio_runner`
56
61
57
62
58
63
59 By default IPython will assume integration with Python's provided
64 By default IPython will assume integration with Python's provided
60 :mod:`asyncio`, but integration with other libraries is provided. In particular
65 :mod:`asyncio`, but integration with other libraries is provided. In particular
61 we provide experimental integration with the ``curio`` and ``trio`` library.
66 we provide experimental integration with the ``curio`` and ``trio`` library, the
67 later one being necessary if you require the ability to do nested call of
68 IPython's ``embed()`` functionality.
62
69
63 You can switch current integration by using the
70 You can switch current integration by using the
64 ``c.InteractiveShell.loop_runner`` option or the ``autoawait <name
71 ``c.InteractiveShell.loop_runner`` option or the ``autoawait <name
65 integration>`` magic.
72 integration>`` magic.
66
73
67 For example::
74 For example::
68
75
69 In [1]: %autoawait trio
76 In [1]: %autoawait trio
70
77
71 In [2]: import trio
78 In [2]: import trio
72
79
73 In [3]: async def child(i):
80 In [3]: async def child(i):
74 ...: print(" child %s goes to sleep"%i)
81 ...: print(" child %s goes to sleep"%i)
75 ...: await trio.sleep(2)
82 ...: await trio.sleep(2)
76 ...: print(" child %s wakes up"%i)
83 ...: print(" child %s wakes up"%i)
77
84
78 In [4]: print('parent start')
85 In [4]: print('parent start')
79 ...: async with trio.open_nursery() as n:
86 ...: async with trio.open_nursery() as n:
80 ...: for i in range(5):
87 ...: for i in range(5):
81 ...: n.spawn(child, i)
88 ...: n.spawn(child, i)
82 ...: print('parent end')
89 ...: print('parent end')
83 parent start
90 parent start
84 child 2 goes to sleep
91 child 2 goes to sleep
85 child 0 goes to sleep
92 child 0 goes to sleep
86 child 3 goes to sleep
93 child 3 goes to sleep
87 child 1 goes to sleep
94 child 1 goes to sleep
88 child 4 goes to sleep
95 child 4 goes to sleep
89 <about 2 seconds pause>
96 <about 2 seconds pause>
90 child 2 wakes up
97 child 2 wakes up
91 child 1 wakes up
98 child 1 wakes up
92 child 0 wakes up
99 child 0 wakes up
93 child 3 wakes up
100 child 3 wakes up
94 child 4 wakes up
101 child 4 wakes up
95 parent end
102 parent end
96
103
97
104
98 In the above example, ``async with`` at top level scope is a syntax error in
105 In the above example, ``async with`` at top level scope is a syntax error in
99 Python.
106 Python.
100
107
101 Using this mode can have unexpected consequences if used in interaction with
108 Using this mode can have unexpected consequences if used in interaction with
102 other features of IPython and various registered extensions. In particular if you
109 other features of IPython and various registered extensions. In particular if you
103 are a direct or indirect user of the AST transformers, these may not apply to
110 are a direct or indirect user of the AST transformers, these may not apply to
104 your code.
111 your code.
105
112
106 The default loop, or runner does not run in the background, so top level
113 When Using command line IPython, the default loop (or runner) does not process
107 asynchronous code must finish for the REPL to allow you to enter more code. As
114 in the background, so top level asynchronous code must finish for the REPL to
108 with usual Python semantic, the awaitables are started only when awaited for the
115 allow you to enter more code. As with usual Python semantic, the awaitables are
109 first time. That is to say, in first example, no network request is done between
116 started only when awaited for the first time. That is to say, in first example,
110 ``In[1]`` and ``In[2]``.
117 no network request is done between ``In[1]`` and ``In[2]``.
111
118
112
119
113 Internals
120 Internals
114 =========
121 =========
115
122
116 As running asynchronous code is not supported in interactive REPL as of Python
123 As running asynchronous code is not supported in interactive REPL (as of Python
117 3.6 we have to rely to a number of complex workaround to allow this to happen.
124 3.7) we have to rely to a number of complex workaround to allow this to happen.
118 It is interesting to understand how this works in order to understand potential
125 It is interesting to understand how this works in order to comprehend potential
119 bugs, or provide a custom runner.
126 bugs, or provide a custom runner.
120
127
121 Among the many approaches that are at our disposition, we find only one that
128 Among the many approaches that are at our disposition, we find only one that
122 suited out need. Under the hood we :ct the code object from a async-def function
129 suited out need. Under the hood we use the code object from a async-def function
123 and run it in global namesapace after modifying the ``__code__`` object.::
130 and run it in global namespace after modifying it to not create a new
131 ``locals()`` scope::
124
132
125 async def inner_async():
133 async def inner_async():
126 locals().update(**global_namespace)
134 locals().update(**global_namespace)
127 #
135 #
128 # here is user code
136 # here is user code
129 #
137 #
130 return last_user_statement
138 return last_user_statement
131 codeobj = modify(inner_async.__code__)
139 codeobj = modify(inner_async.__code__)
132 coroutine = eval(codeobj, user_ns)
140 coroutine = eval(codeobj, user_ns)
133 display(loop_runner(coroutine))
141 display(loop_runner(coroutine))
134
142
135
143
136
144
137 The first thing you'll notice is that unlike classical ``exec``, there is only
145 The first thing you'll notice is that unlike classical ``exec``, there is only
138 one name space. Second, user code runs in a function scope, and not a module
146 one namespace. Second, user code runs in a function scope, and not a module
139 scope.
147 scope.
140
148
141 On top of the above there are significant modification to the AST of
149 On top of the above there are significant modification to the AST of
142 ``function``, and ``loop_runner`` can be arbitrary complex. So there is a
150 ``function``, and ``loop_runner`` can be arbitrary complex. So there is a
143 significant overhead to this kind of code.
151 significant overhead to this kind of code.
144
152
145 By default the generated coroutine function will be consumed by Asyncio's
153 By default the generated coroutine function will be consumed by Asyncio's
146 ``loop_runner = asyncio.get_evenloop().run_until_complete()`` method. It is
154 ``loop_runner = asyncio.get_evenloop().run_until_complete()`` method. It is
147 though possible to provide your own.
155 though possible to provide your own.
148
156
149 A loop runner is a *synchronous* function responsible from running a coroutine
157 A loop runner is a *synchronous* function responsible from running a coroutine
150 object.
158 object.
151
159
152 The runner is responsible from ensuring that ``coroutine`` run to completion,
160 The runner is responsible from ensuring that ``coroutine`` run to completion,
153 and should return the result of executing the coroutine. Let's write a
161 and should return the result of executing the coroutine. Let's write a
154 runner for ``trio`` that print a message when used as an exercise, ``trio`` is
162 runner for ``trio`` that print a message when used as an exercise, ``trio`` is
155 special as it usually prefer to run a function object and make a coroutine by
163 special as it usually prefer to run a function object and make a coroutine by
156 itself, we can get around this limitation by wrapping it in an async-def without
164 itself, we can get around this limitation by wrapping it in an async-def without
157 parameters and passing this value to ``trio``::
165 parameters and passing this value to ``trio``::
158
166
159
167
160 In [1]: import trio
168 In [1]: import trio
161 ...: from types import CoroutineType
169 ...: from types import CoroutineType
162 ...:
170 ...:
163 ...: def trio_runner(coro:CoroutineType):
171 ...: def trio_runner(coro:CoroutineType):
164 ...: print('running asynchronous code')
172 ...: print('running asynchronous code')
165 ...: async def corowrap(coro):
173 ...: async def corowrap(coro):
166 ...: return await coro
174 ...: return await coro
167 ...: return trio.run(corowrap, coro)
175 ...: return trio.run(corowrap, coro)
168
176
169 We can set it up by passing it to ``%autoawait``::
177 We can set it up by passing it to ``%autoawait``::
170
178
171 In [2]: %autoawait trio_runner
179 In [2]: %autoawait trio_runner
172
180
173 In [3]: async def async_hello(name):
181 In [3]: async def async_hello(name):
174 ...: await trio.sleep(1)
182 ...: await trio.sleep(1)
175 ...: print(f'Hello {name} world !')
183 ...: print(f'Hello {name} world !')
176 ...: await trio.sleep(1)
184 ...: await trio.sleep(1)
177
185
178 In [4]: await async_hello('async')
186 In [4]: await async_hello('async')
179 running asynchronous code
187 running asynchronous code
180 Hello async world !
188 Hello async world !
181
189
182
190
183 Asynchronous programming in python (and in particular in the REPL) is still a
191 Asynchronous programming in python (and in particular in the REPL) is still a
184 relatively young subject. Feel free to contribute improvements to this codebase
192 relatively young subject. We expect some code to not behave as you expect, so
185 and give us feedback.
193 feel free to contribute improvements to this codebase and give us feedback.
@@ -1,44 +1,72 b''
1 =====================
1 =====================
2 Development version
2 Development version
3 =====================
3 =====================
4
4
5 This document describes in-flight development work.
5 This document describes in-flight development work.
6
6
7 .. warning::
7 .. warning::
8
8
9 Please do not edit this file by hand (doing so will likely cause merge
9 Please do not edit this file by hand (doing so will likely cause merge
10 conflicts for other Pull Requests). Instead, create a new file in the
10 conflicts for other Pull Requests). Instead, create a new file in the
11 `docs/source/whatsnew/pr` folder
11 `docs/source/whatsnew/pr` folder
12
12
13
13
14 Released .... ...., 2017
14 Released .... ...., 2017
15
15
16
16
17 Need to be updated:
17 Need to be updated:
18
18
19 .. toctree::
19 .. toctree::
20 :maxdepth: 2
20 :maxdepth: 2
21 :glob:
21 :glob:
22
22
23 pr/*
23 pr/*
24
24
25 IPython 6 feature a major improvement in the completion machinery which is now
25 IPython 6 feature a major improvement in the completion machinery which is now
26 capable of completing non-executed code. It is also the first version of IPython
26 capable of completing non-executed code. It is also the first version of IPython
27 to stop compatibility with Python 2, which is still supported on the bugfix only
27 to stop compatibility with Python 2, which is still supported on the bugfix only
28 5.x branch. Read below to have a non-exhaustive list of new features.
28 5.x branch. Read below to have a non-exhaustive list of new features.
29
29
30 Make sure you have pip > 9.0 before upgrading.
30 Make sure you have pip > 9.0 before upgrading.
31 You should be able to update by using:
31 You should be able to update by using:
32
32
33 .. code::
33 .. code::
34
34
35 pip install ipython --upgrade
35 pip install ipython --upgrade
36
36
37
37
38 Autowait: Asynchronous REPL
39 ===========================
40
41 Staring with IPython 7.0 and on Python 3.6+, IPython can automatically await
42 code at top level, you should not need to access an event loop or runner
43 yourself. To know more read the `autoawait`_ section of our docs, or try the
44 following code::
45
46 In [6]: from asyncio import sleep
47 ...: print('Going to sleep...')
48 ...: await sleep(3)
49 ...: print('Waking up')
50 Going to sleep...
51 Waking up
52
53 Asynchronous code in a Notebook interface or any other frontend using the
54 Jupyter Protocol will need further updates of the IPykernel package.
55
56
57 Change to Nested Embed
58 ======================
59
60 The introduction of the ability to run async code had ripple effect on the
61 ability to use nested IPython. You may need to install the ``trio`` library
62 (version 05 at the time of this writing) to
63 have this feature working.
64
65
38 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
66 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
39
67
40
68
41 Backwards incompatible changes
69 Backwards incompatible changes
42 ------------------------------
70 ------------------------------
43
71
44 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
72 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
General Comments 0
You need to be logged in to leave comments. Login now