blob: 549d8d1e9701837d8d0b66505ba503ec284940d8 [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:
132 output = open(TESTFN, "w", encoding=charset)
133 output.write("""{0}if 1:
134 import traceback;
135 raise RuntimeError('{1}')
136 """.format(firstlines, message))
137 output.close()
138 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)
178 # Issue #18960: coding spec should has no effect
179 do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000180
Serhiy Storchakaa7930372016-07-03 22:27:26 +0300181 @support.requires_type_collecting
Victor Stinner9d279b82014-12-05 10:18:30 +0100182 def test_print_traceback_at_exit(self):
183 # Issue #22599: Ensure that it is possible to use the traceback module
184 # to display an exception at Python exit
185 code = textwrap.dedent("""
186 import sys
187 import traceback
188
189 class PrintExceptionAtExit(object):
190 def __init__(self):
191 try:
192 x = 1 / 0
193 except Exception:
194 self.exc_info = sys.exc_info()
195 # self.exc_info[1] (traceback) contains frames:
196 # explicitly clear the reference to self in the current
197 # frame to break a reference cycle
198 self = None
199
200 def __del__(self):
201 traceback.print_exception(*self.exc_info)
202
203 # Keep a reference in the module namespace to call the destructor
204 # when the module is unloaded
205 obj = PrintExceptionAtExit()
206 """)
207 rc, stdout, stderr = assert_python_ok('-c', code)
208 expected = [b'Traceback (most recent call last):',
209 b' File "<string>", line 8, in __init__',
210 b'ZeroDivisionError: division by zero']
211 self.assertEqual(stderr.splitlines(), expected)
212
Berker Peksagc3f417d2015-07-24 17:36:21 +0300213 def test_print_exception(self):
214 output = StringIO()
215 traceback.print_exception(
216 Exception, Exception("projector"), None, file=output
217 )
218 self.assertEqual(output.getvalue(), "Exception: projector\n")
219
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000220
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000221class TracebackFormatTests(unittest.TestCase):
222
Antoine Pitrou58720d62013-08-05 23:26:40 +0200223 def some_exception(self):
224 raise KeyError('blah')
225
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200226 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200227 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200228 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000229 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200230 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000231 except KeyError:
232 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200233 if cleanup_func is not None:
234 # Clear the inner frames, not this one
235 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000236 traceback_fmt = 'Traceback (most recent call last):\n' + \
237 ''.join(traceback.format_tb(tb))
238 file_ = StringIO()
239 traceback_print(tb, file_)
240 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400241 # Call all _tb and _exc functions
242 with captured_output("stderr") as tbstderr:
243 traceback.print_tb(tb)
244 tbfile = StringIO()
245 traceback.print_tb(tb, file=tbfile)
246 with captured_output("stderr") as excstderr:
247 traceback.print_exc()
248 excfmt = traceback.format_exc()
249 excfile = StringIO()
250 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000251 else:
252 raise Error("unable to create test traceback string")
253
254 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000255 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400256 # Now verify the _tb func output
257 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
258 # Now verify the _exc func output
259 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
260 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000261
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000262 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000263 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200264 self.assertEqual(len(tb_lines), 5)
265 banner = tb_lines[0]
266 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000267 self.assertTrue(banner.startswith('Traceback'))
268 self.assertTrue(location.startswith(' File'))
269 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000270
Antoine Pitrou58720d62013-08-05 23:26:40 +0200271 def test_traceback_format(self):
272 self.check_traceback_format()
273
274 def test_traceback_format_with_cleared_frames(self):
275 # Check that traceback formatting also works with a clear()ed frame
276 def cleanup_tb(tb):
277 tb.tb_frame.clear()
278 self.check_traceback_format(cleanup_tb)
279
Benjamin Petersond9fec152013-04-29 16:09:39 -0400280 def test_stack_format(self):
281 # Verify _stack functions. Note we have to use _getframe(1) to
282 # compare them without this frame appearing in the output
283 with captured_output("stderr") as ststderr:
284 traceback.print_stack(sys._getframe(1))
285 stfile = StringIO()
286 traceback.print_stack(sys._getframe(1), file=stfile)
287 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
288
289 stfmt = traceback.format_stack(sys._getframe(1))
290
291 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
292
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300293 def test_print_stack(self):
294 def prn():
295 traceback.print_stack()
296 with captured_output("stderr") as stderr:
297 prn()
298 lineno = prn.__code__.co_firstlineno
299 self.assertEqual(stderr.getvalue().splitlines()[-4:], [
300 ' File "%s", line %d, in test_print_stack' % (__file__, lineno+3),
301 ' prn()',
302 ' File "%s", line %d, in prn' % (__file__, lineno+1),
303 ' traceback.print_stack()',
304 ])
305
306 def test_format_stack(self):
307 def fmt():
308 return traceback.format_stack()
309 result = fmt()
310 lineno = fmt.__code__.co_firstlineno
311 self.assertEqual(result[-2:], [
312 ' File "%s", line %d, in test_format_stack\n'
313 ' result = fmt()\n' % (__file__, lineno+2),
314 ' File "%s", line %d, in fmt\n'
315 ' return traceback.format_stack()\n' % (__file__, lineno+1),
316 ])
317
Benjamin Petersone6528212008-07-15 15:32:09 +0000318
319cause_message = (
320 "\nThe above exception was the direct cause "
321 "of the following exception:\n\n")
322
323context_message = (
324 "\nDuring handling of the above exception, "
325 "another exception occurred:\n\n")
326
327boundaries = re.compile(
328 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
329
330
331class BaseExceptionReportingTests:
332
333 def get_exception(self, exception_or_callable):
334 if isinstance(exception_or_callable, Exception):
335 return exception_or_callable
336 try:
337 exception_or_callable()
338 except Exception as e:
339 return e
340
341 def zero_div(self):
342 1/0 # In zero_div
343
344 def check_zero_div(self, msg):
345 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000346 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000347 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000348 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000349
350 def test_simple(self):
351 try:
352 1/0 # Marker
353 except ZeroDivisionError as _:
354 e = _
355 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000356 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000357 self.assertTrue(lines[0].startswith('Traceback'))
358 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000359 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000360 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000361
362 def test_cause(self):
363 def inner_raise():
364 try:
365 self.zero_div()
366 except ZeroDivisionError as e:
367 raise KeyError from e
368 def outer_raise():
369 inner_raise() # Marker
370 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000371 self.assertEqual(len(blocks), 3)
372 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000373 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000374 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000375
376 def test_context(self):
377 def inner_raise():
378 try:
379 self.zero_div()
380 except ZeroDivisionError:
381 raise KeyError
382 def outer_raise():
383 inner_raise() # Marker
384 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000385 self.assertEqual(len(blocks), 3)
386 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000387 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000388 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000389
Nick Coghlanab7bf212012-02-26 17:49:52 +1000390 def test_context_suppression(self):
391 try:
392 try:
393 raise Exception
394 except:
395 raise ZeroDivisionError from None
396 except ZeroDivisionError as _:
397 e = _
398 lines = self.get_report(e).splitlines()
399 self.assertEqual(len(lines), 4)
400 self.assertTrue(lines[0].startswith('Traceback'))
401 self.assertTrue(lines[1].startswith(' File'))
402 self.assertIn('ZeroDivisionError from None', lines[2])
403 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
404
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000405 def test_cause_and_context(self):
406 # When both a cause and a context are set, only the cause should be
407 # displayed and the context should be muted.
408 def inner_raise():
409 try:
410 self.zero_div()
411 except ZeroDivisionError as _e:
412 e = _e
413 try:
414 xyzzy
415 except NameError:
416 raise KeyError from e
417 def outer_raise():
418 inner_raise() # Marker
419 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000420 self.assertEqual(len(blocks), 3)
421 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000422 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000423 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000424
Benjamin Petersone6528212008-07-15 15:32:09 +0000425 def test_cause_recursive(self):
426 def inner_raise():
427 try:
428 try:
429 self.zero_div()
430 except ZeroDivisionError as e:
431 z = e
432 raise KeyError from e
433 except KeyError as e:
434 raise z from e
435 def outer_raise():
436 inner_raise() # Marker
437 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000438 self.assertEqual(len(blocks), 3)
439 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000440 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000441 self.assertIn('raise KeyError from e', blocks[0])
442 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000443 # The second block (apart from the boundary) is the ZeroDivisionError
444 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000445 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000446 self.check_zero_div(blocks[2])
447
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000448 def test_syntax_error_offset_at_eol(self):
449 # See #10186.
450 def e():
451 raise SyntaxError('', ('', 0, 5, 'hello'))
452 msg = self.get_report(e).splitlines()
453 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000454 def e():
455 exec("x = 5 | 4 |")
456 msg = self.get_report(e).splitlines()
457 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000458
459
460class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
461 #
462 # This checks reporting through the 'traceback' module, with both
463 # format_exception() and print_exception().
464 #
465
466 def get_report(self, e):
467 e = self.get_exception(e)
468 s = ''.join(
469 traceback.format_exception(type(e), e, e.__traceback__))
470 with captured_output("stderr") as sio:
471 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000472 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000473 return s
474
475
476class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
477 #
478 # This checks built-in reporting by the interpreter.
479 #
480
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200481 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000482 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200483 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000484 e = self.get_exception(e)
485 with captured_output("stderr") as s:
486 exception_print(e)
487 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000488
489
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300490class LimitTests(unittest.TestCase):
491
492 ''' Tests for limit argument.
493 It's enough to test extact_tb, extract_stack and format_exception '''
494
495 def last_raises1(self):
496 raise Exception('Last raised')
497
498 def last_raises2(self):
499 self.last_raises1()
500
501 def last_raises3(self):
502 self.last_raises2()
503
504 def last_raises4(self):
505 self.last_raises3()
506
507 def last_raises5(self):
508 self.last_raises4()
509
510 def last_returns_frame1(self):
511 return sys._getframe()
512
513 def last_returns_frame2(self):
514 return self.last_returns_frame1()
515
516 def last_returns_frame3(self):
517 return self.last_returns_frame2()
518
519 def last_returns_frame4(self):
520 return self.last_returns_frame3()
521
522 def last_returns_frame5(self):
523 return self.last_returns_frame4()
524
525 def test_extract_stack(self):
526 frame = self.last_returns_frame5()
527 def extract(**kwargs):
528 return traceback.extract_stack(frame, **kwargs)
529 def assertEqualExcept(actual, expected, ignore):
530 self.assertEqual(actual[:ignore], expected[:ignore])
531 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
532 self.assertEqual(len(actual), len(expected))
533
534 with support.swap_attr(sys, 'tracebacklimit', 1000):
535 nolim = extract()
536 self.assertGreater(len(nolim), 5)
537 self.assertEqual(extract(limit=2), nolim[-2:])
538 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
539 self.assertEqual(extract(limit=-2), nolim[:2])
540 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
541 self.assertEqual(extract(limit=0), [])
542 del sys.tracebacklimit
543 assertEqualExcept(extract(), nolim, -5-1)
544 sys.tracebacklimit = 2
545 self.assertEqual(extract(), nolim[-2:])
546 self.assertEqual(extract(limit=3), nolim[-3:])
547 self.assertEqual(extract(limit=-3), nolim[:3])
548 sys.tracebacklimit = 0
549 self.assertEqual(extract(), [])
550 sys.tracebacklimit = -1
551 self.assertEqual(extract(), [])
552
553 def test_extract_tb(self):
554 try:
555 self.last_raises5()
556 except Exception:
557 exc_type, exc_value, tb = sys.exc_info()
558 def extract(**kwargs):
559 return traceback.extract_tb(tb, **kwargs)
560
561 with support.swap_attr(sys, 'tracebacklimit', 1000):
562 nolim = extract()
563 self.assertEqual(len(nolim), 5+1)
564 self.assertEqual(extract(limit=2), nolim[:2])
565 self.assertEqual(extract(limit=10), nolim)
566 self.assertEqual(extract(limit=-2), nolim[-2:])
567 self.assertEqual(extract(limit=-10), nolim)
568 self.assertEqual(extract(limit=0), [])
569 del sys.tracebacklimit
570 self.assertEqual(extract(), nolim)
571 sys.tracebacklimit = 2
572 self.assertEqual(extract(), nolim[:2])
573 self.assertEqual(extract(limit=3), nolim[:3])
574 self.assertEqual(extract(limit=-3), nolim[-3:])
575 sys.tracebacklimit = 0
576 self.assertEqual(extract(), [])
577 sys.tracebacklimit = -1
578 self.assertEqual(extract(), [])
579
580 def test_format_exception(self):
581 try:
582 self.last_raises5()
583 except Exception:
584 exc_type, exc_value, tb = sys.exc_info()
585 # [1:-1] to exclude "Traceback (...)" header and
586 # exception type and value
587 def extract(**kwargs):
588 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
589
590 with support.swap_attr(sys, 'tracebacklimit', 1000):
591 nolim = extract()
592 self.assertEqual(len(nolim), 5+1)
593 self.assertEqual(extract(limit=2), nolim[:2])
594 self.assertEqual(extract(limit=10), nolim)
595 self.assertEqual(extract(limit=-2), nolim[-2:])
596 self.assertEqual(extract(limit=-10), nolim)
597 self.assertEqual(extract(limit=0), [])
598 del sys.tracebacklimit
599 self.assertEqual(extract(), nolim)
600 sys.tracebacklimit = 2
601 self.assertEqual(extract(), nolim[:2])
602 self.assertEqual(extract(limit=3), nolim[:3])
603 self.assertEqual(extract(limit=-3), nolim[-3:])
604 sys.tracebacklimit = 0
605 self.assertEqual(extract(), [])
606 sys.tracebacklimit = -1
607 self.assertEqual(extract(), [])
608
609
Andrew Kuchling173a1572013-09-15 18:15:56 -0400610class MiscTracebackCases(unittest.TestCase):
611 #
612 # Check non-printing functions in traceback module
613 #
614
615 def test_clear(self):
616 def outer():
617 middle()
618 def middle():
619 inner()
620 def inner():
621 i = 1
622 1/0
623
624 try:
625 outer()
626 except:
627 type_, value, tb = sys.exc_info()
628
629 # Initial assertion: there's one local in the inner frame.
630 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
631 self.assertEqual(len(inner_frame.f_locals), 1)
632
633 # Clear traceback frames
634 traceback.clear_frames(tb)
635
636 # Local variable dict should now be empty.
637 self.assertEqual(len(inner_frame.f_locals), 0)
638
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300639 def test_extract_stack(self):
640 def extract():
641 return traceback.extract_stack()
642 result = extract()
643 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300644 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300645 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
646 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
647 ])
648
Andrew Kuchling173a1572013-09-15 18:15:56 -0400649
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300650class TestFrame(unittest.TestCase):
651
652 def test_basics(self):
653 linecache.clearcache()
654 linecache.lazycache("f", globals())
655 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300656 self.assertEqual(f,
657 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
658 self.assertEqual(tuple(f),
659 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
660 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
661 self.assertEqual(f, tuple(f))
662 # Since tuple.__eq__ doesn't support FrameSummary, the equality
663 # operator fallbacks to FrameSummary.__eq__.
664 self.assertEqual(tuple(f), f)
665 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300666
667 def test_lazy_lines(self):
668 linecache.clearcache()
669 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
670 self.assertEqual(None, f._line)
671 linecache.lazycache("f", globals())
672 self.assertEqual(
673 '"""Test cases for traceback module"""',
674 f.line)
675
676 def test_explicit_line(self):
677 f = traceback.FrameSummary("f", 1, "dummy", line="line")
678 self.assertEqual("line", f.line)
679
680
681class TestStack(unittest.TestCase):
682
683 def test_walk_stack(self):
684 s = list(traceback.walk_stack(None))
685 self.assertGreater(len(s), 10)
686
687 def test_walk_tb(self):
688 try:
689 1/0
690 except Exception:
691 _, _, tb = sys.exc_info()
692 s = list(traceback.walk_tb(tb))
693 self.assertEqual(len(s), 1)
694
695 def test_extract_stack(self):
696 s = traceback.StackSummary.extract(traceback.walk_stack(None))
697 self.assertIsInstance(s, traceback.StackSummary)
698
699 def test_extract_stack_limit(self):
700 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
701 self.assertEqual(len(s), 5)
702
703 def test_extract_stack_lookup_lines(self):
704 linecache.clearcache()
705 linecache.updatecache('/foo.py', globals())
706 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300707 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300708 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
709 linecache.clearcache()
710 self.assertEqual(s[0].line, "import sys")
711
712 def test_extract_stackup_deferred_lookup_lines(self):
713 linecache.clearcache()
714 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300715 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300716 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
717 self.assertEqual({}, linecache.cache)
718 linecache.updatecache('/foo.py', globals())
719 self.assertEqual(s[0].line, "import sys")
720
721 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300722 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300723 self.assertEqual(
724 [' File "foo.py", line 1, in fred\n line\n'],
725 s.format())
726
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300727 def test_from_list_edited_stack(self):
728 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
729 s[0] = ('foo.py', 2, 'fred', 'line')
730 s2 = traceback.StackSummary.from_list(s)
731 self.assertEqual(
732 [' File "foo.py", line 2, in fred\n line\n'],
733 s2.format())
734
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300735 def test_format_smoke(self):
736 # For detailed tests see the format_list tests, which consume the same
737 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300738 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300739 self.assertEqual(
740 [' File "foo.py", line 1, in fred\n line\n'],
741 s.format())
742
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300743 def test_locals(self):
744 linecache.updatecache('/foo.py', globals())
745 c = test_code('/foo.py', 'method')
746 f = test_frame(c, globals(), {'something': 1})
747 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
748 self.assertEqual(s[0].locals, {'something': '1'})
749
750 def test_no_locals(self):
751 linecache.updatecache('/foo.py', globals())
752 c = test_code('/foo.py', 'method')
753 f = test_frame(c, globals(), {'something': 1})
754 s = traceback.StackSummary.extract(iter([(f, 6)]))
755 self.assertEqual(s[0].locals, None)
756
757 def test_format_locals(self):
758 def some_inner(k, v):
759 a = 1
760 b = 2
761 return traceback.StackSummary.extract(
762 traceback.walk_stack(None), capture_locals=True, limit=1)
763 s = some_inner(3, 4)
764 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300765 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300766 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
767 ' a = 1\n'
768 ' b = 2\n'
769 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300770 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300771 ], s.format())
772
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300773class TestTracebackException(unittest.TestCase):
774
775 def test_smoke(self):
776 try:
777 1/0
778 except Exception:
779 exc_info = sys.exc_info()
780 exc = traceback.TracebackException(*exc_info)
781 expected_stack = traceback.StackSummary.extract(
782 traceback.walk_tb(exc_info[2]))
783 self.assertEqual(None, exc.__cause__)
784 self.assertEqual(None, exc.__context__)
785 self.assertEqual(False, exc.__suppress_context__)
786 self.assertEqual(expected_stack, exc.stack)
787 self.assertEqual(exc_info[0], exc.exc_type)
788 self.assertEqual(str(exc_info[1]), str(exc))
789
790 def test_from_exception(self):
791 # Check all the parameters are accepted.
792 def foo():
793 1/0
794 try:
795 foo()
796 except Exception as e:
797 exc_info = sys.exc_info()
798 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300799 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
800 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300801 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300802 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300803 expected_stack = self.expected_stack
804 exc = self.exc
805 self.assertEqual(None, exc.__cause__)
806 self.assertEqual(None, exc.__context__)
807 self.assertEqual(False, exc.__suppress_context__)
808 self.assertEqual(expected_stack, exc.stack)
809 self.assertEqual(exc_info[0], exc.exc_type)
810 self.assertEqual(str(exc_info[1]), str(exc))
811
812 def test_cause(self):
813 try:
814 try:
815 1/0
816 finally:
817 exc_info_context = sys.exc_info()
818 exc_context = traceback.TracebackException(*exc_info_context)
819 cause = Exception("cause")
820 raise Exception("uh oh") from cause
821 except Exception:
822 exc_info = sys.exc_info()
823 exc = traceback.TracebackException(*exc_info)
824 expected_stack = traceback.StackSummary.extract(
825 traceback.walk_tb(exc_info[2]))
826 exc_cause = traceback.TracebackException(Exception, cause, None)
827 self.assertEqual(exc_cause, exc.__cause__)
828 self.assertEqual(exc_context, exc.__context__)
829 self.assertEqual(True, exc.__suppress_context__)
830 self.assertEqual(expected_stack, exc.stack)
831 self.assertEqual(exc_info[0], exc.exc_type)
832 self.assertEqual(str(exc_info[1]), str(exc))
833
834 def test_context(self):
835 try:
836 try:
837 1/0
838 finally:
839 exc_info_context = sys.exc_info()
840 exc_context = traceback.TracebackException(*exc_info_context)
841 raise Exception("uh oh")
842 except Exception:
843 exc_info = sys.exc_info()
844 exc = traceback.TracebackException(*exc_info)
845 expected_stack = traceback.StackSummary.extract(
846 traceback.walk_tb(exc_info[2]))
847 self.assertEqual(None, exc.__cause__)
848 self.assertEqual(exc_context, exc.__context__)
849 self.assertEqual(False, exc.__suppress_context__)
850 self.assertEqual(expected_stack, exc.stack)
851 self.assertEqual(exc_info[0], exc.exc_type)
852 self.assertEqual(str(exc_info[1]), str(exc))
853
854 def test_limit(self):
855 def recurse(n):
856 if n:
857 recurse(n-1)
858 else:
859 1/0
860 try:
861 recurse(10)
862 except Exception:
863 exc_info = sys.exc_info()
864 exc = traceback.TracebackException(*exc_info, limit=5)
865 expected_stack = traceback.StackSummary.extract(
866 traceback.walk_tb(exc_info[2]), limit=5)
867 self.assertEqual(expected_stack, exc.stack)
868
869 def test_lookup_lines(self):
870 linecache.clearcache()
871 e = Exception("uh oh")
872 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300873 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300874 tb = test_tb(f, 6, None)
875 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
876 self.assertEqual({}, linecache.cache)
877 linecache.updatecache('/foo.py', globals())
878 self.assertEqual(exc.stack[0].line, "import sys")
879
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300880 def test_locals(self):
881 linecache.updatecache('/foo.py', globals())
882 e = Exception("uh oh")
883 c = test_code('/foo.py', 'method')
884 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
885 tb = test_tb(f, 6, None)
886 exc = traceback.TracebackException(
887 Exception, e, tb, capture_locals=True)
888 self.assertEqual(
889 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
890
891 def test_no_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})
896 tb = test_tb(f, 6, None)
897 exc = traceback.TracebackException(Exception, e, tb)
898 self.assertEqual(exc.stack[0].locals, None)
899
Berker Peksagc3f417d2015-07-24 17:36:21 +0300900 def test_traceback_header(self):
901 # do not print a traceback header if exc_traceback is None
902 # see issue #24695
903 exc = traceback.TracebackException(Exception, Exception("haven"), None)
904 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
905
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300906
Berker Peksag716b3d32015-04-08 09:47:14 +0300907class MiscTest(unittest.TestCase):
908
909 def test_all(self):
910 expected = set()
911 blacklist = {'print_list'}
912 for name in dir(traceback):
913 if name.startswith('_') or name in blacklist:
914 continue
915 module_object = getattr(traceback, name)
916 if getattr(module_object, '__module__', None) == 'traceback':
917 expected.add(name)
918 self.assertCountEqual(traceback.__all__, expected)
919
Fred Drake2e2be372001-09-20 21:33:42 +0000920
921if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +0300922 unittest.main()