##// END OF EJS Templates
Add more tests
Quentin Peter -
Show More
@@ -1,446 +1,459 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 Python3ChainedExceptionsTest(unittest.TestCase):
256 class Python3ChainedExceptionsTest(unittest.TestCase):
257 DIRECT_CAUSE_ERROR_CODE = """
257 DIRECT_CAUSE_ERROR_CODE = """
258 try:
258 try:
259 x = 1 + 2
259 x = 1 + 2
260 print(not_defined_here)
260 print(not_defined_here)
261 except Exception as e:
261 except Exception as e:
262 x += 55
262 x += 55
263 x - 1
263 x - 1
264 y = {}
264 y = {}
265 raise KeyError('uh') from e
265 raise KeyError('uh') from e
266 """
266 """
267
267
268 EXCEPTION_DURING_HANDLING_CODE = """
268 EXCEPTION_DURING_HANDLING_CODE = """
269 try:
269 try:
270 x = 1 + 2
270 x = 1 + 2
271 print(not_defined_here)
271 print(not_defined_here)
272 except Exception as e:
272 except Exception as e:
273 x += 55
273 x += 55
274 x - 1
274 x - 1
275 y = {}
275 y = {}
276 raise KeyError('uh')
276 raise KeyError('uh')
277 """
277 """
278
278
279 SUPPRESS_CHAINING_CODE = """
279 SUPPRESS_CHAINING_CODE = """
280 try:
280 try:
281 1/0
281 1/0
282 except Exception:
282 except Exception:
283 raise ValueError("Yikes") from None
283 raise ValueError("Yikes") from None
284 """
284 """
285
285
286 def test_direct_cause_error(self):
286 def test_direct_cause_error(self):
287 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
287 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
288 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
288 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
289
289
290 def test_exception_during_handling_error(self):
290 def test_exception_during_handling_error(self):
291 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
291 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
292 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
292 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
293
293
294 def test_suppress_exception_chaining(self):
294 def test_suppress_exception_chaining(self):
295 with tt.AssertNotPrints("ZeroDivisionError"), \
295 with tt.AssertNotPrints("ZeroDivisionError"), \
296 tt.AssertPrints("ValueError", suppress=False):
296 tt.AssertPrints("ValueError", suppress=False):
297 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
297 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
298
298
299 def test_plain_exception(self):
299 def test_plain_direct_cause_error(self):
300 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
301 ip.run_cell("%xmode Plain")
302 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
303 ip.run_cell("%xmode Verbose")
304
305 def test_plain_exception_during_handling_error(self):
300 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
306 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
301 ip.run_cell("%xmode Plain")
307 ip.run_cell("%xmode Plain")
302 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
308 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
303 ip.run_cell("%xmode Verbose")
309 ip.run_cell("%xmode Verbose")
304
310
311 def test_plain_suppress_exception_chaining(self):
312 with tt.AssertNotPrints("ZeroDivisionError"), \
313 tt.AssertPrints("ValueError", suppress=False):
314 ip.run_cell("%xmode Plain")
315 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
316 ip.run_cell("%xmode Verbose")
317
305
318
306 class RecursionTest(unittest.TestCase):
319 class RecursionTest(unittest.TestCase):
307 DEFINITIONS = """
320 DEFINITIONS = """
308 def non_recurs():
321 def non_recurs():
309 1/0
322 1/0
310
323
311 def r1():
324 def r1():
312 r1()
325 r1()
313
326
314 def r3a():
327 def r3a():
315 r3b()
328 r3b()
316
329
317 def r3b():
330 def r3b():
318 r3c()
331 r3c()
319
332
320 def r3c():
333 def r3c():
321 r3a()
334 r3a()
322
335
323 def r3o1():
336 def r3o1():
324 r3a()
337 r3a()
325
338
326 def r3o2():
339 def r3o2():
327 r3o1()
340 r3o1()
328 """
341 """
329 def setUp(self):
342 def setUp(self):
330 ip.run_cell(self.DEFINITIONS)
343 ip.run_cell(self.DEFINITIONS)
331
344
332 def test_no_recursion(self):
345 def test_no_recursion(self):
333 with tt.AssertNotPrints("frames repeated"):
346 with tt.AssertNotPrints("frames repeated"):
334 ip.run_cell("non_recurs()")
347 ip.run_cell("non_recurs()")
335
348
336 @recursionlimit(150)
349 @recursionlimit(150)
337 def test_recursion_one_frame(self):
350 def test_recursion_one_frame(self):
338 with tt.AssertPrints("1 frames repeated"):
351 with tt.AssertPrints("1 frames repeated"):
339 ip.run_cell("r1()")
352 ip.run_cell("r1()")
340
353
341 @recursionlimit(150)
354 @recursionlimit(150)
342 def test_recursion_three_frames(self):
355 def test_recursion_three_frames(self):
343 with tt.AssertPrints("3 frames repeated"):
356 with tt.AssertPrints("3 frames repeated"):
344 ip.run_cell("r3o2()")
357 ip.run_cell("r3o2()")
345
358
346 @recursionlimit(150)
359 @recursionlimit(150)
347 def test_find_recursion(self):
360 def test_find_recursion(self):
348 captured = []
361 captured = []
349 def capture_exc(*args, **kwargs):
362 def capture_exc(*args, **kwargs):
350 captured.append(sys.exc_info())
363 captured.append(sys.exc_info())
351 with mock.patch.object(ip, 'showtraceback', capture_exc):
364 with mock.patch.object(ip, 'showtraceback', capture_exc):
352 ip.run_cell("r3o2()")
365 ip.run_cell("r3o2()")
353
366
354 self.assertEqual(len(captured), 1)
367 self.assertEqual(len(captured), 1)
355 etype, evalue, tb = captured[0]
368 etype, evalue, tb = captured[0]
356 self.assertIn("recursion", str(evalue))
369 self.assertIn("recursion", str(evalue))
357
370
358 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
371 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
359 for r in records[:10]:
372 for r in records[:10]:
360 print(r[1:4])
373 print(r[1:4])
361
374
362 # The outermost frames should be:
375 # The outermost frames should be:
363 # 0: the 'cell' that was running when the exception came up
376 # 0: the 'cell' that was running when the exception came up
364 # 1: r3o2()
377 # 1: r3o2()
365 # 2: r3o1()
378 # 2: r3o1()
366 # 3: r3a()
379 # 3: r3a()
367 # Then repeating r3b, r3c, r3a
380 # Then repeating r3b, r3c, r3a
368 last_unique, repeat_length = find_recursion(etype, evalue, records)
381 last_unique, repeat_length = find_recursion(etype, evalue, records)
369 self.assertEqual(last_unique, 2)
382 self.assertEqual(last_unique, 2)
370 self.assertEqual(repeat_length, 3)
383 self.assertEqual(repeat_length, 3)
371
384
372
385
373 #----------------------------------------------------------------------------
386 #----------------------------------------------------------------------------
374
387
375 # module testing (minimal)
388 # module testing (minimal)
376 def test_handlers():
389 def test_handlers():
377 def spam(c, d_e):
390 def spam(c, d_e):
378 (d, e) = d_e
391 (d, e) = d_e
379 x = c + d
392 x = c + d
380 y = c * d
393 y = c * d
381 foo(x, y)
394 foo(x, y)
382
395
383 def foo(a, b, bar=1):
396 def foo(a, b, bar=1):
384 eggs(a, b + bar)
397 eggs(a, b + bar)
385
398
386 def eggs(f, g, z=globals()):
399 def eggs(f, g, z=globals()):
387 h = f + g
400 h = f + g
388 i = f - g
401 i = f - g
389 return h / i
402 return h / i
390
403
391 buff = io.StringIO()
404 buff = io.StringIO()
392
405
393 buff.write('')
406 buff.write('')
394 buff.write('*** Before ***')
407 buff.write('*** Before ***')
395 try:
408 try:
396 buff.write(spam(1, (2, 3)))
409 buff.write(spam(1, (2, 3)))
397 except:
410 except:
398 traceback.print_exc(file=buff)
411 traceback.print_exc(file=buff)
399
412
400 handler = ColorTB(ostream=buff)
413 handler = ColorTB(ostream=buff)
401 buff.write('*** ColorTB ***')
414 buff.write('*** ColorTB ***')
402 try:
415 try:
403 buff.write(spam(1, (2, 3)))
416 buff.write(spam(1, (2, 3)))
404 except:
417 except:
405 handler(*sys.exc_info())
418 handler(*sys.exc_info())
406 buff.write('')
419 buff.write('')
407
420
408 handler = VerboseTB(ostream=buff)
421 handler = VerboseTB(ostream=buff)
409 buff.write('*** VerboseTB ***')
422 buff.write('*** VerboseTB ***')
410 try:
423 try:
411 buff.write(spam(1, (2, 3)))
424 buff.write(spam(1, (2, 3)))
412 except:
425 except:
413 handler(*sys.exc_info())
426 handler(*sys.exc_info())
414 buff.write('')
427 buff.write('')
415
428
416 from IPython.testing.decorators import skipif
429 from IPython.testing.decorators import skipif
417
430
418 class TokenizeFailureTest(unittest.TestCase):
431 class TokenizeFailureTest(unittest.TestCase):
419 """Tests related to https://github.com/ipython/ipython/issues/6864."""
432 """Tests related to https://github.com/ipython/ipython/issues/6864."""
420
433
421 # that appear to test that we are handling an exception that can be thrown
434 # that appear to test that we are handling an exception that can be thrown
422 # by the tokenizer due to a bug that seem to have been fixed in 3.8, though
435 # by the tokenizer due to a bug that seem to have been fixed in 3.8, though
423 # I'm unsure if other sequences can make it raise this error. Let's just
436 # I'm unsure if other sequences can make it raise this error. Let's just
424 # skip in 3.8 for now
437 # skip in 3.8 for now
425 @skipif(sys.version_info > (3,8))
438 @skipif(sys.version_info > (3,8))
426 def testLogging(self):
439 def testLogging(self):
427 message = "An unexpected error occurred while tokenizing input"
440 message = "An unexpected error occurred while tokenizing input"
428 cell = 'raise ValueError("""a\nb""")'
441 cell = 'raise ValueError("""a\nb""")'
429
442
430 stream = io.StringIO()
443 stream = io.StringIO()
431 handler = logging.StreamHandler(stream)
444 handler = logging.StreamHandler(stream)
432 logger = logging.getLogger()
445 logger = logging.getLogger()
433 loglevel = logger.level
446 loglevel = logger.level
434 logger.addHandler(handler)
447 logger.addHandler(handler)
435 self.addCleanup(lambda: logger.removeHandler(handler))
448 self.addCleanup(lambda: logger.removeHandler(handler))
436 self.addCleanup(lambda: logger.setLevel(loglevel))
449 self.addCleanup(lambda: logger.setLevel(loglevel))
437
450
438 logger.setLevel(logging.INFO)
451 logger.setLevel(logging.INFO)
439 with tt.AssertNotPrints(message):
452 with tt.AssertNotPrints(message):
440 ip.run_cell(cell)
453 ip.run_cell(cell)
441 self.assertNotIn(message, stream.getvalue())
454 self.assertNotIn(message, stream.getvalue())
442
455
443 logger.setLevel(logging.DEBUG)
456 logger.setLevel(logging.DEBUG)
444 with tt.AssertNotPrints(message):
457 with tt.AssertNotPrints(message):
445 ip.run_cell(cell)
458 ip.run_cell(cell)
446 self.assertIn(message, stream.getvalue())
459 self.assertIn(message, stream.getvalue())
General Comments 0
You need to be logged in to leave comments. Login now