blob: bffc03e663ff787f29c0bb9c8fcb9ace7586bc09 [file] [log] [blame]
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00001"""Test cases for traceback module"""
2
Robert Collins6bc2c1e2015-03-05 12:07:57 +13003from collections import namedtuple
Christian Heimes81ee3ef2008-05-04 22:42:01 +00004from io import StringIO
Robert Collins6bc2c1e2015-03-05 12:07:57 +13005import linecache
Christian Heimes81ee3ef2008-05-04 22:42:01 +00006import sys
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00007import unittest
Benjamin Petersone6528212008-07-15 15:32:09 +00008import re
Serhiy Storchaka24559e42015-05-03 13:19:46 +03009from test import support
Berker Peksag716b3d32015-04-08 09:47:14 +030010from test.support import TESTFN, Error, captured_output, unlink, cpython_only
Berker Peksagce643912015-05-06 06:33:17 +030011from test.support.script_helper import assert_python_ok
Victor Stinner9d279b82014-12-05 10:18:30 +010012import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000013
14import traceback
15
Christian Heimes81ee3ef2008-05-04 22:42:01 +000016
Robert Collins6bc2c1e2015-03-05 12:07:57 +130017test_code = namedtuple('code', ['co_filename', 'co_name'])
Robert Collinsd7c7e0e2015-03-05 20:28:52 +130018test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
Robert Collins6bc2c1e2015-03-05 12:07:57 +130019test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next'])
20
21
Martin Panterbb8b1cb2016-09-22 09:37:39 +000022class TracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000023 # For now, a very minimal set of tests. I want to be sure that
24 # formatting of SyntaxErrors works based on changes for 2.1.
25
26 def get_exception_format(self, func, exc):
27 try:
28 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000029 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000030 return traceback.format_exception_only(exc, value)
31 else:
Collin Winter3add4d72007-08-29 23:37:32 +000032 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000033
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000034 def syntax_error_with_caret(self):
35 compile("def fact(x):\n\treturn x!\n", "?", "exec")
36
Georg Brandl751899a2009-06-04 19:41:00 +000037 def syntax_error_with_caret_2(self):
38 compile("1 +\n", "?", "exec")
39
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000040 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000041 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000042
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020043 def syntax_error_with_caret_non_ascii(self):
44 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
45
Florent Xicluna758fa5e2014-01-22 01:11:43 +010046 def syntax_error_bad_indentation2(self):
47 compile(" print(2)", "?", "exec")
48
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000049 def test_caret(self):
50 err = self.get_exception_format(self.syntax_error_with_caret,
51 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000052 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000053 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000054 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000055 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Tim Peters7e01e282001-04-08 07:44:07 +000056
Georg Brandl751899a2009-06-04 19:41:00 +000057 err = self.get_exception_format(self.syntax_error_with_caret_2,
58 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000059 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010060 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
61 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Georg Brandl751899a2009-06-04 19:41:00 +000062
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020063 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
64 SyntaxError)
65 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010066 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
67 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020068
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000069 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000070 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
71 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000072 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000073 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000074
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075 def test_bad_indentation(self):
76 err = self.get_exception_format(self.syntax_error_bad_indentation,
77 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000078 self.assertEqual(len(err), 4)
79 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +000080 self.assertIn("^", err[2])
Guido van Rossume61fd5b2007-07-11 12:20:59 +000081 self.assertEqual(err[1].find(")"), err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000082
Florent Xicluna758fa5e2014-01-22 01:11:43 +010083 err = self.get_exception_format(self.syntax_error_bad_indentation2,
84 IndentationError)
85 self.assertEqual(len(err), 4)
86 self.assertEqual(err[1].strip(), "print(2)")
87 self.assertIn("^", err[2])
88 self.assertEqual(err[1].find("p"), err[2].find("^"))
89
Thomas Wouters477c8d52006-05-27 19:21:47 +000090 def test_base_exception(self):
91 # Test that exceptions derived from BaseException are formatted right
92 e = KeyboardInterrupt()
93 lst = traceback.format_exception_only(e.__class__, e)
94 self.assertEqual(lst, ['KeyboardInterrupt\n'])
95
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 def test_format_exception_only_bad__str__(self):
97 class X(Exception):
98 def __str__(self):
99 1/0
100 err = traceback.format_exception_only(X, X())
101 self.assertEqual(len(err), 1)
102 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +0000103 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300104 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +0000105 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300106 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000107 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000109 def test_encoded_file(self):
110 # Test that tracebacks are correctly printed for encoded source files:
111 # - correct line number (Issue2384)
112 # - respect file encoding (Issue3975)
113 import tempfile, sys, subprocess, os
114
115 # The spawned subprocess has its stdout redirected to a PIPE, and its
116 # encoding may be different from the current interpreter, on Windows
117 # at least.
118 process = subprocess.Popen([sys.executable, "-c",
119 "import sys; print(sys.stdout.encoding)"],
120 stdout=subprocess.PIPE,
121 stderr=subprocess.STDOUT)
122 stdout, stderr = process.communicate()
123 output_encoding = str(stdout, 'ascii').splitlines()[0]
124
125 def do_test(firstlines, message, charset, lineno):
126 # Raise the message in a subprocess, and catch the output
127 try:
Victor Stinner51d8c522016-02-08 17:57:02 +0100128 with open(TESTFN, "w", encoding=charset) as output:
129 output.write("""{0}if 1:
130 import traceback;
131 raise RuntimeError('{1}')
132 """.format(firstlines, message))
133
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000134 process = subprocess.Popen([sys.executable, TESTFN],
135 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
136 stdout, stderr = process.communicate()
137 stdout = stdout.decode(output_encoding).splitlines()
138 finally:
139 unlink(TESTFN)
140
141 # The source lines are encoded with the 'backslashreplace' handler
142 encoded_message = message.encode(output_encoding,
143 'backslashreplace')
144 # and we just decoded them with the output_encoding.
145 message_ascii = encoded_message.decode(output_encoding)
146
147 err_line = "raise RuntimeError('{0}')".format(message_ascii)
148 err_msg = "RuntimeError: {0}".format(message_ascii)
149
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000150 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000151 "Invalid line number: {0!r} instead of {1}".format(
152 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000153 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000154 "Invalid traceback line: {0!r} instead of {1!r}".format(
155 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000156 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000157 "Invalid error message: {0!r} instead of {1!r}".format(
158 stdout[3], err_msg))
159
160 do_test("", "foo", "ascii", 3)
161 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
162 if charset == "ascii":
163 text = "foo"
164 elif charset == "GBK":
165 text = "\u4E02\u5100"
166 else:
167 text = "h\xe9 ho"
168 do_test("# coding: {0}\n".format(charset),
169 text, charset, 4)
170 do_test("#!shebang\n# coding: {0}\n".format(charset),
171 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200172 do_test(" \t\f\n# coding: {0}\n".format(charset),
173 text, charset, 5)
Martin Panter614827c2016-04-19 04:05:59 +0000174 # Issue #18960: coding spec should have no effect
Victor Stinner51d8c522016-02-08 17:57:02 +0100175 do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000176
Serhiy Storchakaa7930372016-07-03 22:27:26 +0300177 @support.requires_type_collecting
Victor Stinner9d279b82014-12-05 10:18:30 +0100178 def test_print_traceback_at_exit(self):
179 # Issue #22599: Ensure that it is possible to use the traceback module
180 # to display an exception at Python exit
181 code = textwrap.dedent("""
182 import sys
183 import traceback
184
185 class PrintExceptionAtExit(object):
186 def __init__(self):
187 try:
188 x = 1 / 0
189 except Exception:
190 self.exc_info = sys.exc_info()
191 # self.exc_info[1] (traceback) contains frames:
192 # explicitly clear the reference to self in the current
193 # frame to break a reference cycle
194 self = None
195
196 def __del__(self):
197 traceback.print_exception(*self.exc_info)
198
199 # Keep a reference in the module namespace to call the destructor
200 # when the module is unloaded
201 obj = PrintExceptionAtExit()
202 """)
203 rc, stdout, stderr = assert_python_ok('-c', code)
204 expected = [b'Traceback (most recent call last):',
205 b' File "<string>", line 8, in __init__',
206 b'ZeroDivisionError: division by zero']
207 self.assertEqual(stderr.splitlines(), expected)
208
Berker Peksagc3f417d2015-07-24 17:36:21 +0300209 def test_print_exception(self):
210 output = StringIO()
211 traceback.print_exception(
212 Exception, Exception("projector"), None, file=output
213 )
214 self.assertEqual(output.getvalue(), "Exception: projector\n")
215
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000216
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000217class TracebackFormatTests(unittest.TestCase):
218
Antoine Pitrou58720d62013-08-05 23:26:40 +0200219 def some_exception(self):
220 raise KeyError('blah')
221
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200222 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200223 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200224 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000225 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200226 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000227 except KeyError:
228 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200229 if cleanup_func is not None:
230 # Clear the inner frames, not this one
231 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000232 traceback_fmt = 'Traceback (most recent call last):\n' + \
233 ''.join(traceback.format_tb(tb))
234 file_ = StringIO()
235 traceback_print(tb, file_)
236 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400237 # Call all _tb and _exc functions
238 with captured_output("stderr") as tbstderr:
239 traceback.print_tb(tb)
240 tbfile = StringIO()
241 traceback.print_tb(tb, file=tbfile)
242 with captured_output("stderr") as excstderr:
243 traceback.print_exc()
244 excfmt = traceback.format_exc()
245 excfile = StringIO()
246 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000247 else:
248 raise Error("unable to create test traceback string")
249
250 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000251 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400252 # Now verify the _tb func output
253 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
254 # Now verify the _exc func output
255 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
256 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000257
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000258 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000259 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200260 self.assertEqual(len(tb_lines), 5)
261 banner = tb_lines[0]
262 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000263 self.assertTrue(banner.startswith('Traceback'))
264 self.assertTrue(location.startswith(' File'))
265 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000266
Antoine Pitrou58720d62013-08-05 23:26:40 +0200267 def test_traceback_format(self):
268 self.check_traceback_format()
269
270 def test_traceback_format_with_cleared_frames(self):
271 # Check that traceback formatting also works with a clear()ed frame
272 def cleanup_tb(tb):
273 tb.tb_frame.clear()
274 self.check_traceback_format(cleanup_tb)
275
Benjamin Petersond9fec152013-04-29 16:09:39 -0400276 def test_stack_format(self):
277 # Verify _stack functions. Note we have to use _getframe(1) to
278 # compare them without this frame appearing in the output
279 with captured_output("stderr") as ststderr:
280 traceback.print_stack(sys._getframe(1))
281 stfile = StringIO()
282 traceback.print_stack(sys._getframe(1), file=stfile)
283 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
284
285 stfmt = traceback.format_stack(sys._getframe(1))
286
287 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
288
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300289 def test_print_stack(self):
290 def prn():
291 traceback.print_stack()
292 with captured_output("stderr") as stderr:
293 prn()
294 lineno = prn.__code__.co_firstlineno
295 self.assertEqual(stderr.getvalue().splitlines()[-4:], [
296 ' File "%s", line %d, in test_print_stack' % (__file__, lineno+3),
297 ' prn()',
298 ' File "%s", line %d, in prn' % (__file__, lineno+1),
299 ' traceback.print_stack()',
300 ])
301
Nick Coghland0034232016-08-15 13:11:34 +1000302 # issue 26823 - Shrink recursive tracebacks
303 def _check_recursive_traceback_display(self, render_exc):
304 # Always show full diffs when this test fails
305 # Note that rearranging things may require adjusting
306 # the relative line numbers in the expected tracebacks
307 self.maxDiff = None
308
309 # Check hitting the recursion limit
310 def f():
311 f()
312
313 with captured_output("stderr") as stderr_f:
314 try:
315 f()
316 except RecursionError as exc:
317 render_exc()
318 else:
319 self.fail("no recursion occurred")
320
321 lineno_f = f.__code__.co_firstlineno
322 result_f = (
323 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400324 f' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000325 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400326 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000327 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400328 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000329 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400330 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000331 ' f()\n'
332 # XXX: The following line changes depending on whether the tests
333 # are run through the interactive interpreter or with -m
334 # It also varies depending on the platform (stack size)
335 # Fortunately, we don't care about exactness here, so we use regex
336 r' \[Previous line repeated (\d+) more times\]' '\n'
337 'RecursionError: maximum recursion depth exceeded\n'
338 )
339
340 expected = result_f.splitlines()
341 actual = stderr_f.getvalue().splitlines()
342
343 # Check the output text matches expectations
344 # 2nd last line contains the repetition count
345 self.assertEqual(actual[:-2], expected[:-2])
346 self.assertRegex(actual[-2], expected[-2])
codedragon3480ef92017-05-24 14:23:46 -0700347 # last line can have additional text appended
348 self.assertIn(expected[-1], actual[-1])
Nick Coghland0034232016-08-15 13:11:34 +1000349
350 # Check the recursion count is roughly as expected
351 rec_limit = sys.getrecursionlimit()
Serhiy Storchakab7281052016-09-12 00:52:40 +0300352 self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
Nick Coghland0034232016-08-15 13:11:34 +1000353
354 # Check a known (limited) number of recursive invocations
355 def g(count=10):
356 if count:
357 return g(count-1)
358 raise ValueError
359
360 with captured_output("stderr") as stderr_g:
361 try:
362 g()
363 except ValueError as exc:
364 render_exc()
365 else:
366 self.fail("no value error was raised")
367
368 lineno_g = g.__code__.co_firstlineno
369 result_g = (
Eric V. Smith451d0e32016-09-09 21:56:20 -0400370 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000371 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400372 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000373 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400374 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000375 ' return g(count-1)\n'
376 ' [Previous line repeated 6 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400377 f' File "{__file__}", line {lineno_g+3}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000378 ' raise ValueError\n'
379 'ValueError\n'
380 )
381 tb_line = (
382 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400383 f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000384 ' g()\n'
385 )
386 expected = (tb_line + result_g).splitlines()
387 actual = stderr_g.getvalue().splitlines()
388 self.assertEqual(actual, expected)
389
390 # Check 2 different repetitive sections
391 def h(count=10):
392 if count:
393 return h(count-1)
394 g()
395
396 with captured_output("stderr") as stderr_h:
397 try:
398 h()
399 except ValueError as exc:
400 render_exc()
401 else:
402 self.fail("no value error was raised")
403
404 lineno_h = h.__code__.co_firstlineno
405 result_h = (
406 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400407 f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000408 ' h()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400409 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000410 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400411 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000412 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400413 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000414 ' return h(count-1)\n'
415 ' [Previous line repeated 6 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400416 f' File "{__file__}", line {lineno_h+3}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000417 ' g()\n'
418 )
419 expected = (result_h + result_g).splitlines()
420 actual = stderr_h.getvalue().splitlines()
421 self.assertEqual(actual, expected)
422
423 def test_recursive_traceback_python(self):
424 self._check_recursive_traceback_display(traceback.print_exc)
425
426 @cpython_only
427 def test_recursive_traceback_cpython_internal(self):
428 from _testcapi import exception_print
429 def render_exc():
430 exc_type, exc_value, exc_tb = sys.exc_info()
431 exception_print(exc_value)
432 self._check_recursive_traceback_display(render_exc)
433
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300434 def test_format_stack(self):
435 def fmt():
436 return traceback.format_stack()
437 result = fmt()
438 lineno = fmt.__code__.co_firstlineno
439 self.assertEqual(result[-2:], [
440 ' File "%s", line %d, in test_format_stack\n'
441 ' result = fmt()\n' % (__file__, lineno+2),
442 ' File "%s", line %d, in fmt\n'
443 ' return traceback.format_stack()\n' % (__file__, lineno+1),
444 ])
445
Zane Bitterde860732017-10-17 17:29:39 -0400446 @cpython_only
447 def test_unhashable(self):
448 from _testcapi import exception_print
449
450 class UnhashableException(Exception):
451 def __eq__(self, other):
452 return True
453
454 ex1 = UnhashableException('ex1')
455 ex2 = UnhashableException('ex2')
456 try:
457 raise ex2 from ex1
458 except UnhashableException:
459 try:
460 raise ex1
461 except UnhashableException:
462 exc_type, exc_val, exc_tb = sys.exc_info()
463
464 with captured_output("stderr") as stderr_f:
465 exception_print(exc_val)
466
467 tb = stderr_f.getvalue().strip().splitlines()
468 self.assertEqual(11, len(tb))
469 self.assertEqual(context_message.strip(), tb[5])
470 self.assertIn('UnhashableException: ex2', tb[3])
471 self.assertIn('UnhashableException: ex1', tb[10])
472
Benjamin Petersone6528212008-07-15 15:32:09 +0000473
474cause_message = (
475 "\nThe above exception was the direct cause "
476 "of the following exception:\n\n")
477
478context_message = (
479 "\nDuring handling of the above exception, "
480 "another exception occurred:\n\n")
481
482boundaries = re.compile(
483 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
484
485
486class BaseExceptionReportingTests:
487
488 def get_exception(self, exception_or_callable):
489 if isinstance(exception_or_callable, Exception):
490 return exception_or_callable
491 try:
492 exception_or_callable()
493 except Exception as e:
494 return e
495
496 def zero_div(self):
497 1/0 # In zero_div
498
499 def check_zero_div(self, msg):
500 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000501 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000502 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000503 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000504
505 def test_simple(self):
506 try:
507 1/0 # Marker
508 except ZeroDivisionError as _:
509 e = _
510 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000511 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000512 self.assertTrue(lines[0].startswith('Traceback'))
513 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000514 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000515 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000516
517 def test_cause(self):
518 def inner_raise():
519 try:
520 self.zero_div()
521 except ZeroDivisionError as e:
522 raise KeyError from e
523 def outer_raise():
524 inner_raise() # Marker
525 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000526 self.assertEqual(len(blocks), 3)
527 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000528 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000529 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000530
531 def test_context(self):
532 def inner_raise():
533 try:
534 self.zero_div()
535 except ZeroDivisionError:
536 raise KeyError
537 def outer_raise():
538 inner_raise() # Marker
539 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000540 self.assertEqual(len(blocks), 3)
541 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000542 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000543 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000544
Nick Coghlanab7bf212012-02-26 17:49:52 +1000545 def test_context_suppression(self):
546 try:
547 try:
548 raise Exception
549 except:
550 raise ZeroDivisionError from None
551 except ZeroDivisionError as _:
552 e = _
553 lines = self.get_report(e).splitlines()
554 self.assertEqual(len(lines), 4)
555 self.assertTrue(lines[0].startswith('Traceback'))
556 self.assertTrue(lines[1].startswith(' File'))
557 self.assertIn('ZeroDivisionError from None', lines[2])
558 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
559
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000560 def test_cause_and_context(self):
561 # When both a cause and a context are set, only the cause should be
562 # displayed and the context should be muted.
563 def inner_raise():
564 try:
565 self.zero_div()
566 except ZeroDivisionError as _e:
567 e = _e
568 try:
569 xyzzy
570 except NameError:
571 raise KeyError from e
572 def outer_raise():
573 inner_raise() # Marker
574 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000575 self.assertEqual(len(blocks), 3)
576 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000577 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000578 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000579
Benjamin Petersone6528212008-07-15 15:32:09 +0000580 def test_cause_recursive(self):
581 def inner_raise():
582 try:
583 try:
584 self.zero_div()
585 except ZeroDivisionError as e:
586 z = e
587 raise KeyError from e
588 except KeyError as e:
589 raise z from e
590 def outer_raise():
591 inner_raise() # Marker
592 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000593 self.assertEqual(len(blocks), 3)
594 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000595 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000596 self.assertIn('raise KeyError from e', blocks[0])
597 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000598 # The second block (apart from the boundary) is the ZeroDivisionError
599 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000600 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000601 self.check_zero_div(blocks[2])
602
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000603 def test_syntax_error_offset_at_eol(self):
604 # See #10186.
605 def e():
606 raise SyntaxError('', ('', 0, 5, 'hello'))
607 msg = self.get_report(e).splitlines()
608 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000609 def e():
610 exec("x = 5 | 4 |")
611 msg = self.get_report(e).splitlines()
612 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000613
Martin Panterbb8b1cb2016-09-22 09:37:39 +0000614 def test_message_none(self):
615 # A message that looks like "None" should not be treated specially
616 err = self.get_report(Exception(None))
617 self.assertIn('Exception: None\n', err)
618 err = self.get_report(Exception('None'))
619 self.assertIn('Exception: None\n', err)
620 err = self.get_report(Exception())
621 self.assertIn('Exception\n', err)
622 err = self.get_report(Exception(''))
623 self.assertIn('Exception\n', err)
624
Benjamin Petersone6528212008-07-15 15:32:09 +0000625
626class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
627 #
628 # This checks reporting through the 'traceback' module, with both
629 # format_exception() and print_exception().
630 #
631
632 def get_report(self, e):
633 e = self.get_exception(e)
634 s = ''.join(
635 traceback.format_exception(type(e), e, e.__traceback__))
636 with captured_output("stderr") as sio:
637 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000638 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000639 return s
640
641
642class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
643 #
644 # This checks built-in reporting by the interpreter.
645 #
646
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200647 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000648 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200649 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000650 e = self.get_exception(e)
651 with captured_output("stderr") as s:
652 exception_print(e)
653 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000654
655
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300656class LimitTests(unittest.TestCase):
657
658 ''' Tests for limit argument.
659 It's enough to test extact_tb, extract_stack and format_exception '''
660
661 def last_raises1(self):
662 raise Exception('Last raised')
663
664 def last_raises2(self):
665 self.last_raises1()
666
667 def last_raises3(self):
668 self.last_raises2()
669
670 def last_raises4(self):
671 self.last_raises3()
672
673 def last_raises5(self):
674 self.last_raises4()
675
676 def last_returns_frame1(self):
677 return sys._getframe()
678
679 def last_returns_frame2(self):
680 return self.last_returns_frame1()
681
682 def last_returns_frame3(self):
683 return self.last_returns_frame2()
684
685 def last_returns_frame4(self):
686 return self.last_returns_frame3()
687
688 def last_returns_frame5(self):
689 return self.last_returns_frame4()
690
691 def test_extract_stack(self):
692 frame = self.last_returns_frame5()
693 def extract(**kwargs):
694 return traceback.extract_stack(frame, **kwargs)
695 def assertEqualExcept(actual, expected, ignore):
696 self.assertEqual(actual[:ignore], expected[:ignore])
697 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
698 self.assertEqual(len(actual), len(expected))
699
700 with support.swap_attr(sys, 'tracebacklimit', 1000):
701 nolim = extract()
702 self.assertGreater(len(nolim), 5)
703 self.assertEqual(extract(limit=2), nolim[-2:])
704 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
705 self.assertEqual(extract(limit=-2), nolim[:2])
706 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
707 self.assertEqual(extract(limit=0), [])
708 del sys.tracebacklimit
709 assertEqualExcept(extract(), nolim, -5-1)
710 sys.tracebacklimit = 2
711 self.assertEqual(extract(), nolim[-2:])
712 self.assertEqual(extract(limit=3), nolim[-3:])
713 self.assertEqual(extract(limit=-3), nolim[:3])
714 sys.tracebacklimit = 0
715 self.assertEqual(extract(), [])
716 sys.tracebacklimit = -1
717 self.assertEqual(extract(), [])
718
719 def test_extract_tb(self):
720 try:
721 self.last_raises5()
722 except Exception:
723 exc_type, exc_value, tb = sys.exc_info()
724 def extract(**kwargs):
725 return traceback.extract_tb(tb, **kwargs)
726
727 with support.swap_attr(sys, 'tracebacklimit', 1000):
728 nolim = extract()
729 self.assertEqual(len(nolim), 5+1)
730 self.assertEqual(extract(limit=2), nolim[:2])
731 self.assertEqual(extract(limit=10), nolim)
732 self.assertEqual(extract(limit=-2), nolim[-2:])
733 self.assertEqual(extract(limit=-10), nolim)
734 self.assertEqual(extract(limit=0), [])
735 del sys.tracebacklimit
736 self.assertEqual(extract(), nolim)
737 sys.tracebacklimit = 2
738 self.assertEqual(extract(), nolim[:2])
739 self.assertEqual(extract(limit=3), nolim[:3])
740 self.assertEqual(extract(limit=-3), nolim[-3:])
741 sys.tracebacklimit = 0
742 self.assertEqual(extract(), [])
743 sys.tracebacklimit = -1
744 self.assertEqual(extract(), [])
745
746 def test_format_exception(self):
747 try:
748 self.last_raises5()
749 except Exception:
750 exc_type, exc_value, tb = sys.exc_info()
751 # [1:-1] to exclude "Traceback (...)" header and
752 # exception type and value
753 def extract(**kwargs):
754 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
755
756 with support.swap_attr(sys, 'tracebacklimit', 1000):
757 nolim = extract()
758 self.assertEqual(len(nolim), 5+1)
759 self.assertEqual(extract(limit=2), nolim[:2])
760 self.assertEqual(extract(limit=10), nolim)
761 self.assertEqual(extract(limit=-2), nolim[-2:])
762 self.assertEqual(extract(limit=-10), nolim)
763 self.assertEqual(extract(limit=0), [])
764 del sys.tracebacklimit
765 self.assertEqual(extract(), nolim)
766 sys.tracebacklimit = 2
767 self.assertEqual(extract(), nolim[:2])
768 self.assertEqual(extract(limit=3), nolim[:3])
769 self.assertEqual(extract(limit=-3), nolim[-3:])
770 sys.tracebacklimit = 0
771 self.assertEqual(extract(), [])
772 sys.tracebacklimit = -1
773 self.assertEqual(extract(), [])
774
775
Andrew Kuchling173a1572013-09-15 18:15:56 -0400776class MiscTracebackCases(unittest.TestCase):
777 #
778 # Check non-printing functions in traceback module
779 #
780
781 def test_clear(self):
782 def outer():
783 middle()
784 def middle():
785 inner()
786 def inner():
787 i = 1
788 1/0
789
790 try:
791 outer()
792 except:
793 type_, value, tb = sys.exc_info()
794
795 # Initial assertion: there's one local in the inner frame.
796 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
797 self.assertEqual(len(inner_frame.f_locals), 1)
798
799 # Clear traceback frames
800 traceback.clear_frames(tb)
801
802 # Local variable dict should now be empty.
803 self.assertEqual(len(inner_frame.f_locals), 0)
804
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300805 def test_extract_stack(self):
806 def extract():
807 return traceback.extract_stack()
808 result = extract()
809 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300810 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300811 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
812 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
813 ])
814
Andrew Kuchling173a1572013-09-15 18:15:56 -0400815
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300816class TestFrame(unittest.TestCase):
817
818 def test_basics(self):
819 linecache.clearcache()
820 linecache.lazycache("f", globals())
821 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300822 self.assertEqual(f,
823 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
824 self.assertEqual(tuple(f),
825 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
826 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
827 self.assertEqual(f, tuple(f))
828 # Since tuple.__eq__ doesn't support FrameSummary, the equality
829 # operator fallbacks to FrameSummary.__eq__.
830 self.assertEqual(tuple(f), f)
831 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300832
833 def test_lazy_lines(self):
834 linecache.clearcache()
835 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
836 self.assertEqual(None, f._line)
837 linecache.lazycache("f", globals())
838 self.assertEqual(
839 '"""Test cases for traceback module"""',
840 f.line)
841
842 def test_explicit_line(self):
843 f = traceback.FrameSummary("f", 1, "dummy", line="line")
844 self.assertEqual("line", f.line)
845
846
847class TestStack(unittest.TestCase):
848
849 def test_walk_stack(self):
Serhiy Storchaka1c1130f2016-10-07 23:45:42 +0300850 def deeper():
851 return list(traceback.walk_stack(None))
852 s1 = list(traceback.walk_stack(None))
853 s2 = deeper()
854 self.assertEqual(len(s2) - len(s1), 1)
855 self.assertEqual(s2[1:], s1)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300856
857 def test_walk_tb(self):
858 try:
859 1/0
860 except Exception:
861 _, _, tb = sys.exc_info()
862 s = list(traceback.walk_tb(tb))
863 self.assertEqual(len(s), 1)
864
865 def test_extract_stack(self):
866 s = traceback.StackSummary.extract(traceback.walk_stack(None))
867 self.assertIsInstance(s, traceback.StackSummary)
868
869 def test_extract_stack_limit(self):
870 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
871 self.assertEqual(len(s), 5)
872
873 def test_extract_stack_lookup_lines(self):
874 linecache.clearcache()
875 linecache.updatecache('/foo.py', globals())
876 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300877 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300878 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
879 linecache.clearcache()
880 self.assertEqual(s[0].line, "import sys")
881
882 def test_extract_stackup_deferred_lookup_lines(self):
883 linecache.clearcache()
884 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300885 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300886 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
887 self.assertEqual({}, linecache.cache)
888 linecache.updatecache('/foo.py', globals())
889 self.assertEqual(s[0].line, "import sys")
890
891 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300892 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300893 self.assertEqual(
894 [' File "foo.py", line 1, in fred\n line\n'],
895 s.format())
896
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300897 def test_from_list_edited_stack(self):
898 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
899 s[0] = ('foo.py', 2, 'fred', 'line')
900 s2 = traceback.StackSummary.from_list(s)
901 self.assertEqual(
902 [' File "foo.py", line 2, in fred\n line\n'],
903 s2.format())
904
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300905 def test_format_smoke(self):
906 # For detailed tests see the format_list tests, which consume the same
907 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300908 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300909 self.assertEqual(
910 [' File "foo.py", line 1, in fred\n line\n'],
911 s.format())
912
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300913 def test_locals(self):
914 linecache.updatecache('/foo.py', globals())
915 c = test_code('/foo.py', 'method')
916 f = test_frame(c, globals(), {'something': 1})
917 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
918 self.assertEqual(s[0].locals, {'something': '1'})
919
920 def test_no_locals(self):
921 linecache.updatecache('/foo.py', globals())
922 c = test_code('/foo.py', 'method')
923 f = test_frame(c, globals(), {'something': 1})
924 s = traceback.StackSummary.extract(iter([(f, 6)]))
925 self.assertEqual(s[0].locals, None)
926
927 def test_format_locals(self):
928 def some_inner(k, v):
929 a = 1
930 b = 2
931 return traceback.StackSummary.extract(
932 traceback.walk_stack(None), capture_locals=True, limit=1)
933 s = some_inner(3, 4)
934 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300935 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300936 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
937 ' a = 1\n'
938 ' b = 2\n'
939 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300940 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300941 ], s.format())
942
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300943class TestTracebackException(unittest.TestCase):
944
945 def test_smoke(self):
946 try:
947 1/0
948 except Exception:
949 exc_info = sys.exc_info()
950 exc = traceback.TracebackException(*exc_info)
951 expected_stack = traceback.StackSummary.extract(
952 traceback.walk_tb(exc_info[2]))
953 self.assertEqual(None, exc.__cause__)
954 self.assertEqual(None, exc.__context__)
955 self.assertEqual(False, exc.__suppress_context__)
956 self.assertEqual(expected_stack, exc.stack)
957 self.assertEqual(exc_info[0], exc.exc_type)
958 self.assertEqual(str(exc_info[1]), str(exc))
959
960 def test_from_exception(self):
961 # Check all the parameters are accepted.
962 def foo():
963 1/0
964 try:
965 foo()
966 except Exception as e:
967 exc_info = sys.exc_info()
968 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300969 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
970 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300971 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300972 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300973 expected_stack = self.expected_stack
974 exc = self.exc
975 self.assertEqual(None, exc.__cause__)
976 self.assertEqual(None, exc.__context__)
977 self.assertEqual(False, exc.__suppress_context__)
978 self.assertEqual(expected_stack, exc.stack)
979 self.assertEqual(exc_info[0], exc.exc_type)
980 self.assertEqual(str(exc_info[1]), str(exc))
981
982 def test_cause(self):
983 try:
984 try:
985 1/0
986 finally:
987 exc_info_context = sys.exc_info()
988 exc_context = traceback.TracebackException(*exc_info_context)
989 cause = Exception("cause")
990 raise Exception("uh oh") from cause
991 except Exception:
992 exc_info = sys.exc_info()
993 exc = traceback.TracebackException(*exc_info)
994 expected_stack = traceback.StackSummary.extract(
995 traceback.walk_tb(exc_info[2]))
996 exc_cause = traceback.TracebackException(Exception, cause, None)
997 self.assertEqual(exc_cause, exc.__cause__)
998 self.assertEqual(exc_context, exc.__context__)
999 self.assertEqual(True, exc.__suppress_context__)
1000 self.assertEqual(expected_stack, exc.stack)
1001 self.assertEqual(exc_info[0], exc.exc_type)
1002 self.assertEqual(str(exc_info[1]), str(exc))
1003
1004 def test_context(self):
1005 try:
1006 try:
1007 1/0
1008 finally:
1009 exc_info_context = sys.exc_info()
1010 exc_context = traceback.TracebackException(*exc_info_context)
1011 raise Exception("uh oh")
1012 except Exception:
1013 exc_info = sys.exc_info()
1014 exc = traceback.TracebackException(*exc_info)
1015 expected_stack = traceback.StackSummary.extract(
1016 traceback.walk_tb(exc_info[2]))
1017 self.assertEqual(None, exc.__cause__)
1018 self.assertEqual(exc_context, exc.__context__)
1019 self.assertEqual(False, exc.__suppress_context__)
1020 self.assertEqual(expected_stack, exc.stack)
1021 self.assertEqual(exc_info[0], exc.exc_type)
1022 self.assertEqual(str(exc_info[1]), str(exc))
1023
Zane Bitterde860732017-10-17 17:29:39 -04001024 def test_unhashable(self):
1025 class UnhashableException(Exception):
1026 def __eq__(self, other):
1027 return True
1028
1029 ex1 = UnhashableException('ex1')
1030 ex2 = UnhashableException('ex2')
1031 try:
1032 raise ex2 from ex1
1033 except UnhashableException:
1034 try:
1035 raise ex1
1036 except UnhashableException:
1037 exc_info = sys.exc_info()
1038 exc = traceback.TracebackException(*exc_info)
1039 formatted = list(exc.format())
1040 self.assertIn('UnhashableException: ex2\n', formatted[2])
1041 self.assertIn('UnhashableException: ex1\n', formatted[6])
1042
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001043 def test_limit(self):
1044 def recurse(n):
1045 if n:
1046 recurse(n-1)
1047 else:
1048 1/0
1049 try:
1050 recurse(10)
1051 except Exception:
1052 exc_info = sys.exc_info()
1053 exc = traceback.TracebackException(*exc_info, limit=5)
1054 expected_stack = traceback.StackSummary.extract(
1055 traceback.walk_tb(exc_info[2]), limit=5)
1056 self.assertEqual(expected_stack, exc.stack)
1057
1058 def test_lookup_lines(self):
1059 linecache.clearcache()
1060 e = Exception("uh oh")
1061 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001062 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001063 tb = test_tb(f, 6, None)
1064 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
1065 self.assertEqual({}, linecache.cache)
1066 linecache.updatecache('/foo.py', globals())
1067 self.assertEqual(exc.stack[0].line, "import sys")
1068
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001069 def test_locals(self):
1070 linecache.updatecache('/foo.py', globals())
1071 e = Exception("uh oh")
1072 c = test_code('/foo.py', 'method')
1073 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
1074 tb = test_tb(f, 6, None)
1075 exc = traceback.TracebackException(
1076 Exception, e, tb, capture_locals=True)
1077 self.assertEqual(
1078 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
1079
1080 def test_no_locals(self):
1081 linecache.updatecache('/foo.py', globals())
1082 e = Exception("uh oh")
1083 c = test_code('/foo.py', 'method')
1084 f = test_frame(c, globals(), {'something': 1})
1085 tb = test_tb(f, 6, None)
1086 exc = traceback.TracebackException(Exception, e, tb)
1087 self.assertEqual(exc.stack[0].locals, None)
1088
Berker Peksagc3f417d2015-07-24 17:36:21 +03001089 def test_traceback_header(self):
1090 # do not print a traceback header if exc_traceback is None
1091 # see issue #24695
1092 exc = traceback.TracebackException(Exception, Exception("haven"), None)
1093 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
1094
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001095
Berker Peksag716b3d32015-04-08 09:47:14 +03001096class MiscTest(unittest.TestCase):
1097
1098 def test_all(self):
1099 expected = set()
1100 blacklist = {'print_list'}
1101 for name in dir(traceback):
1102 if name.startswith('_') or name in blacklist:
1103 continue
1104 module_object = getattr(traceback, name)
1105 if getattr(module_object, '__module__', None) == 'traceback':
1106 expected.add(name)
1107 self.assertCountEqual(traceback.__all__, expected)
1108
Fred Drake2e2be372001-09-20 21:33:42 +00001109
1110if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +03001111 unittest.main()