##// END OF EJS Templates
Merge pull request #12581 from farisachugthai/typing_annotation
Matthias Bussonnier -
r26081:e2837c0a merge
parent child Browse files
Show More
@@ -1,316 +1,323 b''
1 """
1 """
2 Test for async helpers.
2 Test for async helpers.
3
3
4 Should only trigger on python 3.5+ or will have syntax errors.
4 Should only trigger on python 3.5+ or will have syntax errors.
5 """
5 """
6 from itertools import chain, repeat
6 from itertools import chain, repeat
7 import nose.tools as nt
7 import nose.tools as nt
8 from textwrap import dedent, indent
8 from textwrap import dedent, indent
9 from unittest import TestCase
9 from unittest import TestCase
10 from IPython.testing.decorators import skip_without
10 from IPython.testing.decorators import skip_without
11 import sys
11 import sys
12 from typing import TYPE_CHECKING
13
14 if TYPE_CHECKING:
15 from IPython import get_ipython
16
17 ip = get_ipython()
18
12
19
13 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
20 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
14 iprc_nr = lambda x: ip.run_cell(dedent(x))
21 iprc_nr = lambda x: ip.run_cell(dedent(x))
15
22
16 from IPython.core.async_helpers import _should_be_async
23 from IPython.core.async_helpers import _should_be_async
17
24
18 class AsyncTest(TestCase):
25 class AsyncTest(TestCase):
19 def test_should_be_async(self):
26 def test_should_be_async(self):
20 nt.assert_false(_should_be_async("False"))
27 nt.assert_false(_should_be_async("False"))
21 nt.assert_true(_should_be_async("await bar()"))
28 nt.assert_true(_should_be_async("await bar()"))
22 nt.assert_true(_should_be_async("x = await bar()"))
29 nt.assert_true(_should_be_async("x = await bar()"))
23 nt.assert_false(
30 nt.assert_false(
24 _should_be_async(
31 _should_be_async(
25 dedent(
32 dedent(
26 """
33 """
27 async def awaitable():
34 async def awaitable():
28 pass
35 pass
29 """
36 """
30 )
37 )
31 )
38 )
32 )
39 )
33
40
34 def _get_top_level_cases(self):
41 def _get_top_level_cases(self):
35 # These are test cases that should be valid in a function
42 # These are test cases that should be valid in a function
36 # but invalid outside of a function.
43 # but invalid outside of a function.
37 test_cases = []
44 test_cases = []
38 test_cases.append(('basic', "{val}"))
45 test_cases.append(('basic', "{val}"))
39
46
40 # Note, in all conditional cases, I use True instead of
47 # Note, in all conditional cases, I use True instead of
41 # False so that the peephole optimizer won't optimize away
48 # False so that the peephole optimizer won't optimize away
42 # the return, so CPython will see this as a syntax error:
49 # the return, so CPython will see this as a syntax error:
43 #
50 #
44 # while True:
51 # while True:
45 # break
52 # break
46 # return
53 # return
47 #
54 #
48 # But not this:
55 # But not this:
49 #
56 #
50 # while False:
57 # while False:
51 # return
58 # return
52 #
59 #
53 # See https://bugs.python.org/issue1875
60 # See https://bugs.python.org/issue1875
54
61
55 test_cases.append(('if', dedent("""
62 test_cases.append(('if', dedent("""
56 if True:
63 if True:
57 {val}
64 {val}
58 """)))
65 """)))
59
66
60 test_cases.append(('while', dedent("""
67 test_cases.append(('while', dedent("""
61 while True:
68 while True:
62 {val}
69 {val}
63 break
70 break
64 """)))
71 """)))
65
72
66 test_cases.append(('try', dedent("""
73 test_cases.append(('try', dedent("""
67 try:
74 try:
68 {val}
75 {val}
69 except:
76 except:
70 pass
77 pass
71 """)))
78 """)))
72
79
73 test_cases.append(('except', dedent("""
80 test_cases.append(('except', dedent("""
74 try:
81 try:
75 pass
82 pass
76 except:
83 except:
77 {val}
84 {val}
78 """)))
85 """)))
79
86
80 test_cases.append(('finally', dedent("""
87 test_cases.append(('finally', dedent("""
81 try:
88 try:
82 pass
89 pass
83 except:
90 except:
84 pass
91 pass
85 finally:
92 finally:
86 {val}
93 {val}
87 """)))
94 """)))
88
95
89 test_cases.append(('for', dedent("""
96 test_cases.append(('for', dedent("""
90 for _ in range(4):
97 for _ in range(4):
91 {val}
98 {val}
92 """)))
99 """)))
93
100
94
101
95 test_cases.append(('nested', dedent("""
102 test_cases.append(('nested', dedent("""
96 if True:
103 if True:
97 while True:
104 while True:
98 {val}
105 {val}
99 break
106 break
100 """)))
107 """)))
101
108
102 test_cases.append(('deep-nested', dedent("""
109 test_cases.append(('deep-nested', dedent("""
103 if True:
110 if True:
104 while True:
111 while True:
105 break
112 break
106 for x in range(3):
113 for x in range(3):
107 if True:
114 if True:
108 while True:
115 while True:
109 for x in range(3):
116 for x in range(3):
110 {val}
117 {val}
111 """)))
118 """)))
112
119
113 return test_cases
120 return test_cases
114
121
115 def _get_ry_syntax_errors(self):
122 def _get_ry_syntax_errors(self):
116 # This is a mix of tests that should be a syntax error if
123 # This is a mix of tests that should be a syntax error if
117 # return or yield whether or not they are in a function
124 # return or yield whether or not they are in a function
118
125
119 test_cases = []
126 test_cases = []
120
127
121 test_cases.append(('class', dedent("""
128 test_cases.append(('class', dedent("""
122 class V:
129 class V:
123 {val}
130 {val}
124 """)))
131 """)))
125
132
126 test_cases.append(('nested-class', dedent("""
133 test_cases.append(('nested-class', dedent("""
127 class V:
134 class V:
128 class C:
135 class C:
129 {val}
136 {val}
130 """)))
137 """)))
131
138
132 return test_cases
139 return test_cases
133
140
134
141
135 def test_top_level_return_error(self):
142 def test_top_level_return_error(self):
136 tl_err_test_cases = self._get_top_level_cases()
143 tl_err_test_cases = self._get_top_level_cases()
137 tl_err_test_cases.extend(self._get_ry_syntax_errors())
144 tl_err_test_cases.extend(self._get_ry_syntax_errors())
138
145
139 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
146 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
140 dedent('''
147 dedent('''
141 def f():
148 def f():
142 pass
149 pass
143 return
150 return
144 '''),
151 '''),
145 )
152 )
146
153
147 for test_name, test_case in tl_err_test_cases:
154 for test_name, test_case in tl_err_test_cases:
148 # This example should work if 'pass' is used as the value
155 # This example should work if 'pass' is used as the value
149 with self.subTest((test_name, 'pass')):
156 with self.subTest((test_name, 'pass')):
150 iprc(test_case.format(val='pass'))
157 iprc(test_case.format(val='pass'))
151
158
152 # It should fail with all the values
159 # It should fail with all the values
153 for val in vals:
160 for val in vals:
154 with self.subTest((test_name, val)):
161 with self.subTest((test_name, val)):
155 msg = "Syntax error not raised for %s, %s" % (test_name, val)
162 msg = "Syntax error not raised for %s, %s" % (test_name, val)
156 with self.assertRaises(SyntaxError, msg=msg):
163 with self.assertRaises(SyntaxError, msg=msg):
157 iprc(test_case.format(val=val))
164 iprc(test_case.format(val=val))
158
165
159 def test_in_func_no_error(self):
166 def test_in_func_no_error(self):
160 # Test that the implementation of top-level return/yield
167 # Test that the implementation of top-level return/yield
161 # detection isn't *too* aggressive, and works inside a function
168 # detection isn't *too* aggressive, and works inside a function
162 func_contexts = []
169 func_contexts = []
163
170
164 func_contexts.append(('func', False, dedent("""
171 func_contexts.append(('func', False, dedent("""
165 def f():""")))
172 def f():""")))
166
173
167 func_contexts.append(('method', False, dedent("""
174 func_contexts.append(('method', False, dedent("""
168 class MyClass:
175 class MyClass:
169 def __init__(self):
176 def __init__(self):
170 """)))
177 """)))
171
178
172 func_contexts.append(('async-func', True, dedent("""
179 func_contexts.append(('async-func', True, dedent("""
173 async def f():""")))
180 async def f():""")))
174
181
175 func_contexts.append(('async-method', True, dedent("""
182 func_contexts.append(('async-method', True, dedent("""
176 class MyClass:
183 class MyClass:
177 async def f(self):""")))
184 async def f(self):""")))
178
185
179 func_contexts.append(('closure', False, dedent("""
186 func_contexts.append(('closure', False, dedent("""
180 def f():
187 def f():
181 def g():
188 def g():
182 """)))
189 """)))
183
190
184 def nest_case(context, case):
191 def nest_case(context, case):
185 # Detect indentation
192 # Detect indentation
186 lines = context.strip().splitlines()
193 lines = context.strip().splitlines()
187 prefix_len = 0
194 prefix_len = 0
188 for c in lines[-1]:
195 for c in lines[-1]:
189 if c != ' ':
196 if c != ' ':
190 break
197 break
191 prefix_len += 1
198 prefix_len += 1
192
199
193 indented_case = indent(case, ' ' * (prefix_len + 4))
200 indented_case = indent(case, ' ' * (prefix_len + 4))
194 return context + '\n' + indented_case
201 return context + '\n' + indented_case
195
202
196 # Gather and run the tests
203 # Gather and run the tests
197
204
198 # yield is allowed in async functions, starting in Python 3.6,
205 # yield is allowed in async functions, starting in Python 3.6,
199 # and yield from is not allowed in any version
206 # and yield from is not allowed in any version
200 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
207 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
201 async_safe = (True,
208 async_safe = (True,
202 True,
209 True,
203 False)
210 False)
204 vals = tuple(zip(vals, async_safe))
211 vals = tuple(zip(vals, async_safe))
205
212
206 success_tests = zip(self._get_top_level_cases(), repeat(False))
213 success_tests = zip(self._get_top_level_cases(), repeat(False))
207 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
214 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
208
215
209 tests = chain(success_tests, failure_tests)
216 tests = chain(success_tests, failure_tests)
210
217
211 for context_name, async_func, context in func_contexts:
218 for context_name, async_func, context in func_contexts:
212 for (test_name, test_case), should_fail in tests:
219 for (test_name, test_case), should_fail in tests:
213 nested_case = nest_case(context, test_case)
220 nested_case = nest_case(context, test_case)
214
221
215 for val, async_safe in vals:
222 for val, async_safe in vals:
216 val_should_fail = (should_fail or
223 val_should_fail = (should_fail or
217 (async_func and not async_safe))
224 (async_func and not async_safe))
218
225
219 test_id = (context_name, test_name, val)
226 test_id = (context_name, test_name, val)
220 cell = nested_case.format(val=val)
227 cell = nested_case.format(val=val)
221
228
222 with self.subTest(test_id):
229 with self.subTest(test_id):
223 if val_should_fail:
230 if val_should_fail:
224 msg = ("SyntaxError not raised for %s" %
231 msg = ("SyntaxError not raised for %s" %
225 str(test_id))
232 str(test_id))
226 with self.assertRaises(SyntaxError, msg=msg):
233 with self.assertRaises(SyntaxError, msg=msg):
227 iprc(cell)
234 iprc(cell)
228
235
229 print(cell)
236 print(cell)
230 else:
237 else:
231 iprc(cell)
238 iprc(cell)
232
239
233 def test_nonlocal(self):
240 def test_nonlocal(self):
234 # fails if outer scope is not a function scope or if var not defined
241 # fails if outer scope is not a function scope or if var not defined
235 with self.assertRaises(SyntaxError):
242 with self.assertRaises(SyntaxError):
236 iprc("nonlocal x")
243 iprc("nonlocal x")
237 iprc("""
244 iprc("""
238 x = 1
245 x = 1
239 def f():
246 def f():
240 nonlocal x
247 nonlocal x
241 x = 10000
248 x = 10000
242 yield x
249 yield x
243 """)
250 """)
244 iprc("""
251 iprc("""
245 def f():
252 def f():
246 def g():
253 def g():
247 nonlocal x
254 nonlocal x
248 x = 10000
255 x = 10000
249 yield x
256 yield x
250 """)
257 """)
251
258
252 # works if outer scope is a function scope and var exists
259 # works if outer scope is a function scope and var exists
253 iprc("""
260 iprc("""
254 def f():
261 def f():
255 x = 20
262 x = 20
256 def g():
263 def g():
257 nonlocal x
264 nonlocal x
258 x = 10000
265 x = 10000
259 yield x
266 yield x
260 """)
267 """)
261
268
262
269
263 def test_execute(self):
270 def test_execute(self):
264 iprc("""
271 iprc("""
265 import asyncio
272 import asyncio
266 await asyncio.sleep(0.001)
273 await asyncio.sleep(0.001)
267 """
274 """
268 )
275 )
269
276
270 def test_autoawait(self):
277 def test_autoawait(self):
271 iprc("%autoawait False")
278 iprc("%autoawait False")
272 iprc("%autoawait True")
279 iprc("%autoawait True")
273 iprc("""
280 iprc("""
274 from asyncio import sleep
281 from asyncio import sleep
275 await sleep(0.1)
282 await sleep(0.1)
276 """
283 """
277 )
284 )
278
285
279 if sys.version_info < (3,9):
286 if sys.version_info < (3,9):
280 # new pgen parser in 3.9 does not raise MemoryError on too many nested
287 # new pgen parser in 3.9 does not raise MemoryError on too many nested
281 # parens anymore
288 # parens anymore
282 def test_memory_error(self):
289 def test_memory_error(self):
283 with self.assertRaises(MemoryError):
290 with self.assertRaises(MemoryError):
284 iprc("(" * 200 + ")" * 200)
291 iprc("(" * 200 + ")" * 200)
285
292
286 @skip_without('curio')
293 @skip_without('curio')
287 def test_autoawait_curio(self):
294 def test_autoawait_curio(self):
288 iprc("%autoawait curio")
295 iprc("%autoawait curio")
289
296
290 @skip_without('trio')
297 @skip_without('trio')
291 def test_autoawait_trio(self):
298 def test_autoawait_trio(self):
292 iprc("%autoawait trio")
299 iprc("%autoawait trio")
293
300
294 @skip_without('trio')
301 @skip_without('trio')
295 def test_autoawait_trio_wrong_sleep(self):
302 def test_autoawait_trio_wrong_sleep(self):
296 iprc("%autoawait trio")
303 iprc("%autoawait trio")
297 res = iprc_nr("""
304 res = iprc_nr("""
298 import asyncio
305 import asyncio
299 await asyncio.sleep(0)
306 await asyncio.sleep(0)
300 """)
307 """)
301 with nt.assert_raises(TypeError):
308 with nt.assert_raises(TypeError):
302 res.raise_error()
309 res.raise_error()
303
310
304 @skip_without('trio')
311 @skip_without('trio')
305 def test_autoawait_asyncio_wrong_sleep(self):
312 def test_autoawait_asyncio_wrong_sleep(self):
306 iprc("%autoawait asyncio")
313 iprc("%autoawait asyncio")
307 res = iprc_nr("""
314 res = iprc_nr("""
308 import trio
315 import trio
309 await trio.sleep(0)
316 await trio.sleep(0)
310 """)
317 """)
311 with nt.assert_raises(RuntimeError):
318 with nt.assert_raises(RuntimeError):
312 res.raise_error()
319 res.raise_error()
313
320
314
321
315 def tearDown(self):
322 def tearDown(self):
316 ip.loop_runner = "asyncio"
323 ip.loop_runner = "asyncio"
General Comments 0
You need to be logged in to leave comments. Login now