blob: fc7e6cce96edf0b291cd546b972a14959bf2ee94 [file] [log] [blame]
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00001"""Test cases for traceback module"""
2
Robert Collins6bc2c1e2015-03-05 12:07:57 +13003from collections import namedtuple
Christian Heimes81ee3ef2008-05-04 22:42:01 +00004from io import StringIO
Robert Collins6bc2c1e2015-03-05 12:07:57 +13005import linecache
Christian Heimes81ee3ef2008-05-04 22:42:01 +00006import sys
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00007import unittest
Benjamin Petersone6528212008-07-15 15:32:09 +00008import re
Serhiy Storchaka24559e42015-05-03 13:19:46 +03009from test import support
Berker Peksag716b3d32015-04-08 09:47:14 +030010from test.support import TESTFN, Error, captured_output, unlink, cpython_only
Berker Peksagce643912015-05-06 06:33:17 +030011from test.support.script_helper import assert_python_ok
Victor Stinner9d279b82014-12-05 10:18:30 +010012import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000013
14import traceback
15
Christian Heimes81ee3ef2008-05-04 22:42:01 +000016
Robert Collins6bc2c1e2015-03-05 12:07:57 +130017test_code = namedtuple('code', ['co_filename', 'co_name'])
Robert Collinsd7c7e0e2015-03-05 20:28:52 +130018test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
Robert Collins6bc2c1e2015-03-05 12:07:57 +130019test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next'])
20
21
Benjamin Petersone6528212008-07-15 15:32:09 +000022class SyntaxTracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000023 # For now, a very minimal set of tests. I want to be sure that
24 # formatting of SyntaxErrors works based on changes for 2.1.
25
26 def get_exception_format(self, func, exc):
27 try:
28 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000029 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000030 return traceback.format_exception_only(exc, value)
31 else:
Collin Winter3add4d72007-08-29 23:37:32 +000032 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000033
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000034 def syntax_error_with_caret(self):
35 compile("def fact(x):\n\treturn x!\n", "?", "exec")
36
Georg Brandl751899a2009-06-04 19:41:00 +000037 def syntax_error_with_caret_2(self):
38 compile("1 +\n", "?", "exec")
39
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000040 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000041 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000042
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020043 def syntax_error_with_caret_non_ascii(self):
44 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
45
Florent Xicluna758fa5e2014-01-22 01:11:43 +010046 def syntax_error_bad_indentation2(self):
47 compile(" print(2)", "?", "exec")
48
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000049 def test_caret(self):
50 err = self.get_exception_format(self.syntax_error_with_caret,
51 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000052 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000053 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000054 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000055 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Tim Peters7e01e282001-04-08 07:44:07 +000056
Georg Brandl751899a2009-06-04 19:41:00 +000057 err = self.get_exception_format(self.syntax_error_with_caret_2,
58 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000059 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010060 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
61 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Georg Brandl751899a2009-06-04 19:41:00 +000062
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020063 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
64 SyntaxError)
65 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010066 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
67 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020068
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000069 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000070 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
71 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000072 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000073 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000074
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075 def test_bad_indentation(self):
76 err = self.get_exception_format(self.syntax_error_bad_indentation,
77 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000078 self.assertEqual(len(err), 4)
79 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +000080 self.assertIn("^", err[2])
Guido van Rossume61fd5b2007-07-11 12:20:59 +000081 self.assertEqual(err[1].find(")"), err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000082
Florent Xicluna758fa5e2014-01-22 01:11:43 +010083 err = self.get_exception_format(self.syntax_error_bad_indentation2,
84 IndentationError)
85 self.assertEqual(len(err), 4)
86 self.assertEqual(err[1].strip(), "print(2)")
87 self.assertIn("^", err[2])
88 self.assertEqual(err[1].find("p"), err[2].find("^"))
89
Thomas Wouters477c8d52006-05-27 19:21:47 +000090 def test_base_exception(self):
91 # Test that exceptions derived from BaseException are formatted right
92 e = KeyboardInterrupt()
93 lst = traceback.format_exception_only(e.__class__, e)
94 self.assertEqual(lst, ['KeyboardInterrupt\n'])
95
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 def test_format_exception_only_bad__str__(self):
97 class X(Exception):
98 def __str__(self):
99 1/0
100 err = traceback.format_exception_only(X, X())
101 self.assertEqual(len(err), 1)
102 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +0000103 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300104 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +0000105 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300106 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000107 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108
Thomas Wouters89f507f2006-12-13 04:49:30 +0000109 def test_without_exception(self):
110 err = traceback.format_exception_only(None, None)
111 self.assertEqual(err, ['None\n'])
112
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000113 def test_encoded_file(self):
114 # Test that tracebacks are correctly printed for encoded source files:
115 # - correct line number (Issue2384)
116 # - respect file encoding (Issue3975)
117 import tempfile, sys, subprocess, os
118
119 # The spawned subprocess has its stdout redirected to a PIPE, and its
120 # encoding may be different from the current interpreter, on Windows
121 # at least.
122 process = subprocess.Popen([sys.executable, "-c",
123 "import sys; print(sys.stdout.encoding)"],
124 stdout=subprocess.PIPE,
125 stderr=subprocess.STDOUT)
126 stdout, stderr = process.communicate()
127 output_encoding = str(stdout, 'ascii').splitlines()[0]
128
129 def do_test(firstlines, message, charset, lineno):
130 # Raise the message in a subprocess, and catch the output
131 try:
Victor Stinner51d8c522016-02-08 17:57:02 +0100132 with open(TESTFN, "w", encoding=charset) as output:
133 output.write("""{0}if 1:
134 import traceback;
135 raise RuntimeError('{1}')
136 """.format(firstlines, message))
137
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000138 process = subprocess.Popen([sys.executable, TESTFN],
139 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
140 stdout, stderr = process.communicate()
141 stdout = stdout.decode(output_encoding).splitlines()
142 finally:
143 unlink(TESTFN)
144
145 # The source lines are encoded with the 'backslashreplace' handler
146 encoded_message = message.encode(output_encoding,
147 'backslashreplace')
148 # and we just decoded them with the output_encoding.
149 message_ascii = encoded_message.decode(output_encoding)
150
151 err_line = "raise RuntimeError('{0}')".format(message_ascii)
152 err_msg = "RuntimeError: {0}".format(message_ascii)
153
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000154 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000155 "Invalid line number: {0!r} instead of {1}".format(
156 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000157 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000158 "Invalid traceback line: {0!r} instead of {1!r}".format(
159 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000160 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000161 "Invalid error message: {0!r} instead of {1!r}".format(
162 stdout[3], err_msg))
163
164 do_test("", "foo", "ascii", 3)
165 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
166 if charset == "ascii":
167 text = "foo"
168 elif charset == "GBK":
169 text = "\u4E02\u5100"
170 else:
171 text = "h\xe9 ho"
172 do_test("# coding: {0}\n".format(charset),
173 text, charset, 4)
174 do_test("#!shebang\n# coding: {0}\n".format(charset),
175 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200176 do_test(" \t\f\n# coding: {0}\n".format(charset),
177 text, charset, 5)
Martin Panter614827c2016-04-19 04:05:59 +0000178 # Issue #18960: coding spec should have no effect
Victor Stinner51d8c522016-02-08 17:57:02 +0100179 do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000180
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
Nick Coghland0034232016-08-15 13:11:34 +1000306 # issue 26823 - Shrink recursive tracebacks
307 def _check_recursive_traceback_display(self, render_exc):
308 # Always show full diffs when this test fails
309 # Note that rearranging things may require adjusting
310 # the relative line numbers in the expected tracebacks
311 self.maxDiff = None
312
313 # Check hitting the recursion limit
314 def f():
315 f()
316
317 with captured_output("stderr") as stderr_f:
318 try:
319 f()
320 except RecursionError as exc:
321 render_exc()
322 else:
323 self.fail("no recursion occurred")
324
325 lineno_f = f.__code__.co_firstlineno
326 result_f = (
327 'Traceback (most recent call last):\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400328 f' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000329 ' f()\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400330 f' File "{__file__}", line {lineno_f+1}, in f''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000331 ' f()\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400332 f' File "{__file__}", line {lineno_f+1}, in f''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000333 ' f()\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400334 f' File "{__file__}", line {lineno_f+1}, in f''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000335 ' f()\n'
336 # XXX: The following line changes depending on whether the tests
337 # are run through the interactive interpreter or with -m
338 # It also varies depending on the platform (stack size)
339 # Fortunately, we don't care about exactness here, so we use regex
340 r' \[Previous line repeated (\d+) more times\]' '\n'
341 'RecursionError: maximum recursion depth exceeded\n'
342 )
343
344 expected = result_f.splitlines()
345 actual = stderr_f.getvalue().splitlines()
346
347 # Check the output text matches expectations
348 # 2nd last line contains the repetition count
349 self.assertEqual(actual[:-2], expected[:-2])
350 self.assertRegex(actual[-2], expected[-2])
351 self.assertEqual(actual[-1], expected[-1])
352
353 # Check the recursion count is roughly as expected
354 rec_limit = sys.getrecursionlimit()
355 self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-50, rec_limit))
356
357 # Check a known (limited) number of recursive invocations
358 def g(count=10):
359 if count:
360 return g(count-1)
361 raise ValueError
362
363 with captured_output("stderr") as stderr_g:
364 try:
365 g()
366 except ValueError as exc:
367 render_exc()
368 else:
369 self.fail("no value error was raised")
370
371 lineno_g = g.__code__.co_firstlineno
372 result_g = (
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400373 f' File "{__file__}", line {lineno_g+2}, in g''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000374 ' return g(count-1)\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400375 f' File "{__file__}", line {lineno_g+2}, in g''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000376 ' return g(count-1)\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400377 f' File "{__file__}", line {lineno_g+2}, in g''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000378 ' return g(count-1)\n'
379 ' [Previous line repeated 6 more times]\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400380 f' File "{__file__}", line {lineno_g+3}, in g''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000381 ' raise ValueError\n'
382 'ValueError\n'
383 )
384 tb_line = (
385 'Traceback (most recent call last):\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400386 f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000387 ' g()\n'
388 )
389 expected = (tb_line + result_g).splitlines()
390 actual = stderr_g.getvalue().splitlines()
391 self.assertEqual(actual, expected)
392
393 # Check 2 different repetitive sections
394 def h(count=10):
395 if count:
396 return h(count-1)
397 g()
398
399 with captured_output("stderr") as stderr_h:
400 try:
401 h()
402 except ValueError as exc:
403 render_exc()
404 else:
405 self.fail("no value error was raised")
406
407 lineno_h = h.__code__.co_firstlineno
408 result_h = (
409 'Traceback (most recent call last):\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400410 f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000411 ' h()\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400412 f' File "{__file__}", line {lineno_h+2}, in h''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000413 ' return h(count-1)\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400414 f' File "{__file__}", line {lineno_h+2}, in h''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000415 ' return h(count-1)\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400416 f' File "{__file__}", line {lineno_h+2}, in h''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000417 ' return h(count-1)\n'
418 ' [Previous line repeated 6 more times]\n'
Eric V. Smith1b8f7b82016-09-03 11:01:53 -0400419 f' File "{__file__}", line {lineno_h+3}, in h''\n'
Nick Coghland0034232016-08-15 13:11:34 +1000420 ' g()\n'
421 )
422 expected = (result_h + result_g).splitlines()
423 actual = stderr_h.getvalue().splitlines()
424 self.assertEqual(actual, expected)
425
426 def test_recursive_traceback_python(self):
427 self._check_recursive_traceback_display(traceback.print_exc)
428
429 @cpython_only
430 def test_recursive_traceback_cpython_internal(self):
431 from _testcapi import exception_print
432 def render_exc():
433 exc_type, exc_value, exc_tb = sys.exc_info()
434 exception_print(exc_value)
435 self._check_recursive_traceback_display(render_exc)
436
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300437 def test_format_stack(self):
438 def fmt():
439 return traceback.format_stack()
440 result = fmt()
441 lineno = fmt.__code__.co_firstlineno
442 self.assertEqual(result[-2:], [
443 ' File "%s", line %d, in test_format_stack\n'
444 ' result = fmt()\n' % (__file__, lineno+2),
445 ' File "%s", line %d, in fmt\n'
446 ' return traceback.format_stack()\n' % (__file__, lineno+1),
447 ])
448
Benjamin Petersone6528212008-07-15 15:32:09 +0000449
450cause_message = (
451 "\nThe above exception was the direct cause "
452 "of the following exception:\n\n")
453
454context_message = (
455 "\nDuring handling of the above exception, "
456 "another exception occurred:\n\n")
457
458boundaries = re.compile(
459 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
460
461
462class BaseExceptionReportingTests:
463
464 def get_exception(self, exception_or_callable):
465 if isinstance(exception_or_callable, Exception):
466 return exception_or_callable
467 try:
468 exception_or_callable()
469 except Exception as e:
470 return e
471
472 def zero_div(self):
473 1/0 # In zero_div
474
475 def check_zero_div(self, msg):
476 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000477 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000478 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000479 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000480
481 def test_simple(self):
482 try:
483 1/0 # Marker
484 except ZeroDivisionError as _:
485 e = _
486 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000487 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000488 self.assertTrue(lines[0].startswith('Traceback'))
489 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000490 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000491 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000492
493 def test_cause(self):
494 def inner_raise():
495 try:
496 self.zero_div()
497 except ZeroDivisionError as e:
498 raise KeyError from e
499 def outer_raise():
500 inner_raise() # Marker
501 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000502 self.assertEqual(len(blocks), 3)
503 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000504 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000505 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000506
507 def test_context(self):
508 def inner_raise():
509 try:
510 self.zero_div()
511 except ZeroDivisionError:
512 raise KeyError
513 def outer_raise():
514 inner_raise() # Marker
515 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000516 self.assertEqual(len(blocks), 3)
517 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000518 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000519 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000520
Nick Coghlanab7bf212012-02-26 17:49:52 +1000521 def test_context_suppression(self):
522 try:
523 try:
524 raise Exception
525 except:
526 raise ZeroDivisionError from None
527 except ZeroDivisionError as _:
528 e = _
529 lines = self.get_report(e).splitlines()
530 self.assertEqual(len(lines), 4)
531 self.assertTrue(lines[0].startswith('Traceback'))
532 self.assertTrue(lines[1].startswith(' File'))
533 self.assertIn('ZeroDivisionError from None', lines[2])
534 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
535
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000536 def test_cause_and_context(self):
537 # When both a cause and a context are set, only the cause should be
538 # displayed and the context should be muted.
539 def inner_raise():
540 try:
541 self.zero_div()
542 except ZeroDivisionError as _e:
543 e = _e
544 try:
545 xyzzy
546 except NameError:
547 raise KeyError from e
548 def outer_raise():
549 inner_raise() # Marker
550 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000551 self.assertEqual(len(blocks), 3)
552 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000553 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000554 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000555
Benjamin Petersone6528212008-07-15 15:32:09 +0000556 def test_cause_recursive(self):
557 def inner_raise():
558 try:
559 try:
560 self.zero_div()
561 except ZeroDivisionError as e:
562 z = e
563 raise KeyError from e
564 except KeyError as e:
565 raise z from e
566 def outer_raise():
567 inner_raise() # Marker
568 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000569 self.assertEqual(len(blocks), 3)
570 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000571 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000572 self.assertIn('raise KeyError from e', blocks[0])
573 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000574 # The second block (apart from the boundary) is the ZeroDivisionError
575 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000576 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000577 self.check_zero_div(blocks[2])
578
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000579 def test_syntax_error_offset_at_eol(self):
580 # See #10186.
581 def e():
582 raise SyntaxError('', ('', 0, 5, 'hello'))
583 msg = self.get_report(e).splitlines()
584 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000585 def e():
586 exec("x = 5 | 4 |")
587 msg = self.get_report(e).splitlines()
588 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000589
590
591class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
592 #
593 # This checks reporting through the 'traceback' module, with both
594 # format_exception() and print_exception().
595 #
596
597 def get_report(self, e):
598 e = self.get_exception(e)
599 s = ''.join(
600 traceback.format_exception(type(e), e, e.__traceback__))
601 with captured_output("stderr") as sio:
602 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000603 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000604 return s
605
606
607class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
608 #
609 # This checks built-in reporting by the interpreter.
610 #
611
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200612 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000613 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200614 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000615 e = self.get_exception(e)
616 with captured_output("stderr") as s:
617 exception_print(e)
618 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000619
620
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300621class LimitTests(unittest.TestCase):
622
623 ''' Tests for limit argument.
624 It's enough to test extact_tb, extract_stack and format_exception '''
625
626 def last_raises1(self):
627 raise Exception('Last raised')
628
629 def last_raises2(self):
630 self.last_raises1()
631
632 def last_raises3(self):
633 self.last_raises2()
634
635 def last_raises4(self):
636 self.last_raises3()
637
638 def last_raises5(self):
639 self.last_raises4()
640
641 def last_returns_frame1(self):
642 return sys._getframe()
643
644 def last_returns_frame2(self):
645 return self.last_returns_frame1()
646
647 def last_returns_frame3(self):
648 return self.last_returns_frame2()
649
650 def last_returns_frame4(self):
651 return self.last_returns_frame3()
652
653 def last_returns_frame5(self):
654 return self.last_returns_frame4()
655
656 def test_extract_stack(self):
657 frame = self.last_returns_frame5()
658 def extract(**kwargs):
659 return traceback.extract_stack(frame, **kwargs)
660 def assertEqualExcept(actual, expected, ignore):
661 self.assertEqual(actual[:ignore], expected[:ignore])
662 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
663 self.assertEqual(len(actual), len(expected))
664
665 with support.swap_attr(sys, 'tracebacklimit', 1000):
666 nolim = extract()
667 self.assertGreater(len(nolim), 5)
668 self.assertEqual(extract(limit=2), nolim[-2:])
669 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
670 self.assertEqual(extract(limit=-2), nolim[:2])
671 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
672 self.assertEqual(extract(limit=0), [])
673 del sys.tracebacklimit
674 assertEqualExcept(extract(), nolim, -5-1)
675 sys.tracebacklimit = 2
676 self.assertEqual(extract(), nolim[-2:])
677 self.assertEqual(extract(limit=3), nolim[-3:])
678 self.assertEqual(extract(limit=-3), nolim[:3])
679 sys.tracebacklimit = 0
680 self.assertEqual(extract(), [])
681 sys.tracebacklimit = -1
682 self.assertEqual(extract(), [])
683
684 def test_extract_tb(self):
685 try:
686 self.last_raises5()
687 except Exception:
688 exc_type, exc_value, tb = sys.exc_info()
689 def extract(**kwargs):
690 return traceback.extract_tb(tb, **kwargs)
691
692 with support.swap_attr(sys, 'tracebacklimit', 1000):
693 nolim = extract()
694 self.assertEqual(len(nolim), 5+1)
695 self.assertEqual(extract(limit=2), nolim[:2])
696 self.assertEqual(extract(limit=10), nolim)
697 self.assertEqual(extract(limit=-2), nolim[-2:])
698 self.assertEqual(extract(limit=-10), nolim)
699 self.assertEqual(extract(limit=0), [])
700 del sys.tracebacklimit
701 self.assertEqual(extract(), nolim)
702 sys.tracebacklimit = 2
703 self.assertEqual(extract(), nolim[:2])
704 self.assertEqual(extract(limit=3), nolim[:3])
705 self.assertEqual(extract(limit=-3), nolim[-3:])
706 sys.tracebacklimit = 0
707 self.assertEqual(extract(), [])
708 sys.tracebacklimit = -1
709 self.assertEqual(extract(), [])
710
711 def test_format_exception(self):
712 try:
713 self.last_raises5()
714 except Exception:
715 exc_type, exc_value, tb = sys.exc_info()
716 # [1:-1] to exclude "Traceback (...)" header and
717 # exception type and value
718 def extract(**kwargs):
719 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
720
721 with support.swap_attr(sys, 'tracebacklimit', 1000):
722 nolim = extract()
723 self.assertEqual(len(nolim), 5+1)
724 self.assertEqual(extract(limit=2), nolim[:2])
725 self.assertEqual(extract(limit=10), nolim)
726 self.assertEqual(extract(limit=-2), nolim[-2:])
727 self.assertEqual(extract(limit=-10), nolim)
728 self.assertEqual(extract(limit=0), [])
729 del sys.tracebacklimit
730 self.assertEqual(extract(), nolim)
731 sys.tracebacklimit = 2
732 self.assertEqual(extract(), nolim[:2])
733 self.assertEqual(extract(limit=3), nolim[:3])
734 self.assertEqual(extract(limit=-3), nolim[-3:])
735 sys.tracebacklimit = 0
736 self.assertEqual(extract(), [])
737 sys.tracebacklimit = -1
738 self.assertEqual(extract(), [])
739
740
Andrew Kuchling173a1572013-09-15 18:15:56 -0400741class MiscTracebackCases(unittest.TestCase):
742 #
743 # Check non-printing functions in traceback module
744 #
745
746 def test_clear(self):
747 def outer():
748 middle()
749 def middle():
750 inner()
751 def inner():
752 i = 1
753 1/0
754
755 try:
756 outer()
757 except:
758 type_, value, tb = sys.exc_info()
759
760 # Initial assertion: there's one local in the inner frame.
761 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
762 self.assertEqual(len(inner_frame.f_locals), 1)
763
764 # Clear traceback frames
765 traceback.clear_frames(tb)
766
767 # Local variable dict should now be empty.
768 self.assertEqual(len(inner_frame.f_locals), 0)
769
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300770 def test_extract_stack(self):
771 def extract():
772 return traceback.extract_stack()
773 result = extract()
774 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300775 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300776 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
777 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
778 ])
779
Andrew Kuchling173a1572013-09-15 18:15:56 -0400780
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300781class TestFrame(unittest.TestCase):
782
783 def test_basics(self):
784 linecache.clearcache()
785 linecache.lazycache("f", globals())
786 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +0300787 self.assertEqual(f,
788 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
789 self.assertEqual(tuple(f),
790 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
791 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
792 self.assertEqual(f, tuple(f))
793 # Since tuple.__eq__ doesn't support FrameSummary, the equality
794 # operator fallbacks to FrameSummary.__eq__.
795 self.assertEqual(tuple(f), f)
796 self.assertIsNone(f.locals)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300797
798 def test_lazy_lines(self):
799 linecache.clearcache()
800 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
801 self.assertEqual(None, f._line)
802 linecache.lazycache("f", globals())
803 self.assertEqual(
804 '"""Test cases for traceback module"""',
805 f.line)
806
807 def test_explicit_line(self):
808 f = traceback.FrameSummary("f", 1, "dummy", line="line")
809 self.assertEqual("line", f.line)
810
811
812class TestStack(unittest.TestCase):
813
814 def test_walk_stack(self):
815 s = list(traceback.walk_stack(None))
816 self.assertGreater(len(s), 10)
817
818 def test_walk_tb(self):
819 try:
820 1/0
821 except Exception:
822 _, _, tb = sys.exc_info()
823 s = list(traceback.walk_tb(tb))
824 self.assertEqual(len(s), 1)
825
826 def test_extract_stack(self):
827 s = traceback.StackSummary.extract(traceback.walk_stack(None))
828 self.assertIsInstance(s, traceback.StackSummary)
829
830 def test_extract_stack_limit(self):
831 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
832 self.assertEqual(len(s), 5)
833
834 def test_extract_stack_lookup_lines(self):
835 linecache.clearcache()
836 linecache.updatecache('/foo.py', globals())
837 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300838 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300839 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
840 linecache.clearcache()
841 self.assertEqual(s[0].line, "import sys")
842
843 def test_extract_stackup_deferred_lookup_lines(self):
844 linecache.clearcache()
845 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300846 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300847 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
848 self.assertEqual({}, linecache.cache)
849 linecache.updatecache('/foo.py', globals())
850 self.assertEqual(s[0].line, "import sys")
851
852 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300853 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300854 self.assertEqual(
855 [' File "foo.py", line 1, in fred\n line\n'],
856 s.format())
857
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300858 def test_from_list_edited_stack(self):
859 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
860 s[0] = ('foo.py', 2, 'fred', 'line')
861 s2 = traceback.StackSummary.from_list(s)
862 self.assertEqual(
863 [' File "foo.py", line 2, in fred\n line\n'],
864 s2.format())
865
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300866 def test_format_smoke(self):
867 # For detailed tests see the format_list tests, which consume the same
868 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300869 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300870 self.assertEqual(
871 [' File "foo.py", line 1, in fred\n line\n'],
872 s.format())
873
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300874 def test_locals(self):
875 linecache.updatecache('/foo.py', globals())
876 c = test_code('/foo.py', 'method')
877 f = test_frame(c, globals(), {'something': 1})
878 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
879 self.assertEqual(s[0].locals, {'something': '1'})
880
881 def test_no_locals(self):
882 linecache.updatecache('/foo.py', globals())
883 c = test_code('/foo.py', 'method')
884 f = test_frame(c, globals(), {'something': 1})
885 s = traceback.StackSummary.extract(iter([(f, 6)]))
886 self.assertEqual(s[0].locals, None)
887
888 def test_format_locals(self):
889 def some_inner(k, v):
890 a = 1
891 b = 2
892 return traceback.StackSummary.extract(
893 traceback.walk_stack(None), capture_locals=True, limit=1)
894 s = some_inner(3, 4)
895 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300896 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300897 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
898 ' a = 1\n'
899 ' b = 2\n'
900 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300901 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300902 ], s.format())
903
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300904class TestTracebackException(unittest.TestCase):
905
906 def test_smoke(self):
907 try:
908 1/0
909 except Exception:
910 exc_info = sys.exc_info()
911 exc = traceback.TracebackException(*exc_info)
912 expected_stack = traceback.StackSummary.extract(
913 traceback.walk_tb(exc_info[2]))
914 self.assertEqual(None, exc.__cause__)
915 self.assertEqual(None, exc.__context__)
916 self.assertEqual(False, exc.__suppress_context__)
917 self.assertEqual(expected_stack, exc.stack)
918 self.assertEqual(exc_info[0], exc.exc_type)
919 self.assertEqual(str(exc_info[1]), str(exc))
920
921 def test_from_exception(self):
922 # Check all the parameters are accepted.
923 def foo():
924 1/0
925 try:
926 foo()
927 except Exception as e:
928 exc_info = sys.exc_info()
929 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300930 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
931 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300932 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300933 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300934 expected_stack = self.expected_stack
935 exc = self.exc
936 self.assertEqual(None, exc.__cause__)
937 self.assertEqual(None, exc.__context__)
938 self.assertEqual(False, exc.__suppress_context__)
939 self.assertEqual(expected_stack, exc.stack)
940 self.assertEqual(exc_info[0], exc.exc_type)
941 self.assertEqual(str(exc_info[1]), str(exc))
942
943 def test_cause(self):
944 try:
945 try:
946 1/0
947 finally:
948 exc_info_context = sys.exc_info()
949 exc_context = traceback.TracebackException(*exc_info_context)
950 cause = Exception("cause")
951 raise Exception("uh oh") from cause
952 except Exception:
953 exc_info = sys.exc_info()
954 exc = traceback.TracebackException(*exc_info)
955 expected_stack = traceback.StackSummary.extract(
956 traceback.walk_tb(exc_info[2]))
957 exc_cause = traceback.TracebackException(Exception, cause, None)
958 self.assertEqual(exc_cause, exc.__cause__)
959 self.assertEqual(exc_context, exc.__context__)
960 self.assertEqual(True, exc.__suppress_context__)
961 self.assertEqual(expected_stack, exc.stack)
962 self.assertEqual(exc_info[0], exc.exc_type)
963 self.assertEqual(str(exc_info[1]), str(exc))
964
965 def test_context(self):
966 try:
967 try:
968 1/0
969 finally:
970 exc_info_context = sys.exc_info()
971 exc_context = traceback.TracebackException(*exc_info_context)
972 raise Exception("uh oh")
973 except Exception:
974 exc_info = sys.exc_info()
975 exc = traceback.TracebackException(*exc_info)
976 expected_stack = traceback.StackSummary.extract(
977 traceback.walk_tb(exc_info[2]))
978 self.assertEqual(None, exc.__cause__)
979 self.assertEqual(exc_context, exc.__context__)
980 self.assertEqual(False, exc.__suppress_context__)
981 self.assertEqual(expected_stack, exc.stack)
982 self.assertEqual(exc_info[0], exc.exc_type)
983 self.assertEqual(str(exc_info[1]), str(exc))
984
985 def test_limit(self):
986 def recurse(n):
987 if n:
988 recurse(n-1)
989 else:
990 1/0
991 try:
992 recurse(10)
993 except Exception:
994 exc_info = sys.exc_info()
995 exc = traceback.TracebackException(*exc_info, limit=5)
996 expected_stack = traceback.StackSummary.extract(
997 traceback.walk_tb(exc_info[2]), limit=5)
998 self.assertEqual(expected_stack, exc.stack)
999
1000 def test_lookup_lines(self):
1001 linecache.clearcache()
1002 e = Exception("uh oh")
1003 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001004 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001005 tb = test_tb(f, 6, None)
1006 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
1007 self.assertEqual({}, linecache.cache)
1008 linecache.updatecache('/foo.py', globals())
1009 self.assertEqual(exc.stack[0].line, "import sys")
1010
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001011 def test_locals(self):
1012 linecache.updatecache('/foo.py', globals())
1013 e = Exception("uh oh")
1014 c = test_code('/foo.py', 'method')
1015 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
1016 tb = test_tb(f, 6, None)
1017 exc = traceback.TracebackException(
1018 Exception, e, tb, capture_locals=True)
1019 self.assertEqual(
1020 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
1021
1022 def test_no_locals(self):
1023 linecache.updatecache('/foo.py', globals())
1024 e = Exception("uh oh")
1025 c = test_code('/foo.py', 'method')
1026 f = test_frame(c, globals(), {'something': 1})
1027 tb = test_tb(f, 6, None)
1028 exc = traceback.TracebackException(Exception, e, tb)
1029 self.assertEqual(exc.stack[0].locals, None)
1030
Berker Peksagc3f417d2015-07-24 17:36:21 +03001031 def test_traceback_header(self):
1032 # do not print a traceback header if exc_traceback is None
1033 # see issue #24695
1034 exc = traceback.TracebackException(Exception, Exception("haven"), None)
1035 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
1036
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001037
Berker Peksag716b3d32015-04-08 09:47:14 +03001038class MiscTest(unittest.TestCase):
1039
1040 def test_all(self):
1041 expected = set()
1042 blacklist = {'print_list'}
1043 for name in dir(traceback):
1044 if name.startswith('_') or name in blacklist:
1045 continue
1046 module_object = getattr(traceback, name)
1047 if getattr(module_object, '__module__', None) == 'traceback':
1048 expected.add(name)
1049 self.assertCountEqual(traceback.__all__, expected)
1050
Fred Drake2e2be372001-09-20 21:33:42 +00001051
1052if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +03001053 unittest.main()