blob: 49cedda5508f027bef309cd78737e5eb3f667c79 [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:
128 output = open(TESTFN, "w", encoding=charset)
129 output.write("""{0}if 1:
130 import traceback;
131 raise RuntimeError('{1}')
132 """.format(firstlines, message))
133 output.close()
134 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)
174 # Issue #18960: coding spec should has no effect
175 do_test("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
302 def test_format_stack(self):
303 def fmt():
304 return traceback.format_stack()
305 result = fmt()
306 lineno = fmt.__code__.co_firstlineno
307 self.assertEqual(result[-2:], [
308 ' File "%s", line %d, in test_format_stack\n'
309 ' result = fmt()\n' % (__file__, lineno+2),
310 ' File "%s", line %d, in fmt\n'
311 ' return traceback.format_stack()\n' % (__file__, lineno+1),
312 ])
313
Benjamin Petersone6528212008-07-15 15:32:09 +0000314
315cause_message = (
316 "\nThe above exception was the direct cause "
317 "of the following exception:\n\n")
318
319context_message = (
320 "\nDuring handling of the above exception, "
321 "another exception occurred:\n\n")
322
323boundaries = re.compile(
324 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
325
326
327class BaseExceptionReportingTests:
328
329 def get_exception(self, exception_or_callable):
330 if isinstance(exception_or_callable, Exception):
331 return exception_or_callable
332 try:
333 exception_or_callable()
334 except Exception as e:
335 return e
336
337 def zero_div(self):
338 1/0 # In zero_div
339
340 def check_zero_div(self, msg):
341 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000342 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000343 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000344 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000345
346 def test_simple(self):
347 try:
348 1/0 # Marker
349 except ZeroDivisionError as _:
350 e = _
351 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000352 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000353 self.assertTrue(lines[0].startswith('Traceback'))
354 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000355 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000356 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000357
358 def test_cause(self):
359 def inner_raise():
360 try:
361 self.zero_div()
362 except ZeroDivisionError as e:
363 raise KeyError from e
364 def outer_raise():
365 inner_raise() # Marker
366 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000367 self.assertEqual(len(blocks), 3)
368 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000369 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000370 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000371
372 def test_context(self):
373 def inner_raise():
374 try:
375 self.zero_div()
376 except ZeroDivisionError:
377 raise KeyError
378 def outer_raise():
379 inner_raise() # Marker
380 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000381 self.assertEqual(len(blocks), 3)
382 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000383 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000384 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000385
Nick Coghlanab7bf212012-02-26 17:49:52 +1000386 def test_context_suppression(self):
387 try:
388 try:
389 raise Exception
390 except:
391 raise ZeroDivisionError from None
392 except ZeroDivisionError as _:
393 e = _
394 lines = self.get_report(e).splitlines()
395 self.assertEqual(len(lines), 4)
396 self.assertTrue(lines[0].startswith('Traceback'))
397 self.assertTrue(lines[1].startswith(' File'))
398 self.assertIn('ZeroDivisionError from None', lines[2])
399 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
400
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000401 def test_cause_and_context(self):
402 # When both a cause and a context are set, only the cause should be
403 # displayed and the context should be muted.
404 def inner_raise():
405 try:
406 self.zero_div()
407 except ZeroDivisionError as _e:
408 e = _e
409 try:
410 xyzzy
411 except NameError:
412 raise KeyError from e
413 def outer_raise():
414 inner_raise() # Marker
415 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000416 self.assertEqual(len(blocks), 3)
417 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000418 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000419 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000420
Benjamin Petersone6528212008-07-15 15:32:09 +0000421 def test_cause_recursive(self):
422 def inner_raise():
423 try:
424 try:
425 self.zero_div()
426 except ZeroDivisionError as e:
427 z = e
428 raise KeyError from e
429 except KeyError as e:
430 raise z from e
431 def outer_raise():
432 inner_raise() # Marker
433 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000434 self.assertEqual(len(blocks), 3)
435 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000436 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000437 self.assertIn('raise KeyError from e', blocks[0])
438 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000439 # The second block (apart from the boundary) is the ZeroDivisionError
440 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000441 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000442 self.check_zero_div(blocks[2])
443
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000444 def test_syntax_error_offset_at_eol(self):
445 # See #10186.
446 def e():
447 raise SyntaxError('', ('', 0, 5, 'hello'))
448 msg = self.get_report(e).splitlines()
449 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000450 def e():
451 exec("x = 5 | 4 |")
452 msg = self.get_report(e).splitlines()
453 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000454
Martin Panterbb8b1cb2016-09-22 09:37:39 +0000455 def test_message_none(self):
456 # A message that looks like "None" should not be treated specially
457 err = self.get_report(Exception(None))
458 self.assertIn('Exception: None\n', err)
459 err = self.get_report(Exception('None'))
460 self.assertIn('Exception: None\n', err)
461 err = self.get_report(Exception())
462 self.assertIn('Exception\n', err)
463 err = self.get_report(Exception(''))
464 self.assertIn('Exception\n', err)
465
Benjamin Petersone6528212008-07-15 15:32:09 +0000466
467class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
468 #
469 # This checks reporting through the 'traceback' module, with both
470 # format_exception() and print_exception().
471 #
472
473 def get_report(self, e):
474 e = self.get_exception(e)
475 s = ''.join(
476 traceback.format_exception(type(e), e, e.__traceback__))
477 with captured_output("stderr") as sio:
478 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000479 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000480 return s
481
482
483class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
484 #
485 # This checks built-in reporting by the interpreter.
486 #
487
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200488 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000489 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200490 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000491 e = self.get_exception(e)
492 with captured_output("stderr") as s:
493 exception_print(e)
494 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000495
496
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300497class LimitTests(unittest.TestCase):
498
499 ''' Tests for limit argument.
500 It's enough to test extact_tb, extract_stack and format_exception '''
501
502 def last_raises1(self):
503 raise Exception('Last raised')
504
505 def last_raises2(self):
506 self.last_raises1()
507
508 def last_raises3(self):
509 self.last_raises2()
510
511 def last_raises4(self):
512 self.last_raises3()
513
514 def last_raises5(self):
515 self.last_raises4()
516
517 def last_returns_frame1(self):
518 return sys._getframe()
519
520 def last_returns_frame2(self):
521 return self.last_returns_frame1()
522
523 def last_returns_frame3(self):
524 return self.last_returns_frame2()
525
526 def last_returns_frame4(self):
527 return self.last_returns_frame3()
528
529 def last_returns_frame5(self):
530 return self.last_returns_frame4()
531
532 def test_extract_stack(self):
533 frame = self.last_returns_frame5()
534 def extract(**kwargs):
535 return traceback.extract_stack(frame, **kwargs)
536 def assertEqualExcept(actual, expected, ignore):
537 self.assertEqual(actual[:ignore], expected[:ignore])
538 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
539 self.assertEqual(len(actual), len(expected))
540
541 with support.swap_attr(sys, 'tracebacklimit', 1000):
542 nolim = extract()
543 self.assertGreater(len(nolim), 5)
544 self.assertEqual(extract(limit=2), nolim[-2:])
545 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
546 self.assertEqual(extract(limit=-2), nolim[:2])
547 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
548 self.assertEqual(extract(limit=0), [])
549 del sys.tracebacklimit
550 assertEqualExcept(extract(), nolim, -5-1)
551 sys.tracebacklimit = 2
552 self.assertEqual(extract(), nolim[-2:])
553 self.assertEqual(extract(limit=3), nolim[-3:])
554 self.assertEqual(extract(limit=-3), nolim[:3])
555 sys.tracebacklimit = 0
556 self.assertEqual(extract(), [])
557 sys.tracebacklimit = -1
558 self.assertEqual(extract(), [])
559
560 def test_extract_tb(self):
561 try:
562 self.last_raises5()
563 except Exception:
564 exc_type, exc_value, tb = sys.exc_info()
565 def extract(**kwargs):
566 return traceback.extract_tb(tb, **kwargs)
567
568 with support.swap_attr(sys, 'tracebacklimit', 1000):
569 nolim = extract()
570 self.assertEqual(len(nolim), 5+1)
571 self.assertEqual(extract(limit=2), nolim[:2])
572 self.assertEqual(extract(limit=10), nolim)
573 self.assertEqual(extract(limit=-2), nolim[-2:])
574 self.assertEqual(extract(limit=-10), nolim)
575 self.assertEqual(extract(limit=0), [])
576 del sys.tracebacklimit
577 self.assertEqual(extract(), nolim)
578 sys.tracebacklimit = 2
579 self.assertEqual(extract(), nolim[:2])
580 self.assertEqual(extract(limit=3), nolim[:3])
581 self.assertEqual(extract(limit=-3), nolim[-3:])
582 sys.tracebacklimit = 0
583 self.assertEqual(extract(), [])
584 sys.tracebacklimit = -1
585 self.assertEqual(extract(), [])
586
587 def test_format_exception(self):
588 try:
589 self.last_raises5()
590 except Exception:
591 exc_type, exc_value, tb = sys.exc_info()
592 # [1:-1] to exclude "Traceback (...)" header and
593 # exception type and value
594 def extract(**kwargs):
595 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
596
597 with support.swap_attr(sys, 'tracebacklimit', 1000):
598 nolim = extract()
599 self.assertEqual(len(nolim), 5+1)
600 self.assertEqual(extract(limit=2), nolim[:2])
601 self.assertEqual(extract(limit=10), nolim)
602 self.assertEqual(extract(limit=-2), nolim[-2:])
603 self.assertEqual(extract(limit=-10), nolim)
604 self.assertEqual(extract(limit=0), [])
605 del sys.tracebacklimit
606 self.assertEqual(extract(), nolim)
607 sys.tracebacklimit = 2
608 self.assertEqual(extract(), nolim[:2])
609 self.assertEqual(extract(limit=3), nolim[:3])
610 self.assertEqual(extract(limit=-3), nolim[-3:])
611 sys.tracebacklimit = 0
612 self.assertEqual(extract(), [])
613 sys.tracebacklimit = -1
614 self.assertEqual(extract(), [])
615
616
Andrew Kuchling173a1572013-09-15 18:15:56 -0400617class MiscTracebackCases(unittest.TestCase):
618 #
619 # Check non-printing functions in traceback module
620 #
621
622 def test_clear(self):
623 def outer():
624 middle()
625 def middle():
626 inner()
627 def inner():
628 i = 1
629 1/0
630
631 try:
632 outer()
633 except:
634 type_, value, tb = sys.exc_info()
635
636 # Initial assertion: there's one local in the inner frame.
637 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
638 self.assertEqual(len(inner_frame.f_locals), 1)
639
640 # Clear traceback frames
641 traceback.clear_frames(tb)
642
643 # Local variable dict should now be empty.
644 self.assertEqual(len(inner_frame.f_locals), 0)
645
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300646 def test_extract_stack(self):
647 def extract():
648 return traceback.extract_stack()
649 result = extract()
650 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300651 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300652 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
653 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
654 ])
655
Andrew Kuchling173a1572013-09-15 18:15:56 -0400656
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300657class TestFrame(unittest.TestCase):
658
659 def test_basics(self):
660 linecache.clearcache()
661 linecache.lazycache("f", globals())
662 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300663 self.assertEqual(f,
664 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
665 self.assertEqual(tuple(f),
666 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
667 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
668 self.assertEqual(f, tuple(f))
669 # Since tuple.__eq__ doesn't support FrameSummary, the equality
670 # operator fallbacks to FrameSummary.__eq__.
671 self.assertEqual(tuple(f), f)
672 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300673
674 def test_lazy_lines(self):
675 linecache.clearcache()
676 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
677 self.assertEqual(None, f._line)
678 linecache.lazycache("f", globals())
679 self.assertEqual(
680 '"""Test cases for traceback module"""',
681 f.line)
682
683 def test_explicit_line(self):
684 f = traceback.FrameSummary("f", 1, "dummy", line="line")
685 self.assertEqual("line", f.line)
686
687
688class TestStack(unittest.TestCase):
689
690 def test_walk_stack(self):
Serhiy Storchaka1c1130f2016-10-07 23:45:42 +0300691 def deeper():
692 return list(traceback.walk_stack(None))
693 s1 = list(traceback.walk_stack(None))
694 s2 = deeper()
695 self.assertEqual(len(s2) - len(s1), 1)
696 self.assertEqual(s2[1:], s1)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300697
698 def test_walk_tb(self):
699 try:
700 1/0
701 except Exception:
702 _, _, tb = sys.exc_info()
703 s = list(traceback.walk_tb(tb))
704 self.assertEqual(len(s), 1)
705
706 def test_extract_stack(self):
707 s = traceback.StackSummary.extract(traceback.walk_stack(None))
708 self.assertIsInstance(s, traceback.StackSummary)
709
710 def test_extract_stack_limit(self):
711 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
712 self.assertEqual(len(s), 5)
713
714 def test_extract_stack_lookup_lines(self):
715 linecache.clearcache()
716 linecache.updatecache('/foo.py', globals())
717 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300718 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300719 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
720 linecache.clearcache()
721 self.assertEqual(s[0].line, "import sys")
722
723 def test_extract_stackup_deferred_lookup_lines(self):
724 linecache.clearcache()
725 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300726 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300727 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
728 self.assertEqual({}, linecache.cache)
729 linecache.updatecache('/foo.py', globals())
730 self.assertEqual(s[0].line, "import sys")
731
732 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300733 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300734 self.assertEqual(
735 [' File "foo.py", line 1, in fred\n line\n'],
736 s.format())
737
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300738 def test_from_list_edited_stack(self):
739 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
740 s[0] = ('foo.py', 2, 'fred', 'line')
741 s2 = traceback.StackSummary.from_list(s)
742 self.assertEqual(
743 [' File "foo.py", line 2, in fred\n line\n'],
744 s2.format())
745
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300746 def test_format_smoke(self):
747 # For detailed tests see the format_list tests, which consume the same
748 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300749 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300750 self.assertEqual(
751 [' File "foo.py", line 1, in fred\n line\n'],
752 s.format())
753
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300754 def test_locals(self):
755 linecache.updatecache('/foo.py', globals())
756 c = test_code('/foo.py', 'method')
757 f = test_frame(c, globals(), {'something': 1})
758 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
759 self.assertEqual(s[0].locals, {'something': '1'})
760
761 def test_no_locals(self):
762 linecache.updatecache('/foo.py', globals())
763 c = test_code('/foo.py', 'method')
764 f = test_frame(c, globals(), {'something': 1})
765 s = traceback.StackSummary.extract(iter([(f, 6)]))
766 self.assertEqual(s[0].locals, None)
767
768 def test_format_locals(self):
769 def some_inner(k, v):
770 a = 1
771 b = 2
772 return traceback.StackSummary.extract(
773 traceback.walk_stack(None), capture_locals=True, limit=1)
774 s = some_inner(3, 4)
775 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300776 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300777 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
778 ' a = 1\n'
779 ' b = 2\n'
780 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300781 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300782 ], s.format())
783
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300784class TestTracebackException(unittest.TestCase):
785
786 def test_smoke(self):
787 try:
788 1/0
789 except Exception:
790 exc_info = sys.exc_info()
791 exc = traceback.TracebackException(*exc_info)
792 expected_stack = traceback.StackSummary.extract(
793 traceback.walk_tb(exc_info[2]))
794 self.assertEqual(None, exc.__cause__)
795 self.assertEqual(None, exc.__context__)
796 self.assertEqual(False, exc.__suppress_context__)
797 self.assertEqual(expected_stack, exc.stack)
798 self.assertEqual(exc_info[0], exc.exc_type)
799 self.assertEqual(str(exc_info[1]), str(exc))
800
801 def test_from_exception(self):
802 # Check all the parameters are accepted.
803 def foo():
804 1/0
805 try:
806 foo()
807 except Exception as e:
808 exc_info = sys.exc_info()
809 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300810 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
811 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300812 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300813 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300814 expected_stack = self.expected_stack
815 exc = self.exc
816 self.assertEqual(None, exc.__cause__)
817 self.assertEqual(None, exc.__context__)
818 self.assertEqual(False, exc.__suppress_context__)
819 self.assertEqual(expected_stack, exc.stack)
820 self.assertEqual(exc_info[0], exc.exc_type)
821 self.assertEqual(str(exc_info[1]), str(exc))
822
823 def test_cause(self):
824 try:
825 try:
826 1/0
827 finally:
828 exc_info_context = sys.exc_info()
829 exc_context = traceback.TracebackException(*exc_info_context)
830 cause = Exception("cause")
831 raise Exception("uh oh") from cause
832 except Exception:
833 exc_info = sys.exc_info()
834 exc = traceback.TracebackException(*exc_info)
835 expected_stack = traceback.StackSummary.extract(
836 traceback.walk_tb(exc_info[2]))
837 exc_cause = traceback.TracebackException(Exception, cause, None)
838 self.assertEqual(exc_cause, exc.__cause__)
839 self.assertEqual(exc_context, exc.__context__)
840 self.assertEqual(True, exc.__suppress_context__)
841 self.assertEqual(expected_stack, exc.stack)
842 self.assertEqual(exc_info[0], exc.exc_type)
843 self.assertEqual(str(exc_info[1]), str(exc))
844
845 def test_context(self):
846 try:
847 try:
848 1/0
849 finally:
850 exc_info_context = sys.exc_info()
851 exc_context = traceback.TracebackException(*exc_info_context)
852 raise Exception("uh oh")
853 except Exception:
854 exc_info = sys.exc_info()
855 exc = traceback.TracebackException(*exc_info)
856 expected_stack = traceback.StackSummary.extract(
857 traceback.walk_tb(exc_info[2]))
858 self.assertEqual(None, exc.__cause__)
859 self.assertEqual(exc_context, exc.__context__)
860 self.assertEqual(False, exc.__suppress_context__)
861 self.assertEqual(expected_stack, exc.stack)
862 self.assertEqual(exc_info[0], exc.exc_type)
863 self.assertEqual(str(exc_info[1]), str(exc))
864
865 def test_limit(self):
866 def recurse(n):
867 if n:
868 recurse(n-1)
869 else:
870 1/0
871 try:
872 recurse(10)
873 except Exception:
874 exc_info = sys.exc_info()
875 exc = traceback.TracebackException(*exc_info, limit=5)
876 expected_stack = traceback.StackSummary.extract(
877 traceback.walk_tb(exc_info[2]), limit=5)
878 self.assertEqual(expected_stack, exc.stack)
879
880 def test_lookup_lines(self):
881 linecache.clearcache()
882 e = Exception("uh oh")
883 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300884 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300885 tb = test_tb(f, 6, None)
886 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
887 self.assertEqual({}, linecache.cache)
888 linecache.updatecache('/foo.py', globals())
889 self.assertEqual(exc.stack[0].line, "import sys")
890
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300891 def test_locals(self):
892 linecache.updatecache('/foo.py', globals())
893 e = Exception("uh oh")
894 c = test_code('/foo.py', 'method')
895 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
896 tb = test_tb(f, 6, None)
897 exc = traceback.TracebackException(
898 Exception, e, tb, capture_locals=True)
899 self.assertEqual(
900 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
901
902 def test_no_locals(self):
903 linecache.updatecache('/foo.py', globals())
904 e = Exception("uh oh")
905 c = test_code('/foo.py', 'method')
906 f = test_frame(c, globals(), {'something': 1})
907 tb = test_tb(f, 6, None)
908 exc = traceback.TracebackException(Exception, e, tb)
909 self.assertEqual(exc.stack[0].locals, None)
910
Berker Peksagc3f417d2015-07-24 17:36:21 +0300911 def test_traceback_header(self):
912 # do not print a traceback header if exc_traceback is None
913 # see issue #24695
914 exc = traceback.TracebackException(Exception, Exception("haven"), None)
915 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
916
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300917
Berker Peksag716b3d32015-04-08 09:47:14 +0300918class MiscTest(unittest.TestCase):
919
920 def test_all(self):
921 expected = set()
922 blacklist = {'print_list'}
923 for name in dir(traceback):
924 if name.startswith('_') or name in blacklist:
925 continue
926 module_object = getattr(traceback, name)
927 if getattr(module_object, '__module__', None) == 'traceback':
928 expected.add(name)
929 self.assertCountEqual(traceback.__all__, expected)
930
Fred Drake2e2be372001-09-20 21:33:42 +0000931
932if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +0300933 unittest.main()