blob: 9c8929fc3245f611a1f8ca7efeee5901e023c4f7 [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
Benjamin Peterson26d64ae2010-09-20 21:47:37 +00009from test.support import run_unittest, Error, captured_output
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +020010from test.support import TESTFN, unlink, cpython_only
Victor Stinner9d279b82014-12-05 10:18:30 +010011from test.script_helper import assert_python_ok
12import 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
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
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000212
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000213class TracebackFormatTests(unittest.TestCase):
214
Antoine Pitrou58720d62013-08-05 23:26:40 +0200215 def some_exception(self):
216 raise KeyError('blah')
217
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200218 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200219 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200220 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000221 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200222 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000223 except KeyError:
224 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200225 if cleanup_func is not None:
226 # Clear the inner frames, not this one
227 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000228 traceback_fmt = 'Traceback (most recent call last):\n' + \
229 ''.join(traceback.format_tb(tb))
230 file_ = StringIO()
231 traceback_print(tb, file_)
232 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400233 # Call all _tb and _exc functions
234 with captured_output("stderr") as tbstderr:
235 traceback.print_tb(tb)
236 tbfile = StringIO()
237 traceback.print_tb(tb, file=tbfile)
238 with captured_output("stderr") as excstderr:
239 traceback.print_exc()
240 excfmt = traceback.format_exc()
241 excfile = StringIO()
242 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000243 else:
244 raise Error("unable to create test traceback string")
245
246 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000247 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400248 # Now verify the _tb func output
249 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
250 # Now verify the _exc func output
251 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
252 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000253
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000254 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000255 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200256 self.assertEqual(len(tb_lines), 5)
257 banner = tb_lines[0]
258 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000259 self.assertTrue(banner.startswith('Traceback'))
260 self.assertTrue(location.startswith(' File'))
261 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000262
Antoine Pitrou58720d62013-08-05 23:26:40 +0200263 def test_traceback_format(self):
264 self.check_traceback_format()
265
266 def test_traceback_format_with_cleared_frames(self):
267 # Check that traceback formatting also works with a clear()ed frame
268 def cleanup_tb(tb):
269 tb.tb_frame.clear()
270 self.check_traceback_format(cleanup_tb)
271
Benjamin Petersond9fec152013-04-29 16:09:39 -0400272 def test_stack_format(self):
273 # Verify _stack functions. Note we have to use _getframe(1) to
274 # compare them without this frame appearing in the output
275 with captured_output("stderr") as ststderr:
276 traceback.print_stack(sys._getframe(1))
277 stfile = StringIO()
278 traceback.print_stack(sys._getframe(1), file=stfile)
279 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
280
281 stfmt = traceback.format_stack(sys._getframe(1))
282
283 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
284
Benjamin Petersone6528212008-07-15 15:32:09 +0000285
286cause_message = (
287 "\nThe above exception was the direct cause "
288 "of the following exception:\n\n")
289
290context_message = (
291 "\nDuring handling of the above exception, "
292 "another exception occurred:\n\n")
293
294boundaries = re.compile(
295 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
296
297
298class BaseExceptionReportingTests:
299
300 def get_exception(self, exception_or_callable):
301 if isinstance(exception_or_callable, Exception):
302 return exception_or_callable
303 try:
304 exception_or_callable()
305 except Exception as e:
306 return e
307
308 def zero_div(self):
309 1/0 # In zero_div
310
311 def check_zero_div(self, msg):
312 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000313 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000314 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000315 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000316
317 def test_simple(self):
318 try:
319 1/0 # Marker
320 except ZeroDivisionError as _:
321 e = _
322 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000323 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000324 self.assertTrue(lines[0].startswith('Traceback'))
325 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000326 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000327 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000328
329 def test_cause(self):
330 def inner_raise():
331 try:
332 self.zero_div()
333 except ZeroDivisionError as e:
334 raise KeyError from e
335 def outer_raise():
336 inner_raise() # Marker
337 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000338 self.assertEqual(len(blocks), 3)
339 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000340 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000341 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000342
343 def test_context(self):
344 def inner_raise():
345 try:
346 self.zero_div()
347 except ZeroDivisionError:
348 raise KeyError
349 def outer_raise():
350 inner_raise() # Marker
351 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000352 self.assertEqual(len(blocks), 3)
353 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000354 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000355 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000356
Nick Coghlanab7bf212012-02-26 17:49:52 +1000357 def test_context_suppression(self):
358 try:
359 try:
360 raise Exception
361 except:
362 raise ZeroDivisionError from None
363 except ZeroDivisionError as _:
364 e = _
365 lines = self.get_report(e).splitlines()
366 self.assertEqual(len(lines), 4)
367 self.assertTrue(lines[0].startswith('Traceback'))
368 self.assertTrue(lines[1].startswith(' File'))
369 self.assertIn('ZeroDivisionError from None', lines[2])
370 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
371
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000372 def test_cause_and_context(self):
373 # When both a cause and a context are set, only the cause should be
374 # displayed and the context should be muted.
375 def inner_raise():
376 try:
377 self.zero_div()
378 except ZeroDivisionError as _e:
379 e = _e
380 try:
381 xyzzy
382 except NameError:
383 raise KeyError from e
384 def outer_raise():
385 inner_raise() # Marker
386 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000387 self.assertEqual(len(blocks), 3)
388 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000389 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000390 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000391
Benjamin Petersone6528212008-07-15 15:32:09 +0000392 def test_cause_recursive(self):
393 def inner_raise():
394 try:
395 try:
396 self.zero_div()
397 except ZeroDivisionError as e:
398 z = e
399 raise KeyError from e
400 except KeyError as e:
401 raise z from e
402 def outer_raise():
403 inner_raise() # Marker
404 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000405 self.assertEqual(len(blocks), 3)
406 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000407 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000408 self.assertIn('raise KeyError from e', blocks[0])
409 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000410 # The second block (apart from the boundary) is the ZeroDivisionError
411 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000412 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000413 self.check_zero_div(blocks[2])
414
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000415 def test_syntax_error_offset_at_eol(self):
416 # See #10186.
417 def e():
418 raise SyntaxError('', ('', 0, 5, 'hello'))
419 msg = self.get_report(e).splitlines()
420 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000421 def e():
422 exec("x = 5 | 4 |")
423 msg = self.get_report(e).splitlines()
424 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000425
426
427class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
428 #
429 # This checks reporting through the 'traceback' module, with both
430 # format_exception() and print_exception().
431 #
432
433 def get_report(self, e):
434 e = self.get_exception(e)
435 s = ''.join(
436 traceback.format_exception(type(e), e, e.__traceback__))
437 with captured_output("stderr") as sio:
438 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000439 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000440 return s
441
442
443class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
444 #
445 # This checks built-in reporting by the interpreter.
446 #
447
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200448 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000449 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200450 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000451 e = self.get_exception(e)
452 with captured_output("stderr") as s:
453 exception_print(e)
454 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000455
456
Andrew Kuchling173a1572013-09-15 18:15:56 -0400457class MiscTracebackCases(unittest.TestCase):
458 #
459 # Check non-printing functions in traceback module
460 #
461
462 def test_clear(self):
463 def outer():
464 middle()
465 def middle():
466 inner()
467 def inner():
468 i = 1
469 1/0
470
471 try:
472 outer()
473 except:
474 type_, value, tb = sys.exc_info()
475
476 # Initial assertion: there's one local in the inner frame.
477 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
478 self.assertEqual(len(inner_frame.f_locals), 1)
479
480 # Clear traceback frames
481 traceback.clear_frames(tb)
482
483 # Local variable dict should now be empty.
484 self.assertEqual(len(inner_frame.f_locals), 0)
485
486
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300487class TestFrame(unittest.TestCase):
488
489 def test_basics(self):
490 linecache.clearcache()
491 linecache.lazycache("f", globals())
492 f = traceback.FrameSummary("f", 1, "dummy")
493 self.assertEqual(
494 ("f", 1, "dummy", '"""Test cases for traceback module"""'),
495 tuple(f))
496 self.assertEqual(None, f.locals)
497
498 def test_lazy_lines(self):
499 linecache.clearcache()
500 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
501 self.assertEqual(None, f._line)
502 linecache.lazycache("f", globals())
503 self.assertEqual(
504 '"""Test cases for traceback module"""',
505 f.line)
506
507 def test_explicit_line(self):
508 f = traceback.FrameSummary("f", 1, "dummy", line="line")
509 self.assertEqual("line", f.line)
510
511
512class TestStack(unittest.TestCase):
513
514 def test_walk_stack(self):
515 s = list(traceback.walk_stack(None))
516 self.assertGreater(len(s), 10)
517
518 def test_walk_tb(self):
519 try:
520 1/0
521 except Exception:
522 _, _, tb = sys.exc_info()
523 s = list(traceback.walk_tb(tb))
524 self.assertEqual(len(s), 1)
525
526 def test_extract_stack(self):
527 s = traceback.StackSummary.extract(traceback.walk_stack(None))
528 self.assertIsInstance(s, traceback.StackSummary)
529
530 def test_extract_stack_limit(self):
531 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
532 self.assertEqual(len(s), 5)
533
534 def test_extract_stack_lookup_lines(self):
535 linecache.clearcache()
536 linecache.updatecache('/foo.py', globals())
537 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300538 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300539 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
540 linecache.clearcache()
541 self.assertEqual(s[0].line, "import sys")
542
543 def test_extract_stackup_deferred_lookup_lines(self):
544 linecache.clearcache()
545 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300546 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300547 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
548 self.assertEqual({}, linecache.cache)
549 linecache.updatecache('/foo.py', globals())
550 self.assertEqual(s[0].line, "import sys")
551
552 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300553 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300554 self.assertEqual(
555 [' File "foo.py", line 1, in fred\n line\n'],
556 s.format())
557
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300558 def test_from_list_edited_stack(self):
559 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
560 s[0] = ('foo.py', 2, 'fred', 'line')
561 s2 = traceback.StackSummary.from_list(s)
562 self.assertEqual(
563 [' File "foo.py", line 2, in fred\n line\n'],
564 s2.format())
565
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300566 def test_format_smoke(self):
567 # For detailed tests see the format_list tests, which consume the same
568 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300569 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300570 self.assertEqual(
571 [' File "foo.py", line 1, in fred\n line\n'],
572 s.format())
573
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300574 def test_locals(self):
575 linecache.updatecache('/foo.py', globals())
576 c = test_code('/foo.py', 'method')
577 f = test_frame(c, globals(), {'something': 1})
578 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
579 self.assertEqual(s[0].locals, {'something': '1'})
580
581 def test_no_locals(self):
582 linecache.updatecache('/foo.py', globals())
583 c = test_code('/foo.py', 'method')
584 f = test_frame(c, globals(), {'something': 1})
585 s = traceback.StackSummary.extract(iter([(f, 6)]))
586 self.assertEqual(s[0].locals, None)
587
588 def test_format_locals(self):
589 def some_inner(k, v):
590 a = 1
591 b = 2
592 return traceback.StackSummary.extract(
593 traceback.walk_stack(None), capture_locals=True, limit=1)
594 s = some_inner(3, 4)
595 self.assertEqual(
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300596 [' File "' + __file__ + '", line 593, '
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300597 'in some_inner\n'
598 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
599 ' a = 1\n'
600 ' b = 2\n'
601 ' k = 3\n'
602 ' v = 4\n'
603 ], s.format())
604
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300605
606
607class TestTracebackException(unittest.TestCase):
608
609 def test_smoke(self):
610 try:
611 1/0
612 except Exception:
613 exc_info = sys.exc_info()
614 exc = traceback.TracebackException(*exc_info)
615 expected_stack = traceback.StackSummary.extract(
616 traceback.walk_tb(exc_info[2]))
617 self.assertEqual(None, exc.__cause__)
618 self.assertEqual(None, exc.__context__)
619 self.assertEqual(False, exc.__suppress_context__)
620 self.assertEqual(expected_stack, exc.stack)
621 self.assertEqual(exc_info[0], exc.exc_type)
622 self.assertEqual(str(exc_info[1]), str(exc))
623
624 def test_from_exception(self):
625 # Check all the parameters are accepted.
626 def foo():
627 1/0
628 try:
629 foo()
630 except Exception as e:
631 exc_info = sys.exc_info()
632 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300633 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
634 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300635 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300636 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300637 expected_stack = self.expected_stack
638 exc = self.exc
639 self.assertEqual(None, exc.__cause__)
640 self.assertEqual(None, exc.__context__)
641 self.assertEqual(False, exc.__suppress_context__)
642 self.assertEqual(expected_stack, exc.stack)
643 self.assertEqual(exc_info[0], exc.exc_type)
644 self.assertEqual(str(exc_info[1]), str(exc))
645
646 def test_cause(self):
647 try:
648 try:
649 1/0
650 finally:
651 exc_info_context = sys.exc_info()
652 exc_context = traceback.TracebackException(*exc_info_context)
653 cause = Exception("cause")
654 raise Exception("uh oh") from cause
655 except Exception:
656 exc_info = sys.exc_info()
657 exc = traceback.TracebackException(*exc_info)
658 expected_stack = traceback.StackSummary.extract(
659 traceback.walk_tb(exc_info[2]))
660 exc_cause = traceback.TracebackException(Exception, cause, None)
661 self.assertEqual(exc_cause, exc.__cause__)
662 self.assertEqual(exc_context, exc.__context__)
663 self.assertEqual(True, exc.__suppress_context__)
664 self.assertEqual(expected_stack, exc.stack)
665 self.assertEqual(exc_info[0], exc.exc_type)
666 self.assertEqual(str(exc_info[1]), str(exc))
667
668 def test_context(self):
669 try:
670 try:
671 1/0
672 finally:
673 exc_info_context = sys.exc_info()
674 exc_context = traceback.TracebackException(*exc_info_context)
675 raise Exception("uh oh")
676 except Exception:
677 exc_info = sys.exc_info()
678 exc = traceback.TracebackException(*exc_info)
679 expected_stack = traceback.StackSummary.extract(
680 traceback.walk_tb(exc_info[2]))
681 self.assertEqual(None, exc.__cause__)
682 self.assertEqual(exc_context, exc.__context__)
683 self.assertEqual(False, exc.__suppress_context__)
684 self.assertEqual(expected_stack, exc.stack)
685 self.assertEqual(exc_info[0], exc.exc_type)
686 self.assertEqual(str(exc_info[1]), str(exc))
687
688 def test_limit(self):
689 def recurse(n):
690 if n:
691 recurse(n-1)
692 else:
693 1/0
694 try:
695 recurse(10)
696 except Exception:
697 exc_info = sys.exc_info()
698 exc = traceback.TracebackException(*exc_info, limit=5)
699 expected_stack = traceback.StackSummary.extract(
700 traceback.walk_tb(exc_info[2]), limit=5)
701 self.assertEqual(expected_stack, exc.stack)
702
703 def test_lookup_lines(self):
704 linecache.clearcache()
705 e = Exception("uh oh")
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 tb = test_tb(f, 6, None)
709 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
710 self.assertEqual({}, linecache.cache)
711 linecache.updatecache('/foo.py', globals())
712 self.assertEqual(exc.stack[0].line, "import sys")
713
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300714 def test_locals(self):
715 linecache.updatecache('/foo.py', globals())
716 e = Exception("uh oh")
717 c = test_code('/foo.py', 'method')
718 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
719 tb = test_tb(f, 6, None)
720 exc = traceback.TracebackException(
721 Exception, e, tb, capture_locals=True)
722 self.assertEqual(
723 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
724
725 def test_no_locals(self):
726 linecache.updatecache('/foo.py', globals())
727 e = Exception("uh oh")
728 c = test_code('/foo.py', 'method')
729 f = test_frame(c, globals(), {'something': 1})
730 tb = test_tb(f, 6, None)
731 exc = traceback.TracebackException(Exception, e, tb)
732 self.assertEqual(exc.stack[0].locals, None)
733
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300734
Fred Drake2e2be372001-09-20 21:33:42 +0000735def test_main():
Benjamin Petersone6528212008-07-15 15:32:09 +0000736 run_unittest(__name__)
Fred Drake2e2be372001-09-20 21:33:42 +0000737
738if __name__ == "__main__":
739 test_main()