blob: 2fa85f54a76d3e8873d7302732ce2166145a6ef5 [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
Berker Peksag716b3d32015-04-08 09:47:14 +03009from test.support import TESTFN, Error, captured_output, unlink, cpython_only
Victor Stinner9d279b82014-12-05 10:18:30 +010010from test.script_helper import assert_python_ok
11import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000012
13import traceback
14
Christian Heimes81ee3ef2008-05-04 22:42:01 +000015
Robert Collins6bc2c1e2015-03-05 12:07:57 +130016test_code = namedtuple('code', ['co_filename', 'co_name'])
Robert Collinsd7c7e0e2015-03-05 20:28:52 +130017test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
Robert Collins6bc2c1e2015-03-05 12:07:57 +130018test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next'])
19
20
Benjamin Petersone6528212008-07-15 15:32:09 +000021class SyntaxTracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000022 # For now, a very minimal set of tests. I want to be sure that
23 # formatting of SyntaxErrors works based on changes for 2.1.
24
25 def get_exception_format(self, func, exc):
26 try:
27 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000028 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000029 return traceback.format_exception_only(exc, value)
30 else:
Collin Winter3add4d72007-08-29 23:37:32 +000031 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000032
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000033 def syntax_error_with_caret(self):
34 compile("def fact(x):\n\treturn x!\n", "?", "exec")
35
Georg Brandl751899a2009-06-04 19:41:00 +000036 def syntax_error_with_caret_2(self):
37 compile("1 +\n", "?", "exec")
38
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000039 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000040 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000041
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020042 def syntax_error_with_caret_non_ascii(self):
43 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
44
Florent Xicluna758fa5e2014-01-22 01:11:43 +010045 def syntax_error_bad_indentation2(self):
46 compile(" print(2)", "?", "exec")
47
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000048 def test_caret(self):
49 err = self.get_exception_format(self.syntax_error_with_caret,
50 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000051 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000052 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000053 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000054 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Tim Peters7e01e282001-04-08 07:44:07 +000055
Georg Brandl751899a2009-06-04 19:41:00 +000056 err = self.get_exception_format(self.syntax_error_with_caret_2,
57 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000058 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010059 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
60 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Georg Brandl751899a2009-06-04 19:41:00 +000061
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020062 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
63 SyntaxError)
64 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010065 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
66 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020067
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000068 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000069 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
70 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000071 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000072 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000073
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000074 def test_bad_indentation(self):
75 err = self.get_exception_format(self.syntax_error_bad_indentation,
76 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000077 self.assertEqual(len(err), 4)
78 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +000079 self.assertIn("^", err[2])
Guido van Rossume61fd5b2007-07-11 12:20:59 +000080 self.assertEqual(err[1].find(")"), err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000081
Florent Xicluna758fa5e2014-01-22 01:11:43 +010082 err = self.get_exception_format(self.syntax_error_bad_indentation2,
83 IndentationError)
84 self.assertEqual(len(err), 4)
85 self.assertEqual(err[1].strip(), "print(2)")
86 self.assertIn("^", err[2])
87 self.assertEqual(err[1].find("p"), err[2].find("^"))
88
Thomas Wouters477c8d52006-05-27 19:21:47 +000089 def test_base_exception(self):
90 # Test that exceptions derived from BaseException are formatted right
91 e = KeyboardInterrupt()
92 lst = traceback.format_exception_only(e.__class__, e)
93 self.assertEqual(lst, ['KeyboardInterrupt\n'])
94
Thomas Wouters0e3f5912006-08-11 14:57:12 +000095 def test_format_exception_only_bad__str__(self):
96 class X(Exception):
97 def __str__(self):
98 1/0
99 err = traceback.format_exception_only(X, X())
100 self.assertEqual(len(err), 1)
101 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +0000102 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300103 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +0000104 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300105 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000106 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000107
Thomas Wouters89f507f2006-12-13 04:49:30 +0000108 def test_without_exception(self):
109 err = traceback.format_exception_only(None, None)
110 self.assertEqual(err, ['None\n'])
111
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000112 def test_encoded_file(self):
113 # Test that tracebacks are correctly printed for encoded source files:
114 # - correct line number (Issue2384)
115 # - respect file encoding (Issue3975)
116 import tempfile, sys, subprocess, os
117
118 # The spawned subprocess has its stdout redirected to a PIPE, and its
119 # encoding may be different from the current interpreter, on Windows
120 # at least.
121 process = subprocess.Popen([sys.executable, "-c",
122 "import sys; print(sys.stdout.encoding)"],
123 stdout=subprocess.PIPE,
124 stderr=subprocess.STDOUT)
125 stdout, stderr = process.communicate()
126 output_encoding = str(stdout, 'ascii').splitlines()[0]
127
128 def do_test(firstlines, message, charset, lineno):
129 # Raise the message in a subprocess, and catch the output
130 try:
131 output = open(TESTFN, "w", encoding=charset)
132 output.write("""{0}if 1:
133 import traceback;
134 raise RuntimeError('{1}')
135 """.format(firstlines, message))
136 output.close()
137 process = subprocess.Popen([sys.executable, TESTFN],
138 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
139 stdout, stderr = process.communicate()
140 stdout = stdout.decode(output_encoding).splitlines()
141 finally:
142 unlink(TESTFN)
143
144 # The source lines are encoded with the 'backslashreplace' handler
145 encoded_message = message.encode(output_encoding,
146 'backslashreplace')
147 # and we just decoded them with the output_encoding.
148 message_ascii = encoded_message.decode(output_encoding)
149
150 err_line = "raise RuntimeError('{0}')".format(message_ascii)
151 err_msg = "RuntimeError: {0}".format(message_ascii)
152
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000153 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000154 "Invalid line number: {0!r} instead of {1}".format(
155 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000156 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000157 "Invalid traceback line: {0!r} instead of {1!r}".format(
158 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000159 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000160 "Invalid error message: {0!r} instead of {1!r}".format(
161 stdout[3], err_msg))
162
163 do_test("", "foo", "ascii", 3)
164 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
165 if charset == "ascii":
166 text = "foo"
167 elif charset == "GBK":
168 text = "\u4E02\u5100"
169 else:
170 text = "h\xe9 ho"
171 do_test("# coding: {0}\n".format(charset),
172 text, charset, 4)
173 do_test("#!shebang\n# coding: {0}\n".format(charset),
174 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200175 do_test(" \t\f\n# coding: {0}\n".format(charset),
176 text, charset, 5)
177 # Issue #18960: coding spec should has no effect
178 do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000179
Victor Stinner9d279b82014-12-05 10:18:30 +0100180 def test_print_traceback_at_exit(self):
181 # Issue #22599: Ensure that it is possible to use the traceback module
182 # to display an exception at Python exit
183 code = textwrap.dedent("""
184 import sys
185 import traceback
186
187 class PrintExceptionAtExit(object):
188 def __init__(self):
189 try:
190 x = 1 / 0
191 except Exception:
192 self.exc_info = sys.exc_info()
193 # self.exc_info[1] (traceback) contains frames:
194 # explicitly clear the reference to self in the current
195 # frame to break a reference cycle
196 self = None
197
198 def __del__(self):
199 traceback.print_exception(*self.exc_info)
200
201 # Keep a reference in the module namespace to call the destructor
202 # when the module is unloaded
203 obj = PrintExceptionAtExit()
204 """)
205 rc, stdout, stderr = assert_python_ok('-c', code)
206 expected = [b'Traceback (most recent call last):',
207 b' File "<string>", line 8, in __init__',
208 b'ZeroDivisionError: division by zero']
209 self.assertEqual(stderr.splitlines(), expected)
210
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000211
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000212class TracebackFormatTests(unittest.TestCase):
213
Antoine Pitrou58720d62013-08-05 23:26:40 +0200214 def some_exception(self):
215 raise KeyError('blah')
216
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200217 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200218 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200219 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000220 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200221 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000222 except KeyError:
223 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200224 if cleanup_func is not None:
225 # Clear the inner frames, not this one
226 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000227 traceback_fmt = 'Traceback (most recent call last):\n' + \
228 ''.join(traceback.format_tb(tb))
229 file_ = StringIO()
230 traceback_print(tb, file_)
231 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400232 # Call all _tb and _exc functions
233 with captured_output("stderr") as tbstderr:
234 traceback.print_tb(tb)
235 tbfile = StringIO()
236 traceback.print_tb(tb, file=tbfile)
237 with captured_output("stderr") as excstderr:
238 traceback.print_exc()
239 excfmt = traceback.format_exc()
240 excfile = StringIO()
241 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000242 else:
243 raise Error("unable to create test traceback string")
244
245 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000246 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400247 # Now verify the _tb func output
248 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
249 # Now verify the _exc func output
250 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
251 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000252
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000253 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000254 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200255 self.assertEqual(len(tb_lines), 5)
256 banner = tb_lines[0]
257 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000258 self.assertTrue(banner.startswith('Traceback'))
259 self.assertTrue(location.startswith(' File'))
260 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000261
Antoine Pitrou58720d62013-08-05 23:26:40 +0200262 def test_traceback_format(self):
263 self.check_traceback_format()
264
265 def test_traceback_format_with_cleared_frames(self):
266 # Check that traceback formatting also works with a clear()ed frame
267 def cleanup_tb(tb):
268 tb.tb_frame.clear()
269 self.check_traceback_format(cleanup_tb)
270
Benjamin Petersond9fec152013-04-29 16:09:39 -0400271 def test_stack_format(self):
272 # Verify _stack functions. Note we have to use _getframe(1) to
273 # compare them without this frame appearing in the output
274 with captured_output("stderr") as ststderr:
275 traceback.print_stack(sys._getframe(1))
276 stfile = StringIO()
277 traceback.print_stack(sys._getframe(1), file=stfile)
278 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
279
280 stfmt = traceback.format_stack(sys._getframe(1))
281
282 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
283
Benjamin Petersone6528212008-07-15 15:32:09 +0000284
285cause_message = (
286 "\nThe above exception was the direct cause "
287 "of the following exception:\n\n")
288
289context_message = (
290 "\nDuring handling of the above exception, "
291 "another exception occurred:\n\n")
292
293boundaries = re.compile(
294 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
295
296
297class BaseExceptionReportingTests:
298
299 def get_exception(self, exception_or_callable):
300 if isinstance(exception_or_callable, Exception):
301 return exception_or_callable
302 try:
303 exception_or_callable()
304 except Exception as e:
305 return e
306
307 def zero_div(self):
308 1/0 # In zero_div
309
310 def check_zero_div(self, msg):
311 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000312 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000313 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000314 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000315
316 def test_simple(self):
317 try:
318 1/0 # Marker
319 except ZeroDivisionError as _:
320 e = _
321 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000322 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000323 self.assertTrue(lines[0].startswith('Traceback'))
324 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000325 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000326 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000327
328 def test_cause(self):
329 def inner_raise():
330 try:
331 self.zero_div()
332 except ZeroDivisionError as e:
333 raise KeyError from e
334 def outer_raise():
335 inner_raise() # Marker
336 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000337 self.assertEqual(len(blocks), 3)
338 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000339 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000340 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000341
342 def test_context(self):
343 def inner_raise():
344 try:
345 self.zero_div()
346 except ZeroDivisionError:
347 raise KeyError
348 def outer_raise():
349 inner_raise() # Marker
350 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000351 self.assertEqual(len(blocks), 3)
352 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000353 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000354 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000355
Nick Coghlanab7bf212012-02-26 17:49:52 +1000356 def test_context_suppression(self):
357 try:
358 try:
359 raise Exception
360 except:
361 raise ZeroDivisionError from None
362 except ZeroDivisionError as _:
363 e = _
364 lines = self.get_report(e).splitlines()
365 self.assertEqual(len(lines), 4)
366 self.assertTrue(lines[0].startswith('Traceback'))
367 self.assertTrue(lines[1].startswith(' File'))
368 self.assertIn('ZeroDivisionError from None', lines[2])
369 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
370
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000371 def test_cause_and_context(self):
372 # When both a cause and a context are set, only the cause should be
373 # displayed and the context should be muted.
374 def inner_raise():
375 try:
376 self.zero_div()
377 except ZeroDivisionError as _e:
378 e = _e
379 try:
380 xyzzy
381 except NameError:
382 raise KeyError from e
383 def outer_raise():
384 inner_raise() # Marker
385 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000386 self.assertEqual(len(blocks), 3)
387 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000388 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000389 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000390
Benjamin Petersone6528212008-07-15 15:32:09 +0000391 def test_cause_recursive(self):
392 def inner_raise():
393 try:
394 try:
395 self.zero_div()
396 except ZeroDivisionError as e:
397 z = e
398 raise KeyError from e
399 except KeyError as e:
400 raise z from e
401 def outer_raise():
402 inner_raise() # Marker
403 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000404 self.assertEqual(len(blocks), 3)
405 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000406 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000407 self.assertIn('raise KeyError from e', blocks[0])
408 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000409 # The second block (apart from the boundary) is the ZeroDivisionError
410 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000411 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000412 self.check_zero_div(blocks[2])
413
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000414 def test_syntax_error_offset_at_eol(self):
415 # See #10186.
416 def e():
417 raise SyntaxError('', ('', 0, 5, 'hello'))
418 msg = self.get_report(e).splitlines()
419 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000420 def e():
421 exec("x = 5 | 4 |")
422 msg = self.get_report(e).splitlines()
423 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000424
425
426class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
427 #
428 # This checks reporting through the 'traceback' module, with both
429 # format_exception() and print_exception().
430 #
431
432 def get_report(self, e):
433 e = self.get_exception(e)
434 s = ''.join(
435 traceback.format_exception(type(e), e, e.__traceback__))
436 with captured_output("stderr") as sio:
437 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000438 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000439 return s
440
441
442class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
443 #
444 # This checks built-in reporting by the interpreter.
445 #
446
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200447 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000448 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200449 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000450 e = self.get_exception(e)
451 with captured_output("stderr") as s:
452 exception_print(e)
453 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000454
455
Andrew Kuchling173a1572013-09-15 18:15:56 -0400456class MiscTracebackCases(unittest.TestCase):
457 #
458 # Check non-printing functions in traceback module
459 #
460
461 def test_clear(self):
462 def outer():
463 middle()
464 def middle():
465 inner()
466 def inner():
467 i = 1
468 1/0
469
470 try:
471 outer()
472 except:
473 type_, value, tb = sys.exc_info()
474
475 # Initial assertion: there's one local in the inner frame.
476 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
477 self.assertEqual(len(inner_frame.f_locals), 1)
478
479 # Clear traceback frames
480 traceback.clear_frames(tb)
481
482 # Local variable dict should now be empty.
483 self.assertEqual(len(inner_frame.f_locals), 0)
484
485
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300486class TestFrame(unittest.TestCase):
487
488 def test_basics(self):
489 linecache.clearcache()
490 linecache.lazycache("f", globals())
491 f = traceback.FrameSummary("f", 1, "dummy")
492 self.assertEqual(
493 ("f", 1, "dummy", '"""Test cases for traceback module"""'),
494 tuple(f))
495 self.assertEqual(None, f.locals)
496
497 def test_lazy_lines(self):
498 linecache.clearcache()
499 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
500 self.assertEqual(None, f._line)
501 linecache.lazycache("f", globals())
502 self.assertEqual(
503 '"""Test cases for traceback module"""',
504 f.line)
505
506 def test_explicit_line(self):
507 f = traceback.FrameSummary("f", 1, "dummy", line="line")
508 self.assertEqual("line", f.line)
509
510
511class TestStack(unittest.TestCase):
512
513 def test_walk_stack(self):
514 s = list(traceback.walk_stack(None))
515 self.assertGreater(len(s), 10)
516
517 def test_walk_tb(self):
518 try:
519 1/0
520 except Exception:
521 _, _, tb = sys.exc_info()
522 s = list(traceback.walk_tb(tb))
523 self.assertEqual(len(s), 1)
524
525 def test_extract_stack(self):
526 s = traceback.StackSummary.extract(traceback.walk_stack(None))
527 self.assertIsInstance(s, traceback.StackSummary)
528
529 def test_extract_stack_limit(self):
530 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
531 self.assertEqual(len(s), 5)
532
533 def test_extract_stack_lookup_lines(self):
534 linecache.clearcache()
535 linecache.updatecache('/foo.py', globals())
536 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300537 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300538 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
539 linecache.clearcache()
540 self.assertEqual(s[0].line, "import sys")
541
542 def test_extract_stackup_deferred_lookup_lines(self):
543 linecache.clearcache()
544 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300545 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300546 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
547 self.assertEqual({}, linecache.cache)
548 linecache.updatecache('/foo.py', globals())
549 self.assertEqual(s[0].line, "import sys")
550
551 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300552 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300553 self.assertEqual(
554 [' File "foo.py", line 1, in fred\n line\n'],
555 s.format())
556
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300557 def test_from_list_edited_stack(self):
558 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
559 s[0] = ('foo.py', 2, 'fred', 'line')
560 s2 = traceback.StackSummary.from_list(s)
561 self.assertEqual(
562 [' File "foo.py", line 2, in fred\n line\n'],
563 s2.format())
564
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300565 def test_format_smoke(self):
566 # For detailed tests see the format_list tests, which consume the same
567 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300568 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300569 self.assertEqual(
570 [' File "foo.py", line 1, in fred\n line\n'],
571 s.format())
572
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300573 def test_locals(self):
574 linecache.updatecache('/foo.py', globals())
575 c = test_code('/foo.py', 'method')
576 f = test_frame(c, globals(), {'something': 1})
577 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
578 self.assertEqual(s[0].locals, {'something': '1'})
579
580 def test_no_locals(self):
581 linecache.updatecache('/foo.py', globals())
582 c = test_code('/foo.py', 'method')
583 f = test_frame(c, globals(), {'something': 1})
584 s = traceback.StackSummary.extract(iter([(f, 6)]))
585 self.assertEqual(s[0].locals, None)
586
587 def test_format_locals(self):
588 def some_inner(k, v):
589 a = 1
590 b = 2
591 return traceback.StackSummary.extract(
592 traceback.walk_stack(None), capture_locals=True, limit=1)
593 s = some_inner(3, 4)
594 self.assertEqual(
Berker Peksag716b3d32015-04-08 09:47:14 +0300595 [' File "' + __file__ + '", line 592, '
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300596 'in some_inner\n'
597 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
598 ' a = 1\n'
599 ' b = 2\n'
600 ' k = 3\n'
601 ' v = 4\n'
602 ], s.format())
603
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300604
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300605class TestTracebackException(unittest.TestCase):
606
607 def test_smoke(self):
608 try:
609 1/0
610 except Exception:
611 exc_info = sys.exc_info()
612 exc = traceback.TracebackException(*exc_info)
613 expected_stack = traceback.StackSummary.extract(
614 traceback.walk_tb(exc_info[2]))
615 self.assertEqual(None, exc.__cause__)
616 self.assertEqual(None, exc.__context__)
617 self.assertEqual(False, exc.__suppress_context__)
618 self.assertEqual(expected_stack, exc.stack)
619 self.assertEqual(exc_info[0], exc.exc_type)
620 self.assertEqual(str(exc_info[1]), str(exc))
621
622 def test_from_exception(self):
623 # Check all the parameters are accepted.
624 def foo():
625 1/0
626 try:
627 foo()
628 except Exception as e:
629 exc_info = sys.exc_info()
630 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300631 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
632 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300633 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300634 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300635 expected_stack = self.expected_stack
636 exc = self.exc
637 self.assertEqual(None, exc.__cause__)
638 self.assertEqual(None, exc.__context__)
639 self.assertEqual(False, exc.__suppress_context__)
640 self.assertEqual(expected_stack, exc.stack)
641 self.assertEqual(exc_info[0], exc.exc_type)
642 self.assertEqual(str(exc_info[1]), str(exc))
643
644 def test_cause(self):
645 try:
646 try:
647 1/0
648 finally:
649 exc_info_context = sys.exc_info()
650 exc_context = traceback.TracebackException(*exc_info_context)
651 cause = Exception("cause")
652 raise Exception("uh oh") from cause
653 except Exception:
654 exc_info = sys.exc_info()
655 exc = traceback.TracebackException(*exc_info)
656 expected_stack = traceback.StackSummary.extract(
657 traceback.walk_tb(exc_info[2]))
658 exc_cause = traceback.TracebackException(Exception, cause, None)
659 self.assertEqual(exc_cause, exc.__cause__)
660 self.assertEqual(exc_context, exc.__context__)
661 self.assertEqual(True, exc.__suppress_context__)
662 self.assertEqual(expected_stack, exc.stack)
663 self.assertEqual(exc_info[0], exc.exc_type)
664 self.assertEqual(str(exc_info[1]), str(exc))
665
666 def test_context(self):
667 try:
668 try:
669 1/0
670 finally:
671 exc_info_context = sys.exc_info()
672 exc_context = traceback.TracebackException(*exc_info_context)
673 raise Exception("uh oh")
674 except Exception:
675 exc_info = sys.exc_info()
676 exc = traceback.TracebackException(*exc_info)
677 expected_stack = traceback.StackSummary.extract(
678 traceback.walk_tb(exc_info[2]))
679 self.assertEqual(None, exc.__cause__)
680 self.assertEqual(exc_context, exc.__context__)
681 self.assertEqual(False, exc.__suppress_context__)
682 self.assertEqual(expected_stack, exc.stack)
683 self.assertEqual(exc_info[0], exc.exc_type)
684 self.assertEqual(str(exc_info[1]), str(exc))
685
686 def test_limit(self):
687 def recurse(n):
688 if n:
689 recurse(n-1)
690 else:
691 1/0
692 try:
693 recurse(10)
694 except Exception:
695 exc_info = sys.exc_info()
696 exc = traceback.TracebackException(*exc_info, limit=5)
697 expected_stack = traceback.StackSummary.extract(
698 traceback.walk_tb(exc_info[2]), limit=5)
699 self.assertEqual(expected_stack, exc.stack)
700
701 def test_lookup_lines(self):
702 linecache.clearcache()
703 e = Exception("uh oh")
704 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300705 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300706 tb = test_tb(f, 6, None)
707 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
708 self.assertEqual({}, linecache.cache)
709 linecache.updatecache('/foo.py', globals())
710 self.assertEqual(exc.stack[0].line, "import sys")
711
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300712 def test_locals(self):
713 linecache.updatecache('/foo.py', globals())
714 e = Exception("uh oh")
715 c = test_code('/foo.py', 'method')
716 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
717 tb = test_tb(f, 6, None)
718 exc = traceback.TracebackException(
719 Exception, e, tb, capture_locals=True)
720 self.assertEqual(
721 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
722
723 def test_no_locals(self):
724 linecache.updatecache('/foo.py', globals())
725 e = Exception("uh oh")
726 c = test_code('/foo.py', 'method')
727 f = test_frame(c, globals(), {'something': 1})
728 tb = test_tb(f, 6, None)
729 exc = traceback.TracebackException(Exception, e, tb)
730 self.assertEqual(exc.stack[0].locals, None)
731
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300732
Berker Peksag716b3d32015-04-08 09:47:14 +0300733class MiscTest(unittest.TestCase):
734
735 def test_all(self):
736 expected = set()
737 blacklist = {'print_list'}
738 for name in dir(traceback):
739 if name.startswith('_') or name in blacklist:
740 continue
741 module_object = getattr(traceback, name)
742 if getattr(module_object, '__module__', None) == 'traceback':
743 expected.add(name)
744 self.assertCountEqual(traceback.__all__, expected)
745
Fred Drake2e2be372001-09-20 21:33:42 +0000746
747if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +0300748 unittest.main()