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