blob: 6bd6fa6303300fdad30dedd2ed523f6f1ca8e6a2 [file] [log] [blame]
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00001"""Test cases for traceback module"""
2
Christian Heimes81ee3ef2008-05-04 22:42:01 +00003from io import StringIO
4import sys
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00005import unittest
Benjamin Petersone6528212008-07-15 15:32:09 +00006import re
Benjamin Peterson26d64ae2010-09-20 21:47:37 +00007from test.support import run_unittest, Error, captured_output
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +02008from test.support import TESTFN, unlink, cpython_only
Victor Stinner9d279b82014-12-05 10:18:30 +01009from test.script_helper import assert_python_ok
10import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000011
12import traceback
13
Christian Heimes81ee3ef2008-05-04 22:42:01 +000014
Benjamin Petersone6528212008-07-15 15:32:09 +000015class SyntaxTracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000016 # For now, a very minimal set of tests. I want to be sure that
17 # formatting of SyntaxErrors works based on changes for 2.1.
18
19 def get_exception_format(self, func, exc):
20 try:
21 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000022 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000023 return traceback.format_exception_only(exc, value)
24 else:
Collin Winter3add4d72007-08-29 23:37:32 +000025 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000026
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000027 def syntax_error_with_caret(self):
28 compile("def fact(x):\n\treturn x!\n", "?", "exec")
29
Georg Brandl751899a2009-06-04 19:41:00 +000030 def syntax_error_with_caret_2(self):
31 compile("1 +\n", "?", "exec")
32
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000033 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000034 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000035
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020036 def syntax_error_with_caret_non_ascii(self):
37 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
38
Florent Xicluna758fa5e2014-01-22 01:11:43 +010039 def syntax_error_bad_indentation2(self):
40 compile(" print(2)", "?", "exec")
41
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000042 def test_caret(self):
43 err = self.get_exception_format(self.syntax_error_with_caret,
44 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000045 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000046 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000047 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000048 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Tim Peters7e01e282001-04-08 07:44:07 +000049
Georg Brandl751899a2009-06-04 19:41:00 +000050 err = self.get_exception_format(self.syntax_error_with_caret_2,
51 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000052 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010053 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
54 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Georg Brandl751899a2009-06-04 19:41:00 +000055
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020056 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
57 SyntaxError)
58 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010059 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
60 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020061
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000062 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000063 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
64 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000065 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000066 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000067
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000068 def test_bad_indentation(self):
69 err = self.get_exception_format(self.syntax_error_bad_indentation,
70 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000071 self.assertEqual(len(err), 4)
72 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +000073 self.assertIn("^", err[2])
Guido van Rossume61fd5b2007-07-11 12:20:59 +000074 self.assertEqual(err[1].find(")"), err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075
Florent Xicluna758fa5e2014-01-22 01:11:43 +010076 err = self.get_exception_format(self.syntax_error_bad_indentation2,
77 IndentationError)
78 self.assertEqual(len(err), 4)
79 self.assertEqual(err[1].strip(), "print(2)")
80 self.assertIn("^", err[2])
81 self.assertEqual(err[1].find("p"), err[2].find("^"))
82
Thomas Wouters477c8d52006-05-27 19:21:47 +000083 def test_base_exception(self):
84 # Test that exceptions derived from BaseException are formatted right
85 e = KeyboardInterrupt()
86 lst = traceback.format_exception_only(e.__class__, e)
87 self.assertEqual(lst, ['KeyboardInterrupt\n'])
88
Thomas Wouters0e3f5912006-08-11 14:57:12 +000089 def test_format_exception_only_bad__str__(self):
90 class X(Exception):
91 def __str__(self):
92 1/0
93 err = traceback.format_exception_only(X, X())
94 self.assertEqual(len(err), 1)
95 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +000096 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +030097 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +000098 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +030099 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000100 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000101
Thomas Wouters89f507f2006-12-13 04:49:30 +0000102 def test_without_exception(self):
103 err = traceback.format_exception_only(None, None)
104 self.assertEqual(err, ['None\n'])
105
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000106 def test_encoded_file(self):
107 # Test that tracebacks are correctly printed for encoded source files:
108 # - correct line number (Issue2384)
109 # - respect file encoding (Issue3975)
110 import tempfile, sys, subprocess, os
111
112 # The spawned subprocess has its stdout redirected to a PIPE, and its
113 # encoding may be different from the current interpreter, on Windows
114 # at least.
115 process = subprocess.Popen([sys.executable, "-c",
116 "import sys; print(sys.stdout.encoding)"],
117 stdout=subprocess.PIPE,
118 stderr=subprocess.STDOUT)
119 stdout, stderr = process.communicate()
120 output_encoding = str(stdout, 'ascii').splitlines()[0]
121
122 def do_test(firstlines, message, charset, lineno):
123 # Raise the message in a subprocess, and catch the output
124 try:
125 output = open(TESTFN, "w", encoding=charset)
126 output.write("""{0}if 1:
127 import traceback;
128 raise RuntimeError('{1}')
129 """.format(firstlines, message))
130 output.close()
131 process = subprocess.Popen([sys.executable, TESTFN],
132 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
133 stdout, stderr = process.communicate()
134 stdout = stdout.decode(output_encoding).splitlines()
135 finally:
136 unlink(TESTFN)
137
138 # The source lines are encoded with the 'backslashreplace' handler
139 encoded_message = message.encode(output_encoding,
140 'backslashreplace')
141 # and we just decoded them with the output_encoding.
142 message_ascii = encoded_message.decode(output_encoding)
143
144 err_line = "raise RuntimeError('{0}')".format(message_ascii)
145 err_msg = "RuntimeError: {0}".format(message_ascii)
146
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000147 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000148 "Invalid line number: {0!r} instead of {1}".format(
149 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000150 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000151 "Invalid traceback line: {0!r} instead of {1!r}".format(
152 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000153 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000154 "Invalid error message: {0!r} instead of {1!r}".format(
155 stdout[3], err_msg))
156
157 do_test("", "foo", "ascii", 3)
158 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
159 if charset == "ascii":
160 text = "foo"
161 elif charset == "GBK":
162 text = "\u4E02\u5100"
163 else:
164 text = "h\xe9 ho"
165 do_test("# coding: {0}\n".format(charset),
166 text, charset, 4)
167 do_test("#!shebang\n# coding: {0}\n".format(charset),
168 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200169 do_test(" \t\f\n# coding: {0}\n".format(charset),
170 text, charset, 5)
171 # Issue #18960: coding spec should has no effect
172 do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000173
Victor Stinner9d279b82014-12-05 10:18:30 +0100174 def test_print_traceback_at_exit(self):
175 # Issue #22599: Ensure that it is possible to use the traceback module
176 # to display an exception at Python exit
177 code = textwrap.dedent("""
178 import sys
179 import traceback
180
181 class PrintExceptionAtExit(object):
182 def __init__(self):
183 try:
184 x = 1 / 0
185 except Exception:
186 self.exc_info = sys.exc_info()
187 # self.exc_info[1] (traceback) contains frames:
188 # explicitly clear the reference to self in the current
189 # frame to break a reference cycle
190 self = None
191
192 def __del__(self):
193 traceback.print_exception(*self.exc_info)
194
195 # Keep a reference in the module namespace to call the destructor
196 # when the module is unloaded
197 obj = PrintExceptionAtExit()
198 """)
199 rc, stdout, stderr = assert_python_ok('-c', code)
200 expected = [b'Traceback (most recent call last):',
201 b' File "<string>", line 8, in __init__',
202 b'ZeroDivisionError: division by zero']
203 self.assertEqual(stderr.splitlines(), expected)
204
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000205
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000206class TracebackFormatTests(unittest.TestCase):
207
Antoine Pitrou58720d62013-08-05 23:26:40 +0200208 def some_exception(self):
209 raise KeyError('blah')
210
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200211 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200212 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200213 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000214 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200215 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000216 except KeyError:
217 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200218 if cleanup_func is not None:
219 # Clear the inner frames, not this one
220 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000221 traceback_fmt = 'Traceback (most recent call last):\n' + \
222 ''.join(traceback.format_tb(tb))
223 file_ = StringIO()
224 traceback_print(tb, file_)
225 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400226 # Call all _tb and _exc functions
227 with captured_output("stderr") as tbstderr:
228 traceback.print_tb(tb)
229 tbfile = StringIO()
230 traceback.print_tb(tb, file=tbfile)
231 with captured_output("stderr") as excstderr:
232 traceback.print_exc()
233 excfmt = traceback.format_exc()
234 excfile = StringIO()
235 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000236 else:
237 raise Error("unable to create test traceback string")
238
239 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000240 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400241 # Now verify the _tb func output
242 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
243 # Now verify the _exc func output
244 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
245 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000246
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000247 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000248 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200249 self.assertEqual(len(tb_lines), 5)
250 banner = tb_lines[0]
251 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000252 self.assertTrue(banner.startswith('Traceback'))
253 self.assertTrue(location.startswith(' File'))
254 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000255
Antoine Pitrou58720d62013-08-05 23:26:40 +0200256 def test_traceback_format(self):
257 self.check_traceback_format()
258
259 def test_traceback_format_with_cleared_frames(self):
260 # Check that traceback formatting also works with a clear()ed frame
261 def cleanup_tb(tb):
262 tb.tb_frame.clear()
263 self.check_traceback_format(cleanup_tb)
264
Benjamin Petersond9fec152013-04-29 16:09:39 -0400265 def test_stack_format(self):
266 # Verify _stack functions. Note we have to use _getframe(1) to
267 # compare them without this frame appearing in the output
268 with captured_output("stderr") as ststderr:
269 traceback.print_stack(sys._getframe(1))
270 stfile = StringIO()
271 traceback.print_stack(sys._getframe(1), file=stfile)
272 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
273
274 stfmt = traceback.format_stack(sys._getframe(1))
275
276 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
277
Benjamin Petersone6528212008-07-15 15:32:09 +0000278
279cause_message = (
280 "\nThe above exception was the direct cause "
281 "of the following exception:\n\n")
282
283context_message = (
284 "\nDuring handling of the above exception, "
285 "another exception occurred:\n\n")
286
287boundaries = re.compile(
288 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
289
290
291class BaseExceptionReportingTests:
292
293 def get_exception(self, exception_or_callable):
294 if isinstance(exception_or_callable, Exception):
295 return exception_or_callable
296 try:
297 exception_or_callable()
298 except Exception as e:
299 return e
300
301 def zero_div(self):
302 1/0 # In zero_div
303
304 def check_zero_div(self, msg):
305 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000306 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000307 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000308 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000309
310 def test_simple(self):
311 try:
312 1/0 # Marker
313 except ZeroDivisionError as _:
314 e = _
315 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000316 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000317 self.assertTrue(lines[0].startswith('Traceback'))
318 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000319 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000320 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000321
322 def test_cause(self):
323 def inner_raise():
324 try:
325 self.zero_div()
326 except ZeroDivisionError as e:
327 raise KeyError from e
328 def outer_raise():
329 inner_raise() # Marker
330 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000331 self.assertEqual(len(blocks), 3)
332 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000333 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000334 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000335
336 def test_context(self):
337 def inner_raise():
338 try:
339 self.zero_div()
340 except ZeroDivisionError:
341 raise KeyError
342 def outer_raise():
343 inner_raise() # Marker
344 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000345 self.assertEqual(len(blocks), 3)
346 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000347 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000348 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000349
Nick Coghlanab7bf212012-02-26 17:49:52 +1000350 def test_context_suppression(self):
351 try:
352 try:
353 raise Exception
354 except:
355 raise ZeroDivisionError from None
356 except ZeroDivisionError as _:
357 e = _
358 lines = self.get_report(e).splitlines()
359 self.assertEqual(len(lines), 4)
360 self.assertTrue(lines[0].startswith('Traceback'))
361 self.assertTrue(lines[1].startswith(' File'))
362 self.assertIn('ZeroDivisionError from None', lines[2])
363 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
364
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000365 def test_cause_and_context(self):
366 # When both a cause and a context are set, only the cause should be
367 # displayed and the context should be muted.
368 def inner_raise():
369 try:
370 self.zero_div()
371 except ZeroDivisionError as _e:
372 e = _e
373 try:
374 xyzzy
375 except NameError:
376 raise KeyError from e
377 def outer_raise():
378 inner_raise() # Marker
379 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000380 self.assertEqual(len(blocks), 3)
381 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000382 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000383 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000384
Benjamin Petersone6528212008-07-15 15:32:09 +0000385 def test_cause_recursive(self):
386 def inner_raise():
387 try:
388 try:
389 self.zero_div()
390 except ZeroDivisionError as e:
391 z = e
392 raise KeyError from e
393 except KeyError as e:
394 raise z from e
395 def outer_raise():
396 inner_raise() # Marker
397 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000398 self.assertEqual(len(blocks), 3)
399 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000400 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000401 self.assertIn('raise KeyError from e', blocks[0])
402 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000403 # The second block (apart from the boundary) is the ZeroDivisionError
404 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000405 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000406 self.check_zero_div(blocks[2])
407
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000408 def test_syntax_error_offset_at_eol(self):
409 # See #10186.
410 def e():
411 raise SyntaxError('', ('', 0, 5, 'hello'))
412 msg = self.get_report(e).splitlines()
413 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000414 def e():
415 exec("x = 5 | 4 |")
416 msg = self.get_report(e).splitlines()
417 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000418
419
420class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
421 #
422 # This checks reporting through the 'traceback' module, with both
423 # format_exception() and print_exception().
424 #
425
426 def get_report(self, e):
427 e = self.get_exception(e)
428 s = ''.join(
429 traceback.format_exception(type(e), e, e.__traceback__))
430 with captured_output("stderr") as sio:
431 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000432 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000433 return s
434
435
436class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
437 #
438 # This checks built-in reporting by the interpreter.
439 #
440
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200441 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000442 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200443 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000444 e = self.get_exception(e)
445 with captured_output("stderr") as s:
446 exception_print(e)
447 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000448
449
Andrew Kuchling173a1572013-09-15 18:15:56 -0400450class MiscTracebackCases(unittest.TestCase):
451 #
452 # Check non-printing functions in traceback module
453 #
454
455 def test_clear(self):
456 def outer():
457 middle()
458 def middle():
459 inner()
460 def inner():
461 i = 1
462 1/0
463
464 try:
465 outer()
466 except:
467 type_, value, tb = sys.exc_info()
468
469 # Initial assertion: there's one local in the inner frame.
470 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
471 self.assertEqual(len(inner_frame.f_locals), 1)
472
473 # Clear traceback frames
474 traceback.clear_frames(tb)
475
476 # Local variable dict should now be empty.
477 self.assertEqual(len(inner_frame.f_locals), 0)
478
479
Fred Drake2e2be372001-09-20 21:33:42 +0000480def test_main():
Benjamin Petersone6528212008-07-15 15:32:09 +0000481 run_unittest(__name__)
Fred Drake2e2be372001-09-20 21:33:42 +0000482
483if __name__ == "__main__":
484 test_main()