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