##// END OF EJS Templates
add test
yangyang -
Show More
@@ -1,309 +1,313 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
11
12
12
13 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
13 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
14 iprc_nr = lambda x: ip.run_cell(dedent(x))
14 iprc_nr = lambda x: ip.run_cell(dedent(x))
15
15
16 from IPython.core.async_helpers import _should_be_async
16 from IPython.core.async_helpers import _should_be_async
17
17
18 class AsyncTest(TestCase):
18 class AsyncTest(TestCase):
19 def test_should_be_async(self):
19 def test_should_be_async(self):
20 nt.assert_false(_should_be_async("False"))
20 nt.assert_false(_should_be_async("False"))
21 nt.assert_true(_should_be_async("await bar()"))
21 nt.assert_true(_should_be_async("await bar()"))
22 nt.assert_true(_should_be_async("x = await bar()"))
22 nt.assert_true(_should_be_async("x = await bar()"))
23 nt.assert_false(
23 nt.assert_false(
24 _should_be_async(
24 _should_be_async(
25 dedent(
25 dedent(
26 """
26 """
27 async def awaitable():
27 async def awaitable():
28 pass
28 pass
29 """
29 """
30 )
30 )
31 )
31 )
32 )
32 )
33
33
34 def _get_top_level_cases(self):
34 def _get_top_level_cases(self):
35 # These are test cases that should be valid in a function
35 # These are test cases that should be valid in a function
36 # but invalid outside of a function.
36 # but invalid outside of a function.
37 test_cases = []
37 test_cases = []
38 test_cases.append(('basic', "{val}"))
38 test_cases.append(('basic', "{val}"))
39
39
40 # Note, in all conditional cases, I use True instead of
40 # Note, in all conditional cases, I use True instead of
41 # False so that the peephole optimizer won't optimize away
41 # False so that the peephole optimizer won't optimize away
42 # the return, so CPython will see this as a syntax error:
42 # the return, so CPython will see this as a syntax error:
43 #
43 #
44 # while True:
44 # while True:
45 # break
45 # break
46 # return
46 # return
47 #
47 #
48 # But not this:
48 # But not this:
49 #
49 #
50 # while False:
50 # while False:
51 # return
51 # return
52 #
52 #
53 # See https://bugs.python.org/issue1875
53 # See https://bugs.python.org/issue1875
54
54
55 test_cases.append(('if', dedent("""
55 test_cases.append(('if', dedent("""
56 if True:
56 if True:
57 {val}
57 {val}
58 """)))
58 """)))
59
59
60 test_cases.append(('while', dedent("""
60 test_cases.append(('while', dedent("""
61 while True:
61 while True:
62 {val}
62 {val}
63 break
63 break
64 """)))
64 """)))
65
65
66 test_cases.append(('try', dedent("""
66 test_cases.append(('try', dedent("""
67 try:
67 try:
68 {val}
68 {val}
69 except:
69 except:
70 pass
70 pass
71 """)))
71 """)))
72
72
73 test_cases.append(('except', dedent("""
73 test_cases.append(('except', dedent("""
74 try:
74 try:
75 pass
75 pass
76 except:
76 except:
77 {val}
77 {val}
78 """)))
78 """)))
79
79
80 test_cases.append(('finally', dedent("""
80 test_cases.append(('finally', dedent("""
81 try:
81 try:
82 pass
82 pass
83 except:
83 except:
84 pass
84 pass
85 finally:
85 finally:
86 {val}
86 {val}
87 """)))
87 """)))
88
88
89 test_cases.append(('for', dedent("""
89 test_cases.append(('for', dedent("""
90 for _ in range(4):
90 for _ in range(4):
91 {val}
91 {val}
92 """)))
92 """)))
93
93
94
94
95 test_cases.append(('nested', dedent("""
95 test_cases.append(('nested', dedent("""
96 if True:
96 if True:
97 while True:
97 while True:
98 {val}
98 {val}
99 break
99 break
100 """)))
100 """)))
101
101
102 test_cases.append(('deep-nested', dedent("""
102 test_cases.append(('deep-nested', dedent("""
103 if True:
103 if True:
104 while True:
104 while True:
105 break
105 break
106 for x in range(3):
106 for x in range(3):
107 if True:
107 if True:
108 while True:
108 while True:
109 for x in range(3):
109 for x in range(3):
110 {val}
110 {val}
111 """)))
111 """)))
112
112
113 return test_cases
113 return test_cases
114
114
115 def _get_ry_syntax_errors(self):
115 def _get_ry_syntax_errors(self):
116 # This is a mix of tests that should be a syntax error if
116 # 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
117 # return or yield whether or not they are in a function
118
118
119 test_cases = []
119 test_cases = []
120
120
121 test_cases.append(('class', dedent("""
121 test_cases.append(('class', dedent("""
122 class V:
122 class V:
123 {val}
123 {val}
124 """)))
124 """)))
125
125
126 test_cases.append(('nested-class', dedent("""
126 test_cases.append(('nested-class', dedent("""
127 class V:
127 class V:
128 class C:
128 class C:
129 {val}
129 {val}
130 """)))
130 """)))
131
131
132 return test_cases
132 return test_cases
133
133
134
134
135 def test_top_level_return_error(self):
135 def test_top_level_return_error(self):
136 tl_err_test_cases = self._get_top_level_cases()
136 tl_err_test_cases = self._get_top_level_cases()
137 tl_err_test_cases.extend(self._get_ry_syntax_errors())
137 tl_err_test_cases.extend(self._get_ry_syntax_errors())
138
138
139 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
139 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
140 dedent('''
140 dedent('''
141 def f():
141 def f():
142 pass
142 pass
143 return
143 return
144 '''),
144 '''),
145 )
145 )
146
146
147 for test_name, test_case in tl_err_test_cases:
147 for test_name, test_case in tl_err_test_cases:
148 # This example should work if 'pass' is used as the value
148 # This example should work if 'pass' is used as the value
149 with self.subTest((test_name, 'pass')):
149 with self.subTest((test_name, 'pass')):
150 iprc(test_case.format(val='pass'))
150 iprc(test_case.format(val='pass'))
151
151
152 # It should fail with all the values
152 # It should fail with all the values
153 for val in vals:
153 for val in vals:
154 with self.subTest((test_name, val)):
154 with self.subTest((test_name, val)):
155 msg = "Syntax error not raised for %s, %s" % (test_name, val)
155 msg = "Syntax error not raised for %s, %s" % (test_name, val)
156 with self.assertRaises(SyntaxError, msg=msg):
156 with self.assertRaises(SyntaxError, msg=msg):
157 iprc(test_case.format(val=val))
157 iprc(test_case.format(val=val))
158
158
159 def test_in_func_no_error(self):
159 def test_in_func_no_error(self):
160 # Test that the implementation of top-level return/yield
160 # Test that the implementation of top-level return/yield
161 # detection isn't *too* aggressive, and works inside a function
161 # detection isn't *too* aggressive, and works inside a function
162 func_contexts = []
162 func_contexts = []
163
163
164 func_contexts.append(('func', False, dedent("""
164 func_contexts.append(('func', False, dedent("""
165 def f():""")))
165 def f():""")))
166
166
167 func_contexts.append(('method', False, dedent("""
167 func_contexts.append(('method', False, dedent("""
168 class MyClass:
168 class MyClass:
169 def __init__(self):
169 def __init__(self):
170 """)))
170 """)))
171
171
172 func_contexts.append(('async-func', True, dedent("""
172 func_contexts.append(('async-func', True, dedent("""
173 async def f():""")))
173 async def f():""")))
174
174
175 func_contexts.append(('async-method', True, dedent("""
175 func_contexts.append(('async-method', True, dedent("""
176 class MyClass:
176 class MyClass:
177 async def f(self):""")))
177 async def f(self):""")))
178
178
179 func_contexts.append(('closure', False, dedent("""
179 func_contexts.append(('closure', False, dedent("""
180 def f():
180 def f():
181 def g():
181 def g():
182 """)))
182 """)))
183
183
184 def nest_case(context, case):
184 def nest_case(context, case):
185 # Detect indentation
185 # Detect indentation
186 lines = context.strip().splitlines()
186 lines = context.strip().splitlines()
187 prefix_len = 0
187 prefix_len = 0
188 for c in lines[-1]:
188 for c in lines[-1]:
189 if c != ' ':
189 if c != ' ':
190 break
190 break
191 prefix_len += 1
191 prefix_len += 1
192
192
193 indented_case = indent(case, ' ' * (prefix_len + 4))
193 indented_case = indent(case, ' ' * (prefix_len + 4))
194 return context + '\n' + indented_case
194 return context + '\n' + indented_case
195
195
196 # Gather and run the tests
196 # Gather and run the tests
197
197
198 # yield is allowed in async functions, starting in Python 3.6,
198 # yield is allowed in async functions, starting in Python 3.6,
199 # and yield from is not allowed in any version
199 # and yield from is not allowed in any version
200 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
200 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
201 async_safe = (True,
201 async_safe = (True,
202 True,
202 True,
203 False)
203 False)
204 vals = tuple(zip(vals, async_safe))
204 vals = tuple(zip(vals, async_safe))
205
205
206 success_tests = zip(self._get_top_level_cases(), repeat(False))
206 success_tests = zip(self._get_top_level_cases(), repeat(False))
207 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
207 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
208
208
209 tests = chain(success_tests, failure_tests)
209 tests = chain(success_tests, failure_tests)
210
210
211 for context_name, async_func, context in func_contexts:
211 for context_name, async_func, context in func_contexts:
212 for (test_name, test_case), should_fail in tests:
212 for (test_name, test_case), should_fail in tests:
213 nested_case = nest_case(context, test_case)
213 nested_case = nest_case(context, test_case)
214
214
215 for val, async_safe in vals:
215 for val, async_safe in vals:
216 val_should_fail = (should_fail or
216 val_should_fail = (should_fail or
217 (async_func and not async_safe))
217 (async_func and not async_safe))
218
218
219 test_id = (context_name, test_name, val)
219 test_id = (context_name, test_name, val)
220 cell = nested_case.format(val=val)
220 cell = nested_case.format(val=val)
221
221
222 with self.subTest(test_id):
222 with self.subTest(test_id):
223 if val_should_fail:
223 if val_should_fail:
224 msg = ("SyntaxError not raised for %s" %
224 msg = ("SyntaxError not raised for %s" %
225 str(test_id))
225 str(test_id))
226 with self.assertRaises(SyntaxError, msg=msg):
226 with self.assertRaises(SyntaxError, msg=msg):
227 iprc(cell)
227 iprc(cell)
228
228
229 print(cell)
229 print(cell)
230 else:
230 else:
231 iprc(cell)
231 iprc(cell)
232
232
233 def test_nonlocal(self):
233 def test_nonlocal(self):
234 # fails if outer scope is not a function scope or if var not defined
234 # fails if outer scope is not a function scope or if var not defined
235 with self.assertRaises(SyntaxError):
235 with self.assertRaises(SyntaxError):
236 iprc("nonlocal x")
236 iprc("nonlocal x")
237 iprc("""
237 iprc("""
238 x = 1
238 x = 1
239 def f():
239 def f():
240 nonlocal x
240 nonlocal x
241 x = 10000
241 x = 10000
242 yield x
242 yield x
243 """)
243 """)
244 iprc("""
244 iprc("""
245 def f():
245 def f():
246 def g():
246 def g():
247 nonlocal x
247 nonlocal x
248 x = 10000
248 x = 10000
249 yield x
249 yield x
250 """)
250 """)
251
251
252 # works if outer scope is a function scope and var exists
252 # works if outer scope is a function scope and var exists
253 iprc("""
253 iprc("""
254 def f():
254 def f():
255 x = 20
255 x = 20
256 def g():
256 def g():
257 nonlocal x
257 nonlocal x
258 x = 10000
258 x = 10000
259 yield x
259 yield x
260 """)
260 """)
261
261
262
262
263 def test_execute(self):
263 def test_execute(self):
264 iprc("""
264 iprc("""
265 import asyncio
265 import asyncio
266 await asyncio.sleep(0.001)
266 await asyncio.sleep(0.001)
267 """
267 """
268 )
268 )
269
269
270 def test_autoawait(self):
270 def test_autoawait(self):
271 iprc("%autoawait False")
271 iprc("%autoawait False")
272 iprc("%autoawait True")
272 iprc("%autoawait True")
273 iprc("""
273 iprc("""
274 from asyncio import sleep
274 from asyncio import sleep
275 await sleep(0.1)
275 await sleep(0.1)
276 """
276 """
277 )
277 )
278
278
279 def test_memory_error(self):
280 with self.assertRaises(MemoryError):
281 iprc("(" * 200 + ")" * 200)
282
279 @skip_without('curio')
283 @skip_without('curio')
280 def test_autoawait_curio(self):
284 def test_autoawait_curio(self):
281 iprc("%autoawait curio")
285 iprc("%autoawait curio")
282
286
283 @skip_without('trio')
287 @skip_without('trio')
284 def test_autoawait_trio(self):
288 def test_autoawait_trio(self):
285 iprc("%autoawait trio")
289 iprc("%autoawait trio")
286
290
287 @skip_without('trio')
291 @skip_without('trio')
288 def test_autoawait_trio_wrong_sleep(self):
292 def test_autoawait_trio_wrong_sleep(self):
289 iprc("%autoawait trio")
293 iprc("%autoawait trio")
290 res = iprc_nr("""
294 res = iprc_nr("""
291 import asyncio
295 import asyncio
292 await asyncio.sleep(0)
296 await asyncio.sleep(0)
293 """)
297 """)
294 with nt.assert_raises(TypeError):
298 with nt.assert_raises(TypeError):
295 res.raise_error()
299 res.raise_error()
296
300
297 @skip_without('trio')
301 @skip_without('trio')
298 def test_autoawait_asyncio_wrong_sleep(self):
302 def test_autoawait_asyncio_wrong_sleep(self):
299 iprc("%autoawait asyncio")
303 iprc("%autoawait asyncio")
300 res = iprc_nr("""
304 res = iprc_nr("""
301 import trio
305 import trio
302 await trio.sleep(0)
306 await trio.sleep(0)
303 """)
307 """)
304 with nt.assert_raises(RuntimeError):
308 with nt.assert_raises(RuntimeError):
305 res.raise_error()
309 res.raise_error()
306
310
307
311
308 def tearDown(self):
312 def tearDown(self):
309 ip.loop_runner = "asyncio"
313 ip.loop_runner = "asyncio"
@@ -1,459 +1,466 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.core.ultratb
2 """Tests for IPython.core.ultratb
3 """
3 """
4 import io
4 import io
5 import logging
5 import logging
6 import sys
6 import sys
7 import os.path
7 import os.path
8 from textwrap import dedent
8 from textwrap import dedent
9 import traceback
9 import traceback
10 import unittest
10 import unittest
11 from unittest import mock
11 from unittest import mock
12
12
13 import IPython.core.ultratb as ultratb
13 import IPython.core.ultratb as ultratb
14 from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion
14 from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion
15
15
16
16
17 from IPython.testing import tools as tt
17 from IPython.testing import tools as tt
18 from IPython.testing.decorators import onlyif_unicode_paths
18 from IPython.testing.decorators import onlyif_unicode_paths
19 from IPython.utils.syspathcontext import prepended_to_syspath
19 from IPython.utils.syspathcontext import prepended_to_syspath
20 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.utils.tempdir import TemporaryDirectory
21
21
22 file_1 = """1
22 file_1 = """1
23 2
23 2
24 3
24 3
25 def f():
25 def f():
26 1/0
26 1/0
27 """
27 """
28
28
29 file_2 = """def f():
29 file_2 = """def f():
30 1/0
30 1/0
31 """
31 """
32
32
33
33
34 def recursionlimit(frames):
34 def recursionlimit(frames):
35 """
35 """
36 decorator to set the recursion limit temporarily
36 decorator to set the recursion limit temporarily
37 """
37 """
38
38
39 def inner(test_function):
39 def inner(test_function):
40 def wrapper(*args, **kwargs):
40 def wrapper(*args, **kwargs):
41 _orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT
41 _orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT
42 ultratb._FRAME_RECURSION_LIMIT = 50
42 ultratb._FRAME_RECURSION_LIMIT = 50
43
43
44 rl = sys.getrecursionlimit()
44 rl = sys.getrecursionlimit()
45 sys.setrecursionlimit(frames)
45 sys.setrecursionlimit(frames)
46 try:
46 try:
47 return test_function(*args, **kwargs)
47 return test_function(*args, **kwargs)
48 finally:
48 finally:
49 sys.setrecursionlimit(rl)
49 sys.setrecursionlimit(rl)
50 ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit
50 ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit
51
51
52 return wrapper
52 return wrapper
53
53
54 return inner
54 return inner
55
55
56
56
57 class ChangedPyFileTest(unittest.TestCase):
57 class ChangedPyFileTest(unittest.TestCase):
58 def test_changing_py_file(self):
58 def test_changing_py_file(self):
59 """Traceback produced if the line where the error occurred is missing?
59 """Traceback produced if the line where the error occurred is missing?
60
60
61 https://github.com/ipython/ipython/issues/1456
61 https://github.com/ipython/ipython/issues/1456
62 """
62 """
63 with TemporaryDirectory() as td:
63 with TemporaryDirectory() as td:
64 fname = os.path.join(td, "foo.py")
64 fname = os.path.join(td, "foo.py")
65 with open(fname, "w") as f:
65 with open(fname, "w") as f:
66 f.write(file_1)
66 f.write(file_1)
67
67
68 with prepended_to_syspath(td):
68 with prepended_to_syspath(td):
69 ip.run_cell("import foo")
69 ip.run_cell("import foo")
70
70
71 with tt.AssertPrints("ZeroDivisionError"):
71 with tt.AssertPrints("ZeroDivisionError"):
72 ip.run_cell("foo.f()")
72 ip.run_cell("foo.f()")
73
73
74 # Make the file shorter, so the line of the error is missing.
74 # Make the file shorter, so the line of the error is missing.
75 with open(fname, "w") as f:
75 with open(fname, "w") as f:
76 f.write(file_2)
76 f.write(file_2)
77
77
78 # For some reason, this was failing on the *second* call after
78 # For some reason, this was failing on the *second* call after
79 # changing the file, so we call f() twice.
79 # changing the file, so we call f() twice.
80 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
80 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
81 with tt.AssertPrints("ZeroDivisionError"):
81 with tt.AssertPrints("ZeroDivisionError"):
82 ip.run_cell("foo.f()")
82 ip.run_cell("foo.f()")
83 with tt.AssertPrints("ZeroDivisionError"):
83 with tt.AssertPrints("ZeroDivisionError"):
84 ip.run_cell("foo.f()")
84 ip.run_cell("foo.f()")
85
85
86 iso_8859_5_file = u'''# coding: iso-8859-5
86 iso_8859_5_file = u'''# coding: iso-8859-5
87
87
88 def fail():
88 def fail():
89 """Π΄Π±Π˜Π–"""
89 """Π΄Π±Π˜Π–"""
90 1/0 # Π΄Π±Π˜Π–
90 1/0 # Π΄Π±Π˜Π–
91 '''
91 '''
92
92
93 class NonAsciiTest(unittest.TestCase):
93 class NonAsciiTest(unittest.TestCase):
94 @onlyif_unicode_paths
94 @onlyif_unicode_paths
95 def test_nonascii_path(self):
95 def test_nonascii_path(self):
96 # Non-ascii directory name as well.
96 # Non-ascii directory name as well.
97 with TemporaryDirectory(suffix=u'Γ©') as td:
97 with TemporaryDirectory(suffix=u'Γ©') as td:
98 fname = os.path.join(td, u"fooΓ©.py")
98 fname = os.path.join(td, u"fooΓ©.py")
99 with open(fname, "w") as f:
99 with open(fname, "w") as f:
100 f.write(file_1)
100 f.write(file_1)
101
101
102 with prepended_to_syspath(td):
102 with prepended_to_syspath(td):
103 ip.run_cell("import foo")
103 ip.run_cell("import foo")
104
104
105 with tt.AssertPrints("ZeroDivisionError"):
105 with tt.AssertPrints("ZeroDivisionError"):
106 ip.run_cell("foo.f()")
106 ip.run_cell("foo.f()")
107
107
108 def test_iso8859_5(self):
108 def test_iso8859_5(self):
109 with TemporaryDirectory() as td:
109 with TemporaryDirectory() as td:
110 fname = os.path.join(td, 'dfghjkl.py')
110 fname = os.path.join(td, 'dfghjkl.py')
111
111
112 with io.open(fname, 'w', encoding='iso-8859-5') as f:
112 with io.open(fname, 'w', encoding='iso-8859-5') as f:
113 f.write(iso_8859_5_file)
113 f.write(iso_8859_5_file)
114
114
115 with prepended_to_syspath(td):
115 with prepended_to_syspath(td):
116 ip.run_cell("from dfghjkl import fail")
116 ip.run_cell("from dfghjkl import fail")
117
117
118 with tt.AssertPrints("ZeroDivisionError"):
118 with tt.AssertPrints("ZeroDivisionError"):
119 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
119 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
120 ip.run_cell('fail()')
120 ip.run_cell('fail()')
121
121
122 def test_nonascii_msg(self):
122 def test_nonascii_msg(self):
123 cell = u"raise Exception('Γ©')"
123 cell = u"raise Exception('Γ©')"
124 expected = u"Exception('Γ©')"
124 expected = u"Exception('Γ©')"
125 ip.run_cell("%xmode plain")
125 ip.run_cell("%xmode plain")
126 with tt.AssertPrints(expected):
126 with tt.AssertPrints(expected):
127 ip.run_cell(cell)
127 ip.run_cell(cell)
128
128
129 ip.run_cell("%xmode verbose")
129 ip.run_cell("%xmode verbose")
130 with tt.AssertPrints(expected):
130 with tt.AssertPrints(expected):
131 ip.run_cell(cell)
131 ip.run_cell(cell)
132
132
133 ip.run_cell("%xmode context")
133 ip.run_cell("%xmode context")
134 with tt.AssertPrints(expected):
134 with tt.AssertPrints(expected):
135 ip.run_cell(cell)
135 ip.run_cell(cell)
136
136
137 ip.run_cell("%xmode minimal")
137 ip.run_cell("%xmode minimal")
138 with tt.AssertPrints(u"Exception: Γ©"):
138 with tt.AssertPrints(u"Exception: Γ©"):
139 ip.run_cell(cell)
139 ip.run_cell(cell)
140
140
141 # Put this back into Context mode for later tests.
141 # Put this back into Context mode for later tests.
142 ip.run_cell("%xmode context")
142 ip.run_cell("%xmode context")
143
143
144 class NestedGenExprTestCase(unittest.TestCase):
144 class NestedGenExprTestCase(unittest.TestCase):
145 """
145 """
146 Regression test for the following issues:
146 Regression test for the following issues:
147 https://github.com/ipython/ipython/issues/8293
147 https://github.com/ipython/ipython/issues/8293
148 https://github.com/ipython/ipython/issues/8205
148 https://github.com/ipython/ipython/issues/8205
149 """
149 """
150 def test_nested_genexpr(self):
150 def test_nested_genexpr(self):
151 code = dedent(
151 code = dedent(
152 """\
152 """\
153 class SpecificException(Exception):
153 class SpecificException(Exception):
154 pass
154 pass
155
155
156 def foo(x):
156 def foo(x):
157 raise SpecificException("Success!")
157 raise SpecificException("Success!")
158
158
159 sum(sum(foo(x) for _ in [0]) for x in [0])
159 sum(sum(foo(x) for _ in [0]) for x in [0])
160 """
160 """
161 )
161 )
162 with tt.AssertPrints('SpecificException: Success!', suppress=False):
162 with tt.AssertPrints('SpecificException: Success!', suppress=False):
163 ip.run_cell(code)
163 ip.run_cell(code)
164
164
165
165
166 indentationerror_file = """if True:
166 indentationerror_file = """if True:
167 zoon()
167 zoon()
168 """
168 """
169
169
170 class IndentationErrorTest(unittest.TestCase):
170 class IndentationErrorTest(unittest.TestCase):
171 def test_indentationerror_shows_line(self):
171 def test_indentationerror_shows_line(self):
172 # See issue gh-2398
172 # See issue gh-2398
173 with tt.AssertPrints("IndentationError"):
173 with tt.AssertPrints("IndentationError"):
174 with tt.AssertPrints("zoon()", suppress=False):
174 with tt.AssertPrints("zoon()", suppress=False):
175 ip.run_cell(indentationerror_file)
175 ip.run_cell(indentationerror_file)
176
176
177 with TemporaryDirectory() as td:
177 with TemporaryDirectory() as td:
178 fname = os.path.join(td, "foo.py")
178 fname = os.path.join(td, "foo.py")
179 with open(fname, "w") as f:
179 with open(fname, "w") as f:
180 f.write(indentationerror_file)
180 f.write(indentationerror_file)
181
181
182 with tt.AssertPrints("IndentationError"):
182 with tt.AssertPrints("IndentationError"):
183 with tt.AssertPrints("zoon()", suppress=False):
183 with tt.AssertPrints("zoon()", suppress=False):
184 ip.magic('run %s' % fname)
184 ip.magic('run %s' % fname)
185
185
186 se_file_1 = """1
186 se_file_1 = """1
187 2
187 2
188 7/
188 7/
189 """
189 """
190
190
191 se_file_2 = """7/
191 se_file_2 = """7/
192 """
192 """
193
193
194 class SyntaxErrorTest(unittest.TestCase):
194 class SyntaxErrorTest(unittest.TestCase):
195 def test_syntaxerror_without_lineno(self):
195 def test_syntaxerror_without_lineno(self):
196 with tt.AssertNotPrints("TypeError"):
196 with tt.AssertNotPrints("TypeError"):
197 with tt.AssertPrints("line unknown"):
197 with tt.AssertPrints("line unknown"):
198 ip.run_cell("raise SyntaxError()")
198 ip.run_cell("raise SyntaxError()")
199
199
200 def test_syntaxerror_no_stacktrace_at_compile_time(self):
200 def test_syntaxerror_no_stacktrace_at_compile_time(self):
201 syntax_error_at_compile_time = """
201 syntax_error_at_compile_time = """
202 def foo():
202 def foo():
203 ..
203 ..
204 """
204 """
205 with tt.AssertPrints("SyntaxError"):
205 with tt.AssertPrints("SyntaxError"):
206 ip.run_cell(syntax_error_at_compile_time)
206 ip.run_cell(syntax_error_at_compile_time)
207
207
208 with tt.AssertNotPrints("foo()"):
208 with tt.AssertNotPrints("foo()"):
209 ip.run_cell(syntax_error_at_compile_time)
209 ip.run_cell(syntax_error_at_compile_time)
210
210
211 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
211 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
212 syntax_error_at_runtime = """
212 syntax_error_at_runtime = """
213 def foo():
213 def foo():
214 eval("..")
214 eval("..")
215
215
216 def bar():
216 def bar():
217 foo()
217 foo()
218
218
219 bar()
219 bar()
220 """
220 """
221 with tt.AssertPrints("SyntaxError"):
221 with tt.AssertPrints("SyntaxError"):
222 ip.run_cell(syntax_error_at_runtime)
222 ip.run_cell(syntax_error_at_runtime)
223 # Assert syntax error during runtime generate stacktrace
223 # Assert syntax error during runtime generate stacktrace
224 with tt.AssertPrints(["foo()", "bar()"]):
224 with tt.AssertPrints(["foo()", "bar()"]):
225 ip.run_cell(syntax_error_at_runtime)
225 ip.run_cell(syntax_error_at_runtime)
226 del ip.user_ns['bar']
226 del ip.user_ns['bar']
227 del ip.user_ns['foo']
227 del ip.user_ns['foo']
228
228
229 def test_changing_py_file(self):
229 def test_changing_py_file(self):
230 with TemporaryDirectory() as td:
230 with TemporaryDirectory() as td:
231 fname = os.path.join(td, "foo.py")
231 fname = os.path.join(td, "foo.py")
232 with open(fname, 'w') as f:
232 with open(fname, 'w') as f:
233 f.write(se_file_1)
233 f.write(se_file_1)
234
234
235 with tt.AssertPrints(["7/", "SyntaxError"]):
235 with tt.AssertPrints(["7/", "SyntaxError"]):
236 ip.magic("run " + fname)
236 ip.magic("run " + fname)
237
237
238 # Modify the file
238 # Modify the file
239 with open(fname, 'w') as f:
239 with open(fname, 'w') as f:
240 f.write(se_file_2)
240 f.write(se_file_2)
241
241
242 # The SyntaxError should point to the correct line
242 # The SyntaxError should point to the correct line
243 with tt.AssertPrints(["7/", "SyntaxError"]):
243 with tt.AssertPrints(["7/", "SyntaxError"]):
244 ip.magic("run " + fname)
244 ip.magic("run " + fname)
245
245
246 def test_non_syntaxerror(self):
246 def test_non_syntaxerror(self):
247 # SyntaxTB may be called with an error other than a SyntaxError
247 # SyntaxTB may be called with an error other than a SyntaxError
248 # See e.g. gh-4361
248 # See e.g. gh-4361
249 try:
249 try:
250 raise ValueError('QWERTY')
250 raise ValueError('QWERTY')
251 except ValueError:
251 except ValueError:
252 with tt.AssertPrints('QWERTY'):
252 with tt.AssertPrints('QWERTY'):
253 ip.showsyntaxerror()
253 ip.showsyntaxerror()
254
254
255
255
256 class MemoryErrorTest(unittest.TestCase):
257 def test_memoryerror(self):
258 memoryerror_code = "(" * 200 + ")" * 200
259 with tt.AssertPrints("MemoryError"):
260 ip.run_cell(memoryerror_code)
261
262
256 class Python3ChainedExceptionsTest(unittest.TestCase):
263 class Python3ChainedExceptionsTest(unittest.TestCase):
257 DIRECT_CAUSE_ERROR_CODE = """
264 DIRECT_CAUSE_ERROR_CODE = """
258 try:
265 try:
259 x = 1 + 2
266 x = 1 + 2
260 print(not_defined_here)
267 print(not_defined_here)
261 except Exception as e:
268 except Exception as e:
262 x += 55
269 x += 55
263 x - 1
270 x - 1
264 y = {}
271 y = {}
265 raise KeyError('uh') from e
272 raise KeyError('uh') from e
266 """
273 """
267
274
268 EXCEPTION_DURING_HANDLING_CODE = """
275 EXCEPTION_DURING_HANDLING_CODE = """
269 try:
276 try:
270 x = 1 + 2
277 x = 1 + 2
271 print(not_defined_here)
278 print(not_defined_here)
272 except Exception as e:
279 except Exception as e:
273 x += 55
280 x += 55
274 x - 1
281 x - 1
275 y = {}
282 y = {}
276 raise KeyError('uh')
283 raise KeyError('uh')
277 """
284 """
278
285
279 SUPPRESS_CHAINING_CODE = """
286 SUPPRESS_CHAINING_CODE = """
280 try:
287 try:
281 1/0
288 1/0
282 except Exception:
289 except Exception:
283 raise ValueError("Yikes") from None
290 raise ValueError("Yikes") from None
284 """
291 """
285
292
286 def test_direct_cause_error(self):
293 def test_direct_cause_error(self):
287 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
294 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
288 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
295 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
289
296
290 def test_exception_during_handling_error(self):
297 def test_exception_during_handling_error(self):
291 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
298 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
292 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
299 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
293
300
294 def test_suppress_exception_chaining(self):
301 def test_suppress_exception_chaining(self):
295 with tt.AssertNotPrints("ZeroDivisionError"), \
302 with tt.AssertNotPrints("ZeroDivisionError"), \
296 tt.AssertPrints("ValueError", suppress=False):
303 tt.AssertPrints("ValueError", suppress=False):
297 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
304 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
298
305
299 def test_plain_direct_cause_error(self):
306 def test_plain_direct_cause_error(self):
300 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
307 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
301 ip.run_cell("%xmode Plain")
308 ip.run_cell("%xmode Plain")
302 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
309 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
303 ip.run_cell("%xmode Verbose")
310 ip.run_cell("%xmode Verbose")
304
311
305 def test_plain_exception_during_handling_error(self):
312 def test_plain_exception_during_handling_error(self):
306 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
313 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
307 ip.run_cell("%xmode Plain")
314 ip.run_cell("%xmode Plain")
308 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
315 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
309 ip.run_cell("%xmode Verbose")
316 ip.run_cell("%xmode Verbose")
310
317
311 def test_plain_suppress_exception_chaining(self):
318 def test_plain_suppress_exception_chaining(self):
312 with tt.AssertNotPrints("ZeroDivisionError"), \
319 with tt.AssertNotPrints("ZeroDivisionError"), \
313 tt.AssertPrints("ValueError", suppress=False):
320 tt.AssertPrints("ValueError", suppress=False):
314 ip.run_cell("%xmode Plain")
321 ip.run_cell("%xmode Plain")
315 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
322 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
316 ip.run_cell("%xmode Verbose")
323 ip.run_cell("%xmode Verbose")
317
324
318
325
319 class RecursionTest(unittest.TestCase):
326 class RecursionTest(unittest.TestCase):
320 DEFINITIONS = """
327 DEFINITIONS = """
321 def non_recurs():
328 def non_recurs():
322 1/0
329 1/0
323
330
324 def r1():
331 def r1():
325 r1()
332 r1()
326
333
327 def r3a():
334 def r3a():
328 r3b()
335 r3b()
329
336
330 def r3b():
337 def r3b():
331 r3c()
338 r3c()
332
339
333 def r3c():
340 def r3c():
334 r3a()
341 r3a()
335
342
336 def r3o1():
343 def r3o1():
337 r3a()
344 r3a()
338
345
339 def r3o2():
346 def r3o2():
340 r3o1()
347 r3o1()
341 """
348 """
342 def setUp(self):
349 def setUp(self):
343 ip.run_cell(self.DEFINITIONS)
350 ip.run_cell(self.DEFINITIONS)
344
351
345 def test_no_recursion(self):
352 def test_no_recursion(self):
346 with tt.AssertNotPrints("frames repeated"):
353 with tt.AssertNotPrints("frames repeated"):
347 ip.run_cell("non_recurs()")
354 ip.run_cell("non_recurs()")
348
355
349 @recursionlimit(150)
356 @recursionlimit(150)
350 def test_recursion_one_frame(self):
357 def test_recursion_one_frame(self):
351 with tt.AssertPrints("1 frames repeated"):
358 with tt.AssertPrints("1 frames repeated"):
352 ip.run_cell("r1()")
359 ip.run_cell("r1()")
353
360
354 @recursionlimit(150)
361 @recursionlimit(150)
355 def test_recursion_three_frames(self):
362 def test_recursion_three_frames(self):
356 with tt.AssertPrints("3 frames repeated"):
363 with tt.AssertPrints("3 frames repeated"):
357 ip.run_cell("r3o2()")
364 ip.run_cell("r3o2()")
358
365
359 @recursionlimit(150)
366 @recursionlimit(150)
360 def test_find_recursion(self):
367 def test_find_recursion(self):
361 captured = []
368 captured = []
362 def capture_exc(*args, **kwargs):
369 def capture_exc(*args, **kwargs):
363 captured.append(sys.exc_info())
370 captured.append(sys.exc_info())
364 with mock.patch.object(ip, 'showtraceback', capture_exc):
371 with mock.patch.object(ip, 'showtraceback', capture_exc):
365 ip.run_cell("r3o2()")
372 ip.run_cell("r3o2()")
366
373
367 self.assertEqual(len(captured), 1)
374 self.assertEqual(len(captured), 1)
368 etype, evalue, tb = captured[0]
375 etype, evalue, tb = captured[0]
369 self.assertIn("recursion", str(evalue))
376 self.assertIn("recursion", str(evalue))
370
377
371 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
378 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
372 for r in records[:10]:
379 for r in records[:10]:
373 print(r[1:4])
380 print(r[1:4])
374
381
375 # The outermost frames should be:
382 # The outermost frames should be:
376 # 0: the 'cell' that was running when the exception came up
383 # 0: the 'cell' that was running when the exception came up
377 # 1: r3o2()
384 # 1: r3o2()
378 # 2: r3o1()
385 # 2: r3o1()
379 # 3: r3a()
386 # 3: r3a()
380 # Then repeating r3b, r3c, r3a
387 # Then repeating r3b, r3c, r3a
381 last_unique, repeat_length = find_recursion(etype, evalue, records)
388 last_unique, repeat_length = find_recursion(etype, evalue, records)
382 self.assertEqual(last_unique, 2)
389 self.assertEqual(last_unique, 2)
383 self.assertEqual(repeat_length, 3)
390 self.assertEqual(repeat_length, 3)
384
391
385
392
386 #----------------------------------------------------------------------------
393 #----------------------------------------------------------------------------
387
394
388 # module testing (minimal)
395 # module testing (minimal)
389 def test_handlers():
396 def test_handlers():
390 def spam(c, d_e):
397 def spam(c, d_e):
391 (d, e) = d_e
398 (d, e) = d_e
392 x = c + d
399 x = c + d
393 y = c * d
400 y = c * d
394 foo(x, y)
401 foo(x, y)
395
402
396 def foo(a, b, bar=1):
403 def foo(a, b, bar=1):
397 eggs(a, b + bar)
404 eggs(a, b + bar)
398
405
399 def eggs(f, g, z=globals()):
406 def eggs(f, g, z=globals()):
400 h = f + g
407 h = f + g
401 i = f - g
408 i = f - g
402 return h / i
409 return h / i
403
410
404 buff = io.StringIO()
411 buff = io.StringIO()
405
412
406 buff.write('')
413 buff.write('')
407 buff.write('*** Before ***')
414 buff.write('*** Before ***')
408 try:
415 try:
409 buff.write(spam(1, (2, 3)))
416 buff.write(spam(1, (2, 3)))
410 except:
417 except:
411 traceback.print_exc(file=buff)
418 traceback.print_exc(file=buff)
412
419
413 handler = ColorTB(ostream=buff)
420 handler = ColorTB(ostream=buff)
414 buff.write('*** ColorTB ***')
421 buff.write('*** ColorTB ***')
415 try:
422 try:
416 buff.write(spam(1, (2, 3)))
423 buff.write(spam(1, (2, 3)))
417 except:
424 except:
418 handler(*sys.exc_info())
425 handler(*sys.exc_info())
419 buff.write('')
426 buff.write('')
420
427
421 handler = VerboseTB(ostream=buff)
428 handler = VerboseTB(ostream=buff)
422 buff.write('*** VerboseTB ***')
429 buff.write('*** VerboseTB ***')
423 try:
430 try:
424 buff.write(spam(1, (2, 3)))
431 buff.write(spam(1, (2, 3)))
425 except:
432 except:
426 handler(*sys.exc_info())
433 handler(*sys.exc_info())
427 buff.write('')
434 buff.write('')
428
435
429 from IPython.testing.decorators import skipif
436 from IPython.testing.decorators import skipif
430
437
431 class TokenizeFailureTest(unittest.TestCase):
438 class TokenizeFailureTest(unittest.TestCase):
432 """Tests related to https://github.com/ipython/ipython/issues/6864."""
439 """Tests related to https://github.com/ipython/ipython/issues/6864."""
433
440
434 # that appear to test that we are handling an exception that can be thrown
441 # that appear to test that we are handling an exception that can be thrown
435 # by the tokenizer due to a bug that seem to have been fixed in 3.8, though
442 # by the tokenizer due to a bug that seem to have been fixed in 3.8, though
436 # I'm unsure if other sequences can make it raise this error. Let's just
443 # I'm unsure if other sequences can make it raise this error. Let's just
437 # skip in 3.8 for now
444 # skip in 3.8 for now
438 @skipif(sys.version_info > (3,8))
445 @skipif(sys.version_info > (3,8))
439 def testLogging(self):
446 def testLogging(self):
440 message = "An unexpected error occurred while tokenizing input"
447 message = "An unexpected error occurred while tokenizing input"
441 cell = 'raise ValueError("""a\nb""")'
448 cell = 'raise ValueError("""a\nb""")'
442
449
443 stream = io.StringIO()
450 stream = io.StringIO()
444 handler = logging.StreamHandler(stream)
451 handler = logging.StreamHandler(stream)
445 logger = logging.getLogger()
452 logger = logging.getLogger()
446 loglevel = logger.level
453 loglevel = logger.level
447 logger.addHandler(handler)
454 logger.addHandler(handler)
448 self.addCleanup(lambda: logger.removeHandler(handler))
455 self.addCleanup(lambda: logger.removeHandler(handler))
449 self.addCleanup(lambda: logger.setLevel(loglevel))
456 self.addCleanup(lambda: logger.setLevel(loglevel))
450
457
451 logger.setLevel(logging.INFO)
458 logger.setLevel(logging.INFO)
452 with tt.AssertNotPrints(message):
459 with tt.AssertNotPrints(message):
453 ip.run_cell(cell)
460 ip.run_cell(cell)
454 self.assertNotIn(message, stream.getvalue())
461 self.assertNotIn(message, stream.getvalue())
455
462
456 logger.setLevel(logging.DEBUG)
463 logger.setLevel(logging.DEBUG)
457 with tt.AssertNotPrints(message):
464 with tt.AssertNotPrints(message):
458 ip.run_cell(cell)
465 ip.run_cell(cell)
459 self.assertIn(message, stream.getvalue())
466 self.assertIn(message, stream.getvalue())
General Comments 0
You need to be logged in to leave comments. Login now