blob: 5e4b6a27e5f72afb550fbd4f456425a23d4f20b6 [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
Benjamin Petersone6528212008-07-15 15:32:09 +000022class SyntaxTracebackCases(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
Thomas Wouters89f507f2006-12-13 04:49:30 +0000109 def test_without_exception(self):
110 err = traceback.format_exception_only(None, None)
111 self.assertEqual(err, ['None\n'])
112
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000113 def test_encoded_file(self):
114 # Test that tracebacks are correctly printed for encoded source files:
115 # - correct line number (Issue2384)
116 # - respect file encoding (Issue3975)
117 import tempfile, sys, subprocess, os
118
119 # The spawned subprocess has its stdout redirected to a PIPE, and its
120 # encoding may be different from the current interpreter, on Windows
121 # at least.
122 process = subprocess.Popen([sys.executable, "-c",
123 "import sys; print(sys.stdout.encoding)"],
124 stdout=subprocess.PIPE,
125 stderr=subprocess.STDOUT)
126 stdout, stderr = process.communicate()
127 output_encoding = str(stdout, 'ascii').splitlines()[0]
128
129 def do_test(firstlines, message, charset, lineno):
130 # Raise the message in a subprocess, and catch the output
131 try:
Victor Stinner51d8c522016-02-08 17:57:02 +0100132 with open(TESTFN, "w", encoding=charset) as output:
133 output.write("""{0}if 1:
134 import traceback;
135 raise RuntimeError('{1}')
136 """.format(firstlines, message))
137
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000138 process = subprocess.Popen([sys.executable, TESTFN],
139 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
140 stdout, stderr = process.communicate()
141 stdout = stdout.decode(output_encoding).splitlines()
142 finally:
143 unlink(TESTFN)
144
145 # The source lines are encoded with the 'backslashreplace' handler
146 encoded_message = message.encode(output_encoding,
147 'backslashreplace')
148 # and we just decoded them with the output_encoding.
149 message_ascii = encoded_message.decode(output_encoding)
150
151 err_line = "raise RuntimeError('{0}')".format(message_ascii)
152 err_msg = "RuntimeError: {0}".format(message_ascii)
153
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000154 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000155 "Invalid line number: {0!r} instead of {1}".format(
156 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000157 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000158 "Invalid traceback line: {0!r} instead of {1!r}".format(
159 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000160 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000161 "Invalid error message: {0!r} instead of {1!r}".format(
162 stdout[3], err_msg))
163
164 do_test("", "foo", "ascii", 3)
165 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
166 if charset == "ascii":
167 text = "foo"
168 elif charset == "GBK":
169 text = "\u4E02\u5100"
170 else:
171 text = "h\xe9 ho"
172 do_test("# coding: {0}\n".format(charset),
173 text, charset, 4)
174 do_test("#!shebang\n# coding: {0}\n".format(charset),
175 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200176 do_test(" \t\f\n# coding: {0}\n".format(charset),
177 text, charset, 5)
Martin Panter614827c2016-04-19 04:05:59 +0000178 # Issue #18960: coding spec should have no effect
Victor Stinner51d8c522016-02-08 17:57:02 +0100179 do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000180
Victor Stinner9d279b82014-12-05 10:18:30 +0100181 def test_print_traceback_at_exit(self):
182 # Issue #22599: Ensure that it is possible to use the traceback module
183 # to display an exception at Python exit
184 code = textwrap.dedent("""
185 import sys
186 import traceback
187
188 class PrintExceptionAtExit(object):
189 def __init__(self):
190 try:
191 x = 1 / 0
192 except Exception:
193 self.exc_info = sys.exc_info()
194 # self.exc_info[1] (traceback) contains frames:
195 # explicitly clear the reference to self in the current
196 # frame to break a reference cycle
197 self = None
198
199 def __del__(self):
200 traceback.print_exception(*self.exc_info)
201
202 # Keep a reference in the module namespace to call the destructor
203 # when the module is unloaded
204 obj = PrintExceptionAtExit()
205 """)
206 rc, stdout, stderr = assert_python_ok('-c', code)
207 expected = [b'Traceback (most recent call last):',
208 b' File "<string>", line 8, in __init__',
209 b'ZeroDivisionError: division by zero']
210 self.assertEqual(stderr.splitlines(), expected)
211
Berker Peksagc3f417d2015-07-24 17:36:21 +0300212 def test_print_exception(self):
213 output = StringIO()
214 traceback.print_exception(
215 Exception, Exception("projector"), None, file=output
216 )
217 self.assertEqual(output.getvalue(), "Exception: projector\n")
218
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000219
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000220class TracebackFormatTests(unittest.TestCase):
221
Antoine Pitrou58720d62013-08-05 23:26:40 +0200222 def some_exception(self):
223 raise KeyError('blah')
224
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200225 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200226 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200227 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000228 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200229 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000230 except KeyError:
231 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200232 if cleanup_func is not None:
233 # Clear the inner frames, not this one
234 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000235 traceback_fmt = 'Traceback (most recent call last):\n' + \
236 ''.join(traceback.format_tb(tb))
237 file_ = StringIO()
238 traceback_print(tb, file_)
239 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400240 # Call all _tb and _exc functions
241 with captured_output("stderr") as tbstderr:
242 traceback.print_tb(tb)
243 tbfile = StringIO()
244 traceback.print_tb(tb, file=tbfile)
245 with captured_output("stderr") as excstderr:
246 traceback.print_exc()
247 excfmt = traceback.format_exc()
248 excfile = StringIO()
249 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000250 else:
251 raise Error("unable to create test traceback string")
252
253 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000254 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400255 # Now verify the _tb func output
256 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
257 # Now verify the _exc func output
258 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
259 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000260
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000261 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000262 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200263 self.assertEqual(len(tb_lines), 5)
264 banner = tb_lines[0]
265 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000266 self.assertTrue(banner.startswith('Traceback'))
267 self.assertTrue(location.startswith(' File'))
268 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000269
Antoine Pitrou58720d62013-08-05 23:26:40 +0200270 def test_traceback_format(self):
271 self.check_traceback_format()
272
273 def test_traceback_format_with_cleared_frames(self):
274 # Check that traceback formatting also works with a clear()ed frame
275 def cleanup_tb(tb):
276 tb.tb_frame.clear()
277 self.check_traceback_format(cleanup_tb)
278
Benjamin Petersond9fec152013-04-29 16:09:39 -0400279 def test_stack_format(self):
280 # Verify _stack functions. Note we have to use _getframe(1) to
281 # compare them without this frame appearing in the output
282 with captured_output("stderr") as ststderr:
283 traceback.print_stack(sys._getframe(1))
284 stfile = StringIO()
285 traceback.print_stack(sys._getframe(1), file=stfile)
286 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
287
288 stfmt = traceback.format_stack(sys._getframe(1))
289
290 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
291
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300292 def test_print_stack(self):
293 def prn():
294 traceback.print_stack()
295 with captured_output("stderr") as stderr:
296 prn()
297 lineno = prn.__code__.co_firstlineno
298 self.assertEqual(stderr.getvalue().splitlines()[-4:], [
299 ' File "%s", line %d, in test_print_stack' % (__file__, lineno+3),
300 ' prn()',
301 ' File "%s", line %d, in prn' % (__file__, lineno+1),
302 ' traceback.print_stack()',
303 ])
304
305 def test_format_stack(self):
306 def fmt():
307 return traceback.format_stack()
308 result = fmt()
309 lineno = fmt.__code__.co_firstlineno
310 self.assertEqual(result[-2:], [
311 ' File "%s", line %d, in test_format_stack\n'
312 ' result = fmt()\n' % (__file__, lineno+2),
313 ' File "%s", line %d, in fmt\n'
314 ' return traceback.format_stack()\n' % (__file__, lineno+1),
315 ])
316
Benjamin Petersone6528212008-07-15 15:32:09 +0000317
318cause_message = (
319 "\nThe above exception was the direct cause "
320 "of the following exception:\n\n")
321
322context_message = (
323 "\nDuring handling of the above exception, "
324 "another exception occurred:\n\n")
325
326boundaries = re.compile(
327 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
328
329
330class BaseExceptionReportingTests:
331
332 def get_exception(self, exception_or_callable):
333 if isinstance(exception_or_callable, Exception):
334 return exception_or_callable
335 try:
336 exception_or_callable()
337 except Exception as e:
338 return e
339
340 def zero_div(self):
341 1/0 # In zero_div
342
343 def check_zero_div(self, msg):
344 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000345 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000346 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000347 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000348
349 def test_simple(self):
350 try:
351 1/0 # Marker
352 except ZeroDivisionError as _:
353 e = _
354 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000355 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000356 self.assertTrue(lines[0].startswith('Traceback'))
357 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000358 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000359 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000360
361 def test_cause(self):
362 def inner_raise():
363 try:
364 self.zero_div()
365 except ZeroDivisionError as e:
366 raise KeyError from e
367 def outer_raise():
368 inner_raise() # Marker
369 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000370 self.assertEqual(len(blocks), 3)
371 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000372 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000373 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000374
375 def test_context(self):
376 def inner_raise():
377 try:
378 self.zero_div()
379 except ZeroDivisionError:
380 raise KeyError
381 def outer_raise():
382 inner_raise() # Marker
383 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000384 self.assertEqual(len(blocks), 3)
385 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000386 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000387 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000388
Nick Coghlanab7bf212012-02-26 17:49:52 +1000389 def test_context_suppression(self):
390 try:
391 try:
392 raise Exception
393 except:
394 raise ZeroDivisionError from None
395 except ZeroDivisionError as _:
396 e = _
397 lines = self.get_report(e).splitlines()
398 self.assertEqual(len(lines), 4)
399 self.assertTrue(lines[0].startswith('Traceback'))
400 self.assertTrue(lines[1].startswith(' File'))
401 self.assertIn('ZeroDivisionError from None', lines[2])
402 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
403
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000404 def test_cause_and_context(self):
405 # When both a cause and a context are set, only the cause should be
406 # displayed and the context should be muted.
407 def inner_raise():
408 try:
409 self.zero_div()
410 except ZeroDivisionError as _e:
411 e = _e
412 try:
413 xyzzy
414 except NameError:
415 raise KeyError from e
416 def outer_raise():
417 inner_raise() # Marker
418 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000419 self.assertEqual(len(blocks), 3)
420 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000421 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000422 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000423
Benjamin Petersone6528212008-07-15 15:32:09 +0000424 def test_cause_recursive(self):
425 def inner_raise():
426 try:
427 try:
428 self.zero_div()
429 except ZeroDivisionError as e:
430 z = e
431 raise KeyError from e
432 except KeyError as e:
433 raise z from e
434 def outer_raise():
435 inner_raise() # Marker
436 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000437 self.assertEqual(len(blocks), 3)
438 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000439 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000440 self.assertIn('raise KeyError from e', blocks[0])
441 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000442 # The second block (apart from the boundary) is the ZeroDivisionError
443 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000444 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000445 self.check_zero_div(blocks[2])
446
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000447 def test_syntax_error_offset_at_eol(self):
448 # See #10186.
449 def e():
450 raise SyntaxError('', ('', 0, 5, 'hello'))
451 msg = self.get_report(e).splitlines()
452 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000453 def e():
454 exec("x = 5 | 4 |")
455 msg = self.get_report(e).splitlines()
456 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000457
458
459class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
460 #
461 # This checks reporting through the 'traceback' module, with both
462 # format_exception() and print_exception().
463 #
464
465 def get_report(self, e):
466 e = self.get_exception(e)
467 s = ''.join(
468 traceback.format_exception(type(e), e, e.__traceback__))
469 with captured_output("stderr") as sio:
470 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000471 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000472 return s
473
474
475class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
476 #
477 # This checks built-in reporting by the interpreter.
478 #
479
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200480 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000481 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200482 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000483 e = self.get_exception(e)
484 with captured_output("stderr") as s:
485 exception_print(e)
486 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000487
488
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300489class LimitTests(unittest.TestCase):
490
491 ''' Tests for limit argument.
492 It's enough to test extact_tb, extract_stack and format_exception '''
493
494 def last_raises1(self):
495 raise Exception('Last raised')
496
497 def last_raises2(self):
498 self.last_raises1()
499
500 def last_raises3(self):
501 self.last_raises2()
502
503 def last_raises4(self):
504 self.last_raises3()
505
506 def last_raises5(self):
507 self.last_raises4()
508
509 def last_returns_frame1(self):
510 return sys._getframe()
511
512 def last_returns_frame2(self):
513 return self.last_returns_frame1()
514
515 def last_returns_frame3(self):
516 return self.last_returns_frame2()
517
518 def last_returns_frame4(self):
519 return self.last_returns_frame3()
520
521 def last_returns_frame5(self):
522 return self.last_returns_frame4()
523
524 def test_extract_stack(self):
525 frame = self.last_returns_frame5()
526 def extract(**kwargs):
527 return traceback.extract_stack(frame, **kwargs)
528 def assertEqualExcept(actual, expected, ignore):
529 self.assertEqual(actual[:ignore], expected[:ignore])
530 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
531 self.assertEqual(len(actual), len(expected))
532
533 with support.swap_attr(sys, 'tracebacklimit', 1000):
534 nolim = extract()
535 self.assertGreater(len(nolim), 5)
536 self.assertEqual(extract(limit=2), nolim[-2:])
537 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
538 self.assertEqual(extract(limit=-2), nolim[:2])
539 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
540 self.assertEqual(extract(limit=0), [])
541 del sys.tracebacklimit
542 assertEqualExcept(extract(), nolim, -5-1)
543 sys.tracebacklimit = 2
544 self.assertEqual(extract(), nolim[-2:])
545 self.assertEqual(extract(limit=3), nolim[-3:])
546 self.assertEqual(extract(limit=-3), nolim[:3])
547 sys.tracebacklimit = 0
548 self.assertEqual(extract(), [])
549 sys.tracebacklimit = -1
550 self.assertEqual(extract(), [])
551
552 def test_extract_tb(self):
553 try:
554 self.last_raises5()
555 except Exception:
556 exc_type, exc_value, tb = sys.exc_info()
557 def extract(**kwargs):
558 return traceback.extract_tb(tb, **kwargs)
559
560 with support.swap_attr(sys, 'tracebacklimit', 1000):
561 nolim = extract()
562 self.assertEqual(len(nolim), 5+1)
563 self.assertEqual(extract(limit=2), nolim[:2])
564 self.assertEqual(extract(limit=10), nolim)
565 self.assertEqual(extract(limit=-2), nolim[-2:])
566 self.assertEqual(extract(limit=-10), nolim)
567 self.assertEqual(extract(limit=0), [])
568 del sys.tracebacklimit
569 self.assertEqual(extract(), nolim)
570 sys.tracebacklimit = 2
571 self.assertEqual(extract(), nolim[:2])
572 self.assertEqual(extract(limit=3), nolim[:3])
573 self.assertEqual(extract(limit=-3), nolim[-3:])
574 sys.tracebacklimit = 0
575 self.assertEqual(extract(), [])
576 sys.tracebacklimit = -1
577 self.assertEqual(extract(), [])
578
579 def test_format_exception(self):
580 try:
581 self.last_raises5()
582 except Exception:
583 exc_type, exc_value, tb = sys.exc_info()
584 # [1:-1] to exclude "Traceback (...)" header and
585 # exception type and value
586 def extract(**kwargs):
587 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
588
589 with support.swap_attr(sys, 'tracebacklimit', 1000):
590 nolim = extract()
591 self.assertEqual(len(nolim), 5+1)
592 self.assertEqual(extract(limit=2), nolim[:2])
593 self.assertEqual(extract(limit=10), nolim)
594 self.assertEqual(extract(limit=-2), nolim[-2:])
595 self.assertEqual(extract(limit=-10), nolim)
596 self.assertEqual(extract(limit=0), [])
597 del sys.tracebacklimit
598 self.assertEqual(extract(), nolim)
599 sys.tracebacklimit = 2
600 self.assertEqual(extract(), nolim[:2])
601 self.assertEqual(extract(limit=3), nolim[:3])
602 self.assertEqual(extract(limit=-3), nolim[-3:])
603 sys.tracebacklimit = 0
604 self.assertEqual(extract(), [])
605 sys.tracebacklimit = -1
606 self.assertEqual(extract(), [])
607
608
Andrew Kuchling173a1572013-09-15 18:15:56 -0400609class MiscTracebackCases(unittest.TestCase):
610 #
611 # Check non-printing functions in traceback module
612 #
613
614 def test_clear(self):
615 def outer():
616 middle()
617 def middle():
618 inner()
619 def inner():
620 i = 1
621 1/0
622
623 try:
624 outer()
625 except:
626 type_, value, tb = sys.exc_info()
627
628 # Initial assertion: there's one local in the inner frame.
629 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
630 self.assertEqual(len(inner_frame.f_locals), 1)
631
632 # Clear traceback frames
633 traceback.clear_frames(tb)
634
635 # Local variable dict should now be empty.
636 self.assertEqual(len(inner_frame.f_locals), 0)
637
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300638 def test_extract_stack(self):
639 def extract():
640 return traceback.extract_stack()
641 result = extract()
642 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300643 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300644 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
645 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
646 ])
647
Andrew Kuchling173a1572013-09-15 18:15:56 -0400648
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300649class TestFrame(unittest.TestCase):
650
651 def test_basics(self):
652 linecache.clearcache()
653 linecache.lazycache("f", globals())
654 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300655 self.assertEqual(f,
656 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
657 self.assertEqual(tuple(f),
658 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
659 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
660 self.assertEqual(f, tuple(f))
661 # Since tuple.__eq__ doesn't support FrameSummary, the equality
662 # operator fallbacks to FrameSummary.__eq__.
663 self.assertEqual(tuple(f), f)
664 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300665
666 def test_lazy_lines(self):
667 linecache.clearcache()
668 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
669 self.assertEqual(None, f._line)
670 linecache.lazycache("f", globals())
671 self.assertEqual(
672 '"""Test cases for traceback module"""',
673 f.line)
674
675 def test_explicit_line(self):
676 f = traceback.FrameSummary("f", 1, "dummy", line="line")
677 self.assertEqual("line", f.line)
678
679
680class TestStack(unittest.TestCase):
681
682 def test_walk_stack(self):
683 s = list(traceback.walk_stack(None))
684 self.assertGreater(len(s), 10)
685
686 def test_walk_tb(self):
687 try:
688 1/0
689 except Exception:
690 _, _, tb = sys.exc_info()
691 s = list(traceback.walk_tb(tb))
692 self.assertEqual(len(s), 1)
693
694 def test_extract_stack(self):
695 s = traceback.StackSummary.extract(traceback.walk_stack(None))
696 self.assertIsInstance(s, traceback.StackSummary)
697
698 def test_extract_stack_limit(self):
699 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
700 self.assertEqual(len(s), 5)
701
702 def test_extract_stack_lookup_lines(self):
703 linecache.clearcache()
704 linecache.updatecache('/foo.py', globals())
705 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300706 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300707 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
708 linecache.clearcache()
709 self.assertEqual(s[0].line, "import sys")
710
711 def test_extract_stackup_deferred_lookup_lines(self):
712 linecache.clearcache()
713 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300714 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300715 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
716 self.assertEqual({}, linecache.cache)
717 linecache.updatecache('/foo.py', globals())
718 self.assertEqual(s[0].line, "import sys")
719
720 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300721 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300722 self.assertEqual(
723 [' File "foo.py", line 1, in fred\n line\n'],
724 s.format())
725
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300726 def test_from_list_edited_stack(self):
727 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
728 s[0] = ('foo.py', 2, 'fred', 'line')
729 s2 = traceback.StackSummary.from_list(s)
730 self.assertEqual(
731 [' File "foo.py", line 2, in fred\n line\n'],
732 s2.format())
733
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300734 def test_format_smoke(self):
735 # For detailed tests see the format_list tests, which consume the same
736 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300737 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300738 self.assertEqual(
739 [' File "foo.py", line 1, in fred\n line\n'],
740 s.format())
741
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300742 def test_locals(self):
743 linecache.updatecache('/foo.py', globals())
744 c = test_code('/foo.py', 'method')
745 f = test_frame(c, globals(), {'something': 1})
746 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
747 self.assertEqual(s[0].locals, {'something': '1'})
748
749 def test_no_locals(self):
750 linecache.updatecache('/foo.py', globals())
751 c = test_code('/foo.py', 'method')
752 f = test_frame(c, globals(), {'something': 1})
753 s = traceback.StackSummary.extract(iter([(f, 6)]))
754 self.assertEqual(s[0].locals, None)
755
756 def test_format_locals(self):
757 def some_inner(k, v):
758 a = 1
759 b = 2
760 return traceback.StackSummary.extract(
761 traceback.walk_stack(None), capture_locals=True, limit=1)
762 s = some_inner(3, 4)
763 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300764 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300765 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
766 ' a = 1\n'
767 ' b = 2\n'
768 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300769 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300770 ], s.format())
771
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300772class TestTracebackException(unittest.TestCase):
773
774 def test_smoke(self):
775 try:
776 1/0
777 except Exception:
778 exc_info = sys.exc_info()
779 exc = traceback.TracebackException(*exc_info)
780 expected_stack = traceback.StackSummary.extract(
781 traceback.walk_tb(exc_info[2]))
782 self.assertEqual(None, exc.__cause__)
783 self.assertEqual(None, exc.__context__)
784 self.assertEqual(False, exc.__suppress_context__)
785 self.assertEqual(expected_stack, exc.stack)
786 self.assertEqual(exc_info[0], exc.exc_type)
787 self.assertEqual(str(exc_info[1]), str(exc))
788
789 def test_from_exception(self):
790 # Check all the parameters are accepted.
791 def foo():
792 1/0
793 try:
794 foo()
795 except Exception as e:
796 exc_info = sys.exc_info()
797 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300798 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
799 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300800 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300801 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300802 expected_stack = self.expected_stack
803 exc = self.exc
804 self.assertEqual(None, exc.__cause__)
805 self.assertEqual(None, exc.__context__)
806 self.assertEqual(False, exc.__suppress_context__)
807 self.assertEqual(expected_stack, exc.stack)
808 self.assertEqual(exc_info[0], exc.exc_type)
809 self.assertEqual(str(exc_info[1]), str(exc))
810
811 def test_cause(self):
812 try:
813 try:
814 1/0
815 finally:
816 exc_info_context = sys.exc_info()
817 exc_context = traceback.TracebackException(*exc_info_context)
818 cause = Exception("cause")
819 raise Exception("uh oh") from cause
820 except Exception:
821 exc_info = sys.exc_info()
822 exc = traceback.TracebackException(*exc_info)
823 expected_stack = traceback.StackSummary.extract(
824 traceback.walk_tb(exc_info[2]))
825 exc_cause = traceback.TracebackException(Exception, cause, None)
826 self.assertEqual(exc_cause, exc.__cause__)
827 self.assertEqual(exc_context, exc.__context__)
828 self.assertEqual(True, exc.__suppress_context__)
829 self.assertEqual(expected_stack, exc.stack)
830 self.assertEqual(exc_info[0], exc.exc_type)
831 self.assertEqual(str(exc_info[1]), str(exc))
832
833 def test_context(self):
834 try:
835 try:
836 1/0
837 finally:
838 exc_info_context = sys.exc_info()
839 exc_context = traceback.TracebackException(*exc_info_context)
840 raise Exception("uh oh")
841 except Exception:
842 exc_info = sys.exc_info()
843 exc = traceback.TracebackException(*exc_info)
844 expected_stack = traceback.StackSummary.extract(
845 traceback.walk_tb(exc_info[2]))
846 self.assertEqual(None, exc.__cause__)
847 self.assertEqual(exc_context, exc.__context__)
848 self.assertEqual(False, exc.__suppress_context__)
849 self.assertEqual(expected_stack, exc.stack)
850 self.assertEqual(exc_info[0], exc.exc_type)
851 self.assertEqual(str(exc_info[1]), str(exc))
852
853 def test_limit(self):
854 def recurse(n):
855 if n:
856 recurse(n-1)
857 else:
858 1/0
859 try:
860 recurse(10)
861 except Exception:
862 exc_info = sys.exc_info()
863 exc = traceback.TracebackException(*exc_info, limit=5)
864 expected_stack = traceback.StackSummary.extract(
865 traceback.walk_tb(exc_info[2]), limit=5)
866 self.assertEqual(expected_stack, exc.stack)
867
868 def test_lookup_lines(self):
869 linecache.clearcache()
870 e = Exception("uh oh")
871 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300872 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300873 tb = test_tb(f, 6, None)
874 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
875 self.assertEqual({}, linecache.cache)
876 linecache.updatecache('/foo.py', globals())
877 self.assertEqual(exc.stack[0].line, "import sys")
878
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300879 def test_locals(self):
880 linecache.updatecache('/foo.py', globals())
881 e = Exception("uh oh")
882 c = test_code('/foo.py', 'method')
883 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
884 tb = test_tb(f, 6, None)
885 exc = traceback.TracebackException(
886 Exception, e, tb, capture_locals=True)
887 self.assertEqual(
888 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
889
890 def test_no_locals(self):
891 linecache.updatecache('/foo.py', globals())
892 e = Exception("uh oh")
893 c = test_code('/foo.py', 'method')
894 f = test_frame(c, globals(), {'something': 1})
895 tb = test_tb(f, 6, None)
896 exc = traceback.TracebackException(Exception, e, tb)
897 self.assertEqual(exc.stack[0].locals, None)
898
Berker Peksagc3f417d2015-07-24 17:36:21 +0300899 def test_traceback_header(self):
900 # do not print a traceback header if exc_traceback is None
901 # see issue #24695
902 exc = traceback.TracebackException(Exception, Exception("haven"), None)
903 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
904
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300905
Berker Peksag716b3d32015-04-08 09:47:14 +0300906class MiscTest(unittest.TestCase):
907
908 def test_all(self):
909 expected = set()
910 blacklist = {'print_list'}
911 for name in dir(traceback):
912 if name.startswith('_') or name in blacklist:
913 continue
914 module_object = getattr(traceback, name)
915 if getattr(module_object, '__module__', None) == 'traceback':
916 expected.add(name)
917 self.assertCountEqual(traceback.__all__, expected)
918
Fred Drake2e2be372001-09-20 21:33:42 +0000919
920if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +0300921 unittest.main()