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