blob: f2dc650ec8d80c34eaac445b230712cd0d14d328 [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])
347 self.assertEqual(actual[-1], expected[-1])
348
349 # Check the recursion count is roughly as expected
350 rec_limit = sys.getrecursionlimit()
Serhiy Storchakab7281052016-09-12 00:52:40 +0300351 self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
Nick Coghland0034232016-08-15 13:11:34 +1000352
353 # Check a known (limited) number of recursive invocations
354 def g(count=10):
355 if count:
356 return g(count-1)
357 raise ValueError
358
359 with captured_output("stderr") as stderr_g:
360 try:
361 g()
362 except ValueError as exc:
363 render_exc()
364 else:
365 self.fail("no value error was raised")
366
367 lineno_g = g.__code__.co_firstlineno
368 result_g = (
Eric V. Smith451d0e32016-09-09 21:56:20 -0400369 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000370 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400371 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000372 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400373 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000374 ' return g(count-1)\n'
375 ' [Previous line repeated 6 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400376 f' File "{__file__}", line {lineno_g+3}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000377 ' raise ValueError\n'
378 'ValueError\n'
379 )
380 tb_line = (
381 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400382 f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000383 ' g()\n'
384 )
385 expected = (tb_line + result_g).splitlines()
386 actual = stderr_g.getvalue().splitlines()
387 self.assertEqual(actual, expected)
388
389 # Check 2 different repetitive sections
390 def h(count=10):
391 if count:
392 return h(count-1)
393 g()
394
395 with captured_output("stderr") as stderr_h:
396 try:
397 h()
398 except ValueError as exc:
399 render_exc()
400 else:
401 self.fail("no value error was raised")
402
403 lineno_h = h.__code__.co_firstlineno
404 result_h = (
405 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400406 f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000407 ' h()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400408 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000409 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400410 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000411 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400412 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000413 ' return h(count-1)\n'
414 ' [Previous line repeated 6 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400415 f' File "{__file__}", line {lineno_h+3}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000416 ' g()\n'
417 )
418 expected = (result_h + result_g).splitlines()
419 actual = stderr_h.getvalue().splitlines()
420 self.assertEqual(actual, expected)
421
422 def test_recursive_traceback_python(self):
423 self._check_recursive_traceback_display(traceback.print_exc)
424
425 @cpython_only
426 def test_recursive_traceback_cpython_internal(self):
427 from _testcapi import exception_print
428 def render_exc():
429 exc_type, exc_value, exc_tb = sys.exc_info()
430 exception_print(exc_value)
431 self._check_recursive_traceback_display(render_exc)
432
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300433 def test_format_stack(self):
434 def fmt():
435 return traceback.format_stack()
436 result = fmt()
437 lineno = fmt.__code__.co_firstlineno
438 self.assertEqual(result[-2:], [
439 ' File "%s", line %d, in test_format_stack\n'
440 ' result = fmt()\n' % (__file__, lineno+2),
441 ' File "%s", line %d, in fmt\n'
442 ' return traceback.format_stack()\n' % (__file__, lineno+1),
443 ])
444
Benjamin Petersone6528212008-07-15 15:32:09 +0000445
446cause_message = (
447 "\nThe above exception was the direct cause "
448 "of the following exception:\n\n")
449
450context_message = (
451 "\nDuring handling of the above exception, "
452 "another exception occurred:\n\n")
453
454boundaries = re.compile(
455 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
456
457
458class BaseExceptionReportingTests:
459
460 def get_exception(self, exception_or_callable):
461 if isinstance(exception_or_callable, Exception):
462 return exception_or_callable
463 try:
464 exception_or_callable()
465 except Exception as e:
466 return e
467
468 def zero_div(self):
469 1/0 # In zero_div
470
471 def check_zero_div(self, msg):
472 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000473 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000474 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000475 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000476
477 def test_simple(self):
478 try:
479 1/0 # Marker
480 except ZeroDivisionError as _:
481 e = _
482 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000483 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000484 self.assertTrue(lines[0].startswith('Traceback'))
485 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000486 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000487 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000488
489 def test_cause(self):
490 def inner_raise():
491 try:
492 self.zero_div()
493 except ZeroDivisionError as e:
494 raise KeyError from e
495 def outer_raise():
496 inner_raise() # Marker
497 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000498 self.assertEqual(len(blocks), 3)
499 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000500 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000501 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000502
503 def test_context(self):
504 def inner_raise():
505 try:
506 self.zero_div()
507 except ZeroDivisionError:
508 raise KeyError
509 def outer_raise():
510 inner_raise() # Marker
511 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000512 self.assertEqual(len(blocks), 3)
513 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000514 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000515 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000516
Nick Coghlanab7bf212012-02-26 17:49:52 +1000517 def test_context_suppression(self):
518 try:
519 try:
520 raise Exception
521 except:
522 raise ZeroDivisionError from None
523 except ZeroDivisionError as _:
524 e = _
525 lines = self.get_report(e).splitlines()
526 self.assertEqual(len(lines), 4)
527 self.assertTrue(lines[0].startswith('Traceback'))
528 self.assertTrue(lines[1].startswith(' File'))
529 self.assertIn('ZeroDivisionError from None', lines[2])
530 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
531
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000532 def test_cause_and_context(self):
533 # When both a cause and a context are set, only the cause should be
534 # displayed and the context should be muted.
535 def inner_raise():
536 try:
537 self.zero_div()
538 except ZeroDivisionError as _e:
539 e = _e
540 try:
541 xyzzy
542 except NameError:
543 raise KeyError from e
544 def outer_raise():
545 inner_raise() # Marker
546 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000547 self.assertEqual(len(blocks), 3)
548 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000549 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000550 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000551
Benjamin Petersone6528212008-07-15 15:32:09 +0000552 def test_cause_recursive(self):
553 def inner_raise():
554 try:
555 try:
556 self.zero_div()
557 except ZeroDivisionError as e:
558 z = e
559 raise KeyError from e
560 except KeyError as e:
561 raise z from e
562 def outer_raise():
563 inner_raise() # Marker
564 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000565 self.assertEqual(len(blocks), 3)
566 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000567 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000568 self.assertIn('raise KeyError from e', blocks[0])
569 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000570 # The second block (apart from the boundary) is the ZeroDivisionError
571 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000572 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000573 self.check_zero_div(blocks[2])
574
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000575 def test_syntax_error_offset_at_eol(self):
576 # See #10186.
577 def e():
578 raise SyntaxError('', ('', 0, 5, 'hello'))
579 msg = self.get_report(e).splitlines()
580 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000581 def e():
582 exec("x = 5 | 4 |")
583 msg = self.get_report(e).splitlines()
584 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000585
Martin Panterbb8b1cb2016-09-22 09:37:39 +0000586 def test_message_none(self):
587 # A message that looks like "None" should not be treated specially
588 err = self.get_report(Exception(None))
589 self.assertIn('Exception: None\n', err)
590 err = self.get_report(Exception('None'))
591 self.assertIn('Exception: None\n', err)
592 err = self.get_report(Exception())
593 self.assertIn('Exception\n', err)
594 err = self.get_report(Exception(''))
595 self.assertIn('Exception\n', err)
596
Benjamin Petersone6528212008-07-15 15:32:09 +0000597
598class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
599 #
600 # This checks reporting through the 'traceback' module, with both
601 # format_exception() and print_exception().
602 #
603
604 def get_report(self, e):
605 e = self.get_exception(e)
606 s = ''.join(
607 traceback.format_exception(type(e), e, e.__traceback__))
608 with captured_output("stderr") as sio:
609 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000610 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000611 return s
612
613
614class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
615 #
616 # This checks built-in reporting by the interpreter.
617 #
618
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200619 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000620 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200621 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000622 e = self.get_exception(e)
623 with captured_output("stderr") as s:
624 exception_print(e)
625 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000626
627
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300628class LimitTests(unittest.TestCase):
629
630 ''' Tests for limit argument.
631 It's enough to test extact_tb, extract_stack and format_exception '''
632
633 def last_raises1(self):
634 raise Exception('Last raised')
635
636 def last_raises2(self):
637 self.last_raises1()
638
639 def last_raises3(self):
640 self.last_raises2()
641
642 def last_raises4(self):
643 self.last_raises3()
644
645 def last_raises5(self):
646 self.last_raises4()
647
648 def last_returns_frame1(self):
649 return sys._getframe()
650
651 def last_returns_frame2(self):
652 return self.last_returns_frame1()
653
654 def last_returns_frame3(self):
655 return self.last_returns_frame2()
656
657 def last_returns_frame4(self):
658 return self.last_returns_frame3()
659
660 def last_returns_frame5(self):
661 return self.last_returns_frame4()
662
663 def test_extract_stack(self):
664 frame = self.last_returns_frame5()
665 def extract(**kwargs):
666 return traceback.extract_stack(frame, **kwargs)
667 def assertEqualExcept(actual, expected, ignore):
668 self.assertEqual(actual[:ignore], expected[:ignore])
669 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
670 self.assertEqual(len(actual), len(expected))
671
672 with support.swap_attr(sys, 'tracebacklimit', 1000):
673 nolim = extract()
674 self.assertGreater(len(nolim), 5)
675 self.assertEqual(extract(limit=2), nolim[-2:])
676 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
677 self.assertEqual(extract(limit=-2), nolim[:2])
678 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
679 self.assertEqual(extract(limit=0), [])
680 del sys.tracebacklimit
681 assertEqualExcept(extract(), nolim, -5-1)
682 sys.tracebacklimit = 2
683 self.assertEqual(extract(), nolim[-2:])
684 self.assertEqual(extract(limit=3), nolim[-3:])
685 self.assertEqual(extract(limit=-3), nolim[:3])
686 sys.tracebacklimit = 0
687 self.assertEqual(extract(), [])
688 sys.tracebacklimit = -1
689 self.assertEqual(extract(), [])
690
691 def test_extract_tb(self):
692 try:
693 self.last_raises5()
694 except Exception:
695 exc_type, exc_value, tb = sys.exc_info()
696 def extract(**kwargs):
697 return traceback.extract_tb(tb, **kwargs)
698
699 with support.swap_attr(sys, 'tracebacklimit', 1000):
700 nolim = extract()
701 self.assertEqual(len(nolim), 5+1)
702 self.assertEqual(extract(limit=2), nolim[:2])
703 self.assertEqual(extract(limit=10), nolim)
704 self.assertEqual(extract(limit=-2), nolim[-2:])
705 self.assertEqual(extract(limit=-10), nolim)
706 self.assertEqual(extract(limit=0), [])
707 del sys.tracebacklimit
708 self.assertEqual(extract(), nolim)
709 sys.tracebacklimit = 2
710 self.assertEqual(extract(), nolim[:2])
711 self.assertEqual(extract(limit=3), nolim[:3])
712 self.assertEqual(extract(limit=-3), nolim[-3:])
713 sys.tracebacklimit = 0
714 self.assertEqual(extract(), [])
715 sys.tracebacklimit = -1
716 self.assertEqual(extract(), [])
717
718 def test_format_exception(self):
719 try:
720 self.last_raises5()
721 except Exception:
722 exc_type, exc_value, tb = sys.exc_info()
723 # [1:-1] to exclude "Traceback (...)" header and
724 # exception type and value
725 def extract(**kwargs):
726 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
727
728 with support.swap_attr(sys, 'tracebacklimit', 1000):
729 nolim = extract()
730 self.assertEqual(len(nolim), 5+1)
731 self.assertEqual(extract(limit=2), nolim[:2])
732 self.assertEqual(extract(limit=10), nolim)
733 self.assertEqual(extract(limit=-2), nolim[-2:])
734 self.assertEqual(extract(limit=-10), nolim)
735 self.assertEqual(extract(limit=0), [])
736 del sys.tracebacklimit
737 self.assertEqual(extract(), nolim)
738 sys.tracebacklimit = 2
739 self.assertEqual(extract(), nolim[:2])
740 self.assertEqual(extract(limit=3), nolim[:3])
741 self.assertEqual(extract(limit=-3), nolim[-3:])
742 sys.tracebacklimit = 0
743 self.assertEqual(extract(), [])
744 sys.tracebacklimit = -1
745 self.assertEqual(extract(), [])
746
747
Andrew Kuchling173a1572013-09-15 18:15:56 -0400748class MiscTracebackCases(unittest.TestCase):
749 #
750 # Check non-printing functions in traceback module
751 #
752
753 def test_clear(self):
754 def outer():
755 middle()
756 def middle():
757 inner()
758 def inner():
759 i = 1
760 1/0
761
762 try:
763 outer()
764 except:
765 type_, value, tb = sys.exc_info()
766
767 # Initial assertion: there's one local in the inner frame.
768 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
769 self.assertEqual(len(inner_frame.f_locals), 1)
770
771 # Clear traceback frames
772 traceback.clear_frames(tb)
773
774 # Local variable dict should now be empty.
775 self.assertEqual(len(inner_frame.f_locals), 0)
776
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300777 def test_extract_stack(self):
778 def extract():
779 return traceback.extract_stack()
780 result = extract()
781 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300782 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300783 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
784 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
785 ])
786
Andrew Kuchling173a1572013-09-15 18:15:56 -0400787
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300788class TestFrame(unittest.TestCase):
789
790 def test_basics(self):
791 linecache.clearcache()
792 linecache.lazycache("f", globals())
793 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300794 self.assertEqual(f,
795 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
796 self.assertEqual(tuple(f),
797 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
798 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
799 self.assertEqual(f, tuple(f))
800 # Since tuple.__eq__ doesn't support FrameSummary, the equality
801 # operator fallbacks to FrameSummary.__eq__.
802 self.assertEqual(tuple(f), f)
803 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300804
805 def test_lazy_lines(self):
806 linecache.clearcache()
807 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
808 self.assertEqual(None, f._line)
809 linecache.lazycache("f", globals())
810 self.assertEqual(
811 '"""Test cases for traceback module"""',
812 f.line)
813
814 def test_explicit_line(self):
815 f = traceback.FrameSummary("f", 1, "dummy", line="line")
816 self.assertEqual("line", f.line)
817
818
819class TestStack(unittest.TestCase):
820
821 def test_walk_stack(self):
822 s = list(traceback.walk_stack(None))
823 self.assertGreater(len(s), 10)
824
825 def test_walk_tb(self):
826 try:
827 1/0
828 except Exception:
829 _, _, tb = sys.exc_info()
830 s = list(traceback.walk_tb(tb))
831 self.assertEqual(len(s), 1)
832
833 def test_extract_stack(self):
834 s = traceback.StackSummary.extract(traceback.walk_stack(None))
835 self.assertIsInstance(s, traceback.StackSummary)
836
837 def test_extract_stack_limit(self):
838 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
839 self.assertEqual(len(s), 5)
840
841 def test_extract_stack_lookup_lines(self):
842 linecache.clearcache()
843 linecache.updatecache('/foo.py', globals())
844 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300845 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300846 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
847 linecache.clearcache()
848 self.assertEqual(s[0].line, "import sys")
849
850 def test_extract_stackup_deferred_lookup_lines(self):
851 linecache.clearcache()
852 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300853 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300854 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
855 self.assertEqual({}, linecache.cache)
856 linecache.updatecache('/foo.py', globals())
857 self.assertEqual(s[0].line, "import sys")
858
859 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300860 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300861 self.assertEqual(
862 [' File "foo.py", line 1, in fred\n line\n'],
863 s.format())
864
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300865 def test_from_list_edited_stack(self):
866 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
867 s[0] = ('foo.py', 2, 'fred', 'line')
868 s2 = traceback.StackSummary.from_list(s)
869 self.assertEqual(
870 [' File "foo.py", line 2, in fred\n line\n'],
871 s2.format())
872
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300873 def test_format_smoke(self):
874 # For detailed tests see the format_list tests, which consume the same
875 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300876 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300877 self.assertEqual(
878 [' File "foo.py", line 1, in fred\n line\n'],
879 s.format())
880
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300881 def test_locals(self):
882 linecache.updatecache('/foo.py', globals())
883 c = test_code('/foo.py', 'method')
884 f = test_frame(c, globals(), {'something': 1})
885 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
886 self.assertEqual(s[0].locals, {'something': '1'})
887
888 def test_no_locals(self):
889 linecache.updatecache('/foo.py', globals())
890 c = test_code('/foo.py', 'method')
891 f = test_frame(c, globals(), {'something': 1})
892 s = traceback.StackSummary.extract(iter([(f, 6)]))
893 self.assertEqual(s[0].locals, None)
894
895 def test_format_locals(self):
896 def some_inner(k, v):
897 a = 1
898 b = 2
899 return traceback.StackSummary.extract(
900 traceback.walk_stack(None), capture_locals=True, limit=1)
901 s = some_inner(3, 4)
902 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300903 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300904 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
905 ' a = 1\n'
906 ' b = 2\n'
907 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300908 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300909 ], s.format())
910
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300911class TestTracebackException(unittest.TestCase):
912
913 def test_smoke(self):
914 try:
915 1/0
916 except Exception:
917 exc_info = sys.exc_info()
918 exc = traceback.TracebackException(*exc_info)
919 expected_stack = traceback.StackSummary.extract(
920 traceback.walk_tb(exc_info[2]))
921 self.assertEqual(None, exc.__cause__)
922 self.assertEqual(None, exc.__context__)
923 self.assertEqual(False, exc.__suppress_context__)
924 self.assertEqual(expected_stack, exc.stack)
925 self.assertEqual(exc_info[0], exc.exc_type)
926 self.assertEqual(str(exc_info[1]), str(exc))
927
928 def test_from_exception(self):
929 # Check all the parameters are accepted.
930 def foo():
931 1/0
932 try:
933 foo()
934 except Exception as e:
935 exc_info = sys.exc_info()
936 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300937 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
938 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300939 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300940 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300941 expected_stack = self.expected_stack
942 exc = self.exc
943 self.assertEqual(None, exc.__cause__)
944 self.assertEqual(None, exc.__context__)
945 self.assertEqual(False, exc.__suppress_context__)
946 self.assertEqual(expected_stack, exc.stack)
947 self.assertEqual(exc_info[0], exc.exc_type)
948 self.assertEqual(str(exc_info[1]), str(exc))
949
950 def test_cause(self):
951 try:
952 try:
953 1/0
954 finally:
955 exc_info_context = sys.exc_info()
956 exc_context = traceback.TracebackException(*exc_info_context)
957 cause = Exception("cause")
958 raise Exception("uh oh") from cause
959 except Exception:
960 exc_info = sys.exc_info()
961 exc = traceback.TracebackException(*exc_info)
962 expected_stack = traceback.StackSummary.extract(
963 traceback.walk_tb(exc_info[2]))
964 exc_cause = traceback.TracebackException(Exception, cause, None)
965 self.assertEqual(exc_cause, exc.__cause__)
966 self.assertEqual(exc_context, exc.__context__)
967 self.assertEqual(True, exc.__suppress_context__)
968 self.assertEqual(expected_stack, exc.stack)
969 self.assertEqual(exc_info[0], exc.exc_type)
970 self.assertEqual(str(exc_info[1]), str(exc))
971
972 def test_context(self):
973 try:
974 try:
975 1/0
976 finally:
977 exc_info_context = sys.exc_info()
978 exc_context = traceback.TracebackException(*exc_info_context)
979 raise Exception("uh oh")
980 except Exception:
981 exc_info = sys.exc_info()
982 exc = traceback.TracebackException(*exc_info)
983 expected_stack = traceback.StackSummary.extract(
984 traceback.walk_tb(exc_info[2]))
985 self.assertEqual(None, exc.__cause__)
986 self.assertEqual(exc_context, exc.__context__)
987 self.assertEqual(False, exc.__suppress_context__)
988 self.assertEqual(expected_stack, exc.stack)
989 self.assertEqual(exc_info[0], exc.exc_type)
990 self.assertEqual(str(exc_info[1]), str(exc))
991
992 def test_limit(self):
993 def recurse(n):
994 if n:
995 recurse(n-1)
996 else:
997 1/0
998 try:
999 recurse(10)
1000 except Exception:
1001 exc_info = sys.exc_info()
1002 exc = traceback.TracebackException(*exc_info, limit=5)
1003 expected_stack = traceback.StackSummary.extract(
1004 traceback.walk_tb(exc_info[2]), limit=5)
1005 self.assertEqual(expected_stack, exc.stack)
1006
1007 def test_lookup_lines(self):
1008 linecache.clearcache()
1009 e = Exception("uh oh")
1010 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001011 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001012 tb = test_tb(f, 6, None)
1013 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
1014 self.assertEqual({}, linecache.cache)
1015 linecache.updatecache('/foo.py', globals())
1016 self.assertEqual(exc.stack[0].line, "import sys")
1017
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001018 def test_locals(self):
1019 linecache.updatecache('/foo.py', globals())
1020 e = Exception("uh oh")
1021 c = test_code('/foo.py', 'method')
1022 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
1023 tb = test_tb(f, 6, None)
1024 exc = traceback.TracebackException(
1025 Exception, e, tb, capture_locals=True)
1026 self.assertEqual(
1027 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
1028
1029 def test_no_locals(self):
1030 linecache.updatecache('/foo.py', globals())
1031 e = Exception("uh oh")
1032 c = test_code('/foo.py', 'method')
1033 f = test_frame(c, globals(), {'something': 1})
1034 tb = test_tb(f, 6, None)
1035 exc = traceback.TracebackException(Exception, e, tb)
1036 self.assertEqual(exc.stack[0].locals, None)
1037
Berker Peksagc3f417d2015-07-24 17:36:21 +03001038 def test_traceback_header(self):
1039 # do not print a traceback header if exc_traceback is None
1040 # see issue #24695
1041 exc = traceback.TracebackException(Exception, Exception("haven"), None)
1042 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
1043
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001044
Berker Peksag716b3d32015-04-08 09:47:14 +03001045class MiscTest(unittest.TestCase):
1046
1047 def test_all(self):
1048 expected = set()
1049 blacklist = {'print_list'}
1050 for name in dir(traceback):
1051 if name.startswith('_') or name in blacklist:
1052 continue
1053 module_object = getattr(traceback, name)
1054 if getattr(module_object, '__module__', None) == 'traceback':
1055 expected.add(name)
1056 self.assertCountEqual(traceback.__all__, expected)
1057
Fred Drake2e2be372001-09-20 21:33:42 +00001058
1059if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +03001060 unittest.main()