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