blob: 641a2df0631192258316a7c43e701c53ae0cb615 [file] [log] [blame]
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00001"""Test cases for traceback module"""
2
Robert Collins6bc2c1e2015-03-05 12:07:57 +13003from collections import namedtuple
Christian Heimes81ee3ef2008-05-04 22:42:01 +00004from io import StringIO
Robert Collins6bc2c1e2015-03-05 12:07:57 +13005import linecache
Christian Heimes81ee3ef2008-05-04 22:42:01 +00006import sys
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00007import unittest
Benjamin Petersone6528212008-07-15 15:32:09 +00008import re
Serhiy Storchaka24559e42015-05-03 13:19:46 +03009from test import support
Berker Peksag716b3d32015-04-08 09:47:14 +030010from test.support import TESTFN, Error, captured_output, unlink, cpython_only
Berker Peksagce643912015-05-06 06:33:17 +030011from test.support.script_helper import assert_python_ok
Victor Stinner9d279b82014-12-05 10:18:30 +010012import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000013
14import traceback
15
Christian Heimes81ee3ef2008-05-04 22:42:01 +000016
Robert Collins6bc2c1e2015-03-05 12:07:57 +130017test_code = namedtuple('code', ['co_filename', 'co_name'])
Robert Collinsd7c7e0e2015-03-05 20:28:52 +130018test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
Robert Collins6bc2c1e2015-03-05 12:07:57 +130019test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next'])
20
21
Benjamin Petersone6528212008-07-15 15:32:09 +000022class SyntaxTracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000023 # For now, a very minimal set of tests. I want to be sure that
24 # formatting of SyntaxErrors works based on changes for 2.1.
25
26 def get_exception_format(self, func, exc):
27 try:
28 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000029 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000030 return traceback.format_exception_only(exc, value)
31 else:
Collin Winter3add4d72007-08-29 23:37:32 +000032 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000033
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000034 def syntax_error_with_caret(self):
35 compile("def fact(x):\n\treturn x!\n", "?", "exec")
36
Georg Brandl751899a2009-06-04 19:41:00 +000037 def syntax_error_with_caret_2(self):
38 compile("1 +\n", "?", "exec")
39
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000040 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000041 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000042
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020043 def syntax_error_with_caret_non_ascii(self):
44 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
45
Florent Xicluna758fa5e2014-01-22 01:11:43 +010046 def syntax_error_bad_indentation2(self):
47 compile(" print(2)", "?", "exec")
48
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000049 def test_caret(self):
50 err = self.get_exception_format(self.syntax_error_with_caret,
51 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000052 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000053 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000054 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000055 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Tim Peters7e01e282001-04-08 07:44:07 +000056
Georg Brandl751899a2009-06-04 19:41:00 +000057 err = self.get_exception_format(self.syntax_error_with_caret_2,
58 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000059 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010060 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
61 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Georg Brandl751899a2009-06-04 19:41:00 +000062
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020063 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
64 SyntaxError)
65 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010066 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
67 self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020068
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000069 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000070 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
71 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000072 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000073 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000074
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075 def test_bad_indentation(self):
76 err = self.get_exception_format(self.syntax_error_bad_indentation,
77 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000078 self.assertEqual(len(err), 4)
79 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +000080 self.assertIn("^", err[2])
Guido van Rossume61fd5b2007-07-11 12:20:59 +000081 self.assertEqual(err[1].find(")"), err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000082
Florent Xicluna758fa5e2014-01-22 01:11:43 +010083 err = self.get_exception_format(self.syntax_error_bad_indentation2,
84 IndentationError)
85 self.assertEqual(len(err), 4)
86 self.assertEqual(err[1].strip(), "print(2)")
87 self.assertIn("^", err[2])
88 self.assertEqual(err[1].find("p"), err[2].find("^"))
89
Thomas Wouters477c8d52006-05-27 19:21:47 +000090 def test_base_exception(self):
91 # Test that exceptions derived from BaseException are formatted right
92 e = KeyboardInterrupt()
93 lst = traceback.format_exception_only(e.__class__, e)
94 self.assertEqual(lst, ['KeyboardInterrupt\n'])
95
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 def test_format_exception_only_bad__str__(self):
97 class X(Exception):
98 def __str__(self):
99 1/0
100 err = traceback.format_exception_only(X, X())
101 self.assertEqual(len(err), 1)
102 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +0000103 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300104 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +0000105 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300106 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000107 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108
Thomas Wouters89f507f2006-12-13 04:49:30 +0000109 def test_without_exception(self):
110 err = traceback.format_exception_only(None, None)
111 self.assertEqual(err, ['None\n'])
112
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000113 def test_encoded_file(self):
114 # Test that tracebacks are correctly printed for encoded source files:
115 # - correct line number (Issue2384)
116 # - respect file encoding (Issue3975)
117 import tempfile, sys, subprocess, os
118
119 # The spawned subprocess has its stdout redirected to a PIPE, and its
120 # encoding may be different from the current interpreter, on Windows
121 # at least.
122 process = subprocess.Popen([sys.executable, "-c",
123 "import sys; print(sys.stdout.encoding)"],
124 stdout=subprocess.PIPE,
125 stderr=subprocess.STDOUT)
126 stdout, stderr = process.communicate()
127 output_encoding = str(stdout, 'ascii').splitlines()[0]
128
129 def do_test(firstlines, message, charset, lineno):
130 # Raise the message in a subprocess, and catch the output
131 try:
132 output = open(TESTFN, "w", encoding=charset)
133 output.write("""{0}if 1:
134 import traceback;
135 raise RuntimeError('{1}')
136 """.format(firstlines, message))
137 output.close()
138 process = subprocess.Popen([sys.executable, TESTFN],
139 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
140 stdout, stderr = process.communicate()
141 stdout = stdout.decode(output_encoding).splitlines()
142 finally:
143 unlink(TESTFN)
144
145 # The source lines are encoded with the 'backslashreplace' handler
146 encoded_message = message.encode(output_encoding,
147 'backslashreplace')
148 # and we just decoded them with the output_encoding.
149 message_ascii = encoded_message.decode(output_encoding)
150
151 err_line = "raise RuntimeError('{0}')".format(message_ascii)
152 err_msg = "RuntimeError: {0}".format(message_ascii)
153
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000154 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000155 "Invalid line number: {0!r} instead of {1}".format(
156 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000157 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000158 "Invalid traceback line: {0!r} instead of {1!r}".format(
159 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000160 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000161 "Invalid error message: {0!r} instead of {1!r}".format(
162 stdout[3], err_msg))
163
164 do_test("", "foo", "ascii", 3)
165 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
166 if charset == "ascii":
167 text = "foo"
168 elif charset == "GBK":
169 text = "\u4E02\u5100"
170 else:
171 text = "h\xe9 ho"
172 do_test("# coding: {0}\n".format(charset),
173 text, charset, 4)
174 do_test("#!shebang\n# coding: {0}\n".format(charset),
175 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200176 do_test(" \t\f\n# coding: {0}\n".format(charset),
177 text, charset, 5)
178 # Issue #18960: coding spec should has no effect
179 do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000180
Victor Stinner9d279b82014-12-05 10:18:30 +0100181 def test_print_traceback_at_exit(self):
182 # Issue #22599: Ensure that it is possible to use the traceback module
183 # to display an exception at Python exit
184 code = textwrap.dedent("""
185 import sys
186 import traceback
187
188 class PrintExceptionAtExit(object):
189 def __init__(self):
190 try:
191 x = 1 / 0
192 except Exception:
193 self.exc_info = sys.exc_info()
194 # self.exc_info[1] (traceback) contains frames:
195 # explicitly clear the reference to self in the current
196 # frame to break a reference cycle
197 self = None
198
199 def __del__(self):
200 traceback.print_exception(*self.exc_info)
201
202 # Keep a reference in the module namespace to call the destructor
203 # when the module is unloaded
204 obj = PrintExceptionAtExit()
205 """)
206 rc, stdout, stderr = assert_python_ok('-c', code)
207 expected = [b'Traceback (most recent call last):',
208 b' File "<string>", line 8, in __init__',
209 b'ZeroDivisionError: division by zero']
210 self.assertEqual(stderr.splitlines(), expected)
211
Berker Peksagc3f417d2015-07-24 17:36:21 +0300212 def test_print_exception(self):
213 output = StringIO()
214 traceback.print_exception(
215 Exception, Exception("projector"), None, file=output
216 )
217 self.assertEqual(output.getvalue(), "Exception: projector\n")
218
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000219
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000220class TracebackFormatTests(unittest.TestCase):
221
Antoine Pitrou58720d62013-08-05 23:26:40 +0200222 def some_exception(self):
223 raise KeyError('blah')
224
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200225 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200226 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200227 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000228 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200229 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000230 except KeyError:
231 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200232 if cleanup_func is not None:
233 # Clear the inner frames, not this one
234 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000235 traceback_fmt = 'Traceback (most recent call last):\n' + \
236 ''.join(traceback.format_tb(tb))
237 file_ = StringIO()
238 traceback_print(tb, file_)
239 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400240 # Call all _tb and _exc functions
241 with captured_output("stderr") as tbstderr:
242 traceback.print_tb(tb)
243 tbfile = StringIO()
244 traceback.print_tb(tb, file=tbfile)
245 with captured_output("stderr") as excstderr:
246 traceback.print_exc()
247 excfmt = traceback.format_exc()
248 excfile = StringIO()
249 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000250 else:
251 raise Error("unable to create test traceback string")
252
253 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000254 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400255 # Now verify the _tb func output
256 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
257 # Now verify the _exc func output
258 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
259 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000260
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000261 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000262 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200263 self.assertEqual(len(tb_lines), 5)
264 banner = tb_lines[0]
265 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000266 self.assertTrue(banner.startswith('Traceback'))
267 self.assertTrue(location.startswith(' File'))
268 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000269
Antoine Pitrou58720d62013-08-05 23:26:40 +0200270 def test_traceback_format(self):
271 self.check_traceback_format()
272
273 def test_traceback_format_with_cleared_frames(self):
274 # Check that traceback formatting also works with a clear()ed frame
275 def cleanup_tb(tb):
276 tb.tb_frame.clear()
277 self.check_traceback_format(cleanup_tb)
278
Benjamin Petersond9fec152013-04-29 16:09:39 -0400279 def test_stack_format(self):
280 # Verify _stack functions. Note we have to use _getframe(1) to
281 # compare them without this frame appearing in the output
282 with captured_output("stderr") as ststderr:
283 traceback.print_stack(sys._getframe(1))
284 stfile = StringIO()
285 traceback.print_stack(sys._getframe(1), file=stfile)
286 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
287
288 stfmt = traceback.format_stack(sys._getframe(1))
289
290 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
291
Benjamin Petersone6528212008-07-15 15:32:09 +0000292
293cause_message = (
294 "\nThe above exception was the direct cause "
295 "of the following exception:\n\n")
296
297context_message = (
298 "\nDuring handling of the above exception, "
299 "another exception occurred:\n\n")
300
301boundaries = re.compile(
302 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
303
304
305class BaseExceptionReportingTests:
306
307 def get_exception(self, exception_or_callable):
308 if isinstance(exception_or_callable, Exception):
309 return exception_or_callable
310 try:
311 exception_or_callable()
312 except Exception as e:
313 return e
314
315 def zero_div(self):
316 1/0 # In zero_div
317
318 def check_zero_div(self, msg):
319 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000320 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000321 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000322 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000323
324 def test_simple(self):
325 try:
326 1/0 # Marker
327 except ZeroDivisionError as _:
328 e = _
329 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000330 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000331 self.assertTrue(lines[0].startswith('Traceback'))
332 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000333 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000334 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000335
336 def test_cause(self):
337 def inner_raise():
338 try:
339 self.zero_div()
340 except ZeroDivisionError as e:
341 raise KeyError from e
342 def outer_raise():
343 inner_raise() # Marker
344 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000345 self.assertEqual(len(blocks), 3)
346 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000347 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000348 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000349
350 def test_context(self):
351 def inner_raise():
352 try:
353 self.zero_div()
354 except ZeroDivisionError:
355 raise KeyError
356 def outer_raise():
357 inner_raise() # Marker
358 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000359 self.assertEqual(len(blocks), 3)
360 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000361 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000362 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000363
Nick Coghlanab7bf212012-02-26 17:49:52 +1000364 def test_context_suppression(self):
365 try:
366 try:
367 raise Exception
368 except:
369 raise ZeroDivisionError from None
370 except ZeroDivisionError as _:
371 e = _
372 lines = self.get_report(e).splitlines()
373 self.assertEqual(len(lines), 4)
374 self.assertTrue(lines[0].startswith('Traceback'))
375 self.assertTrue(lines[1].startswith(' File'))
376 self.assertIn('ZeroDivisionError from None', lines[2])
377 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
378
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000379 def test_cause_and_context(self):
380 # When both a cause and a context are set, only the cause should be
381 # displayed and the context should be muted.
382 def inner_raise():
383 try:
384 self.zero_div()
385 except ZeroDivisionError as _e:
386 e = _e
387 try:
388 xyzzy
389 except NameError:
390 raise KeyError from e
391 def outer_raise():
392 inner_raise() # Marker
393 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000394 self.assertEqual(len(blocks), 3)
395 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000396 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000397 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000398
Benjamin Petersone6528212008-07-15 15:32:09 +0000399 def test_cause_recursive(self):
400 def inner_raise():
401 try:
402 try:
403 self.zero_div()
404 except ZeroDivisionError as e:
405 z = e
406 raise KeyError from e
407 except KeyError as e:
408 raise z from e
409 def outer_raise():
410 inner_raise() # Marker
411 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000412 self.assertEqual(len(blocks), 3)
413 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000414 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000415 self.assertIn('raise KeyError from e', blocks[0])
416 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000417 # The second block (apart from the boundary) is the ZeroDivisionError
418 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000419 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000420 self.check_zero_div(blocks[2])
421
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000422 def test_syntax_error_offset_at_eol(self):
423 # See #10186.
424 def e():
425 raise SyntaxError('', ('', 0, 5, 'hello'))
426 msg = self.get_report(e).splitlines()
427 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000428 def e():
429 exec("x = 5 | 4 |")
430 msg = self.get_report(e).splitlines()
431 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000432
433
434class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
435 #
436 # This checks reporting through the 'traceback' module, with both
437 # format_exception() and print_exception().
438 #
439
440 def get_report(self, e):
441 e = self.get_exception(e)
442 s = ''.join(
443 traceback.format_exception(type(e), e, e.__traceback__))
444 with captured_output("stderr") as sio:
445 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000446 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000447 return s
448
449
450class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
451 #
452 # This checks built-in reporting by the interpreter.
453 #
454
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200455 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000456 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200457 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000458 e = self.get_exception(e)
459 with captured_output("stderr") as s:
460 exception_print(e)
461 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000462
463
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300464class LimitTests(unittest.TestCase):
465
466 ''' Tests for limit argument.
467 It's enough to test extact_tb, extract_stack and format_exception '''
468
469 def last_raises1(self):
470 raise Exception('Last raised')
471
472 def last_raises2(self):
473 self.last_raises1()
474
475 def last_raises3(self):
476 self.last_raises2()
477
478 def last_raises4(self):
479 self.last_raises3()
480
481 def last_raises5(self):
482 self.last_raises4()
483
484 def last_returns_frame1(self):
485 return sys._getframe()
486
487 def last_returns_frame2(self):
488 return self.last_returns_frame1()
489
490 def last_returns_frame3(self):
491 return self.last_returns_frame2()
492
493 def last_returns_frame4(self):
494 return self.last_returns_frame3()
495
496 def last_returns_frame5(self):
497 return self.last_returns_frame4()
498
499 def test_extract_stack(self):
500 frame = self.last_returns_frame5()
501 def extract(**kwargs):
502 return traceback.extract_stack(frame, **kwargs)
503 def assertEqualExcept(actual, expected, ignore):
504 self.assertEqual(actual[:ignore], expected[:ignore])
505 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
506 self.assertEqual(len(actual), len(expected))
507
508 with support.swap_attr(sys, 'tracebacklimit', 1000):
509 nolim = extract()
510 self.assertGreater(len(nolim), 5)
511 self.assertEqual(extract(limit=2), nolim[-2:])
512 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
513 self.assertEqual(extract(limit=-2), nolim[:2])
514 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
515 self.assertEqual(extract(limit=0), [])
516 del sys.tracebacklimit
517 assertEqualExcept(extract(), nolim, -5-1)
518 sys.tracebacklimit = 2
519 self.assertEqual(extract(), nolim[-2:])
520 self.assertEqual(extract(limit=3), nolim[-3:])
521 self.assertEqual(extract(limit=-3), nolim[:3])
522 sys.tracebacklimit = 0
523 self.assertEqual(extract(), [])
524 sys.tracebacklimit = -1
525 self.assertEqual(extract(), [])
526
527 def test_extract_tb(self):
528 try:
529 self.last_raises5()
530 except Exception:
531 exc_type, exc_value, tb = sys.exc_info()
532 def extract(**kwargs):
533 return traceback.extract_tb(tb, **kwargs)
534
535 with support.swap_attr(sys, 'tracebacklimit', 1000):
536 nolim = extract()
537 self.assertEqual(len(nolim), 5+1)
538 self.assertEqual(extract(limit=2), nolim[:2])
539 self.assertEqual(extract(limit=10), nolim)
540 self.assertEqual(extract(limit=-2), nolim[-2:])
541 self.assertEqual(extract(limit=-10), nolim)
542 self.assertEqual(extract(limit=0), [])
543 del sys.tracebacklimit
544 self.assertEqual(extract(), nolim)
545 sys.tracebacklimit = 2
546 self.assertEqual(extract(), nolim[:2])
547 self.assertEqual(extract(limit=3), nolim[:3])
548 self.assertEqual(extract(limit=-3), nolim[-3:])
549 sys.tracebacklimit = 0
550 self.assertEqual(extract(), [])
551 sys.tracebacklimit = -1
552 self.assertEqual(extract(), [])
553
554 def test_format_exception(self):
555 try:
556 self.last_raises5()
557 except Exception:
558 exc_type, exc_value, tb = sys.exc_info()
559 # [1:-1] to exclude "Traceback (...)" header and
560 # exception type and value
561 def extract(**kwargs):
562 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
563
564 with support.swap_attr(sys, 'tracebacklimit', 1000):
565 nolim = extract()
566 self.assertEqual(len(nolim), 5+1)
567 self.assertEqual(extract(limit=2), nolim[:2])
568 self.assertEqual(extract(limit=10), nolim)
569 self.assertEqual(extract(limit=-2), nolim[-2:])
570 self.assertEqual(extract(limit=-10), nolim)
571 self.assertEqual(extract(limit=0), [])
572 del sys.tracebacklimit
573 self.assertEqual(extract(), nolim)
574 sys.tracebacklimit = 2
575 self.assertEqual(extract(), nolim[:2])
576 self.assertEqual(extract(limit=3), nolim[:3])
577 self.assertEqual(extract(limit=-3), nolim[-3:])
578 sys.tracebacklimit = 0
579 self.assertEqual(extract(), [])
580 sys.tracebacklimit = -1
581 self.assertEqual(extract(), [])
582
583
Andrew Kuchling173a1572013-09-15 18:15:56 -0400584class MiscTracebackCases(unittest.TestCase):
585 #
586 # Check non-printing functions in traceback module
587 #
588
589 def test_clear(self):
590 def outer():
591 middle()
592 def middle():
593 inner()
594 def inner():
595 i = 1
596 1/0
597
598 try:
599 outer()
600 except:
601 type_, value, tb = sys.exc_info()
602
603 # Initial assertion: there's one local in the inner frame.
604 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
605 self.assertEqual(len(inner_frame.f_locals), 1)
606
607 # Clear traceback frames
608 traceback.clear_frames(tb)
609
610 # Local variable dict should now be empty.
611 self.assertEqual(len(inner_frame.f_locals), 0)
612
613
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300614class TestFrame(unittest.TestCase):
615
616 def test_basics(self):
617 linecache.clearcache()
618 linecache.lazycache("f", globals())
619 f = traceback.FrameSummary("f", 1, "dummy")
620 self.assertEqual(
621 ("f", 1, "dummy", '"""Test cases for traceback module"""'),
622 tuple(f))
623 self.assertEqual(None, f.locals)
624
625 def test_lazy_lines(self):
626 linecache.clearcache()
627 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
628 self.assertEqual(None, f._line)
629 linecache.lazycache("f", globals())
630 self.assertEqual(
631 '"""Test cases for traceback module"""',
632 f.line)
633
634 def test_explicit_line(self):
635 f = traceback.FrameSummary("f", 1, "dummy", line="line")
636 self.assertEqual("line", f.line)
637
638
639class TestStack(unittest.TestCase):
640
641 def test_walk_stack(self):
642 s = list(traceback.walk_stack(None))
643 self.assertGreater(len(s), 10)
644
645 def test_walk_tb(self):
646 try:
647 1/0
648 except Exception:
649 _, _, tb = sys.exc_info()
650 s = list(traceback.walk_tb(tb))
651 self.assertEqual(len(s), 1)
652
653 def test_extract_stack(self):
654 s = traceback.StackSummary.extract(traceback.walk_stack(None))
655 self.assertIsInstance(s, traceback.StackSummary)
656
657 def test_extract_stack_limit(self):
658 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
659 self.assertEqual(len(s), 5)
660
661 def test_extract_stack_lookup_lines(self):
662 linecache.clearcache()
663 linecache.updatecache('/foo.py', globals())
664 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300665 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300666 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
667 linecache.clearcache()
668 self.assertEqual(s[0].line, "import sys")
669
670 def test_extract_stackup_deferred_lookup_lines(self):
671 linecache.clearcache()
672 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300673 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300674 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
675 self.assertEqual({}, linecache.cache)
676 linecache.updatecache('/foo.py', globals())
677 self.assertEqual(s[0].line, "import sys")
678
679 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300680 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300681 self.assertEqual(
682 [' File "foo.py", line 1, in fred\n line\n'],
683 s.format())
684
Robert Collinsbbb8ade2015-03-16 15:27:16 +1300685 def test_from_list_edited_stack(self):
686 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
687 s[0] = ('foo.py', 2, 'fred', 'line')
688 s2 = traceback.StackSummary.from_list(s)
689 self.assertEqual(
690 [' File "foo.py", line 2, in fred\n line\n'],
691 s2.format())
692
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300693 def test_format_smoke(self):
694 # For detailed tests see the format_list tests, which consume the same
695 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300696 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300697 self.assertEqual(
698 [' File "foo.py", line 1, in fred\n line\n'],
699 s.format())
700
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300701 def test_locals(self):
702 linecache.updatecache('/foo.py', globals())
703 c = test_code('/foo.py', 'method')
704 f = test_frame(c, globals(), {'something': 1})
705 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
706 self.assertEqual(s[0].locals, {'something': '1'})
707
708 def test_no_locals(self):
709 linecache.updatecache('/foo.py', globals())
710 c = test_code('/foo.py', 'method')
711 f = test_frame(c, globals(), {'something': 1})
712 s = traceback.StackSummary.extract(iter([(f, 6)]))
713 self.assertEqual(s[0].locals, None)
714
715 def test_format_locals(self):
716 def some_inner(k, v):
717 a = 1
718 b = 2
719 return traceback.StackSummary.extract(
720 traceback.walk_stack(None), capture_locals=True, limit=1)
721 s = some_inner(3, 4)
722 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300723 [' File "%s", line %d, in some_inner\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300724 ' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
725 ' a = 1\n'
726 ' b = 2\n'
727 ' k = 3\n'
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300728 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 4)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300729 ], s.format())
730
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300731class TestTracebackException(unittest.TestCase):
732
733 def test_smoke(self):
734 try:
735 1/0
736 except Exception:
737 exc_info = sys.exc_info()
738 exc = traceback.TracebackException(*exc_info)
739 expected_stack = traceback.StackSummary.extract(
740 traceback.walk_tb(exc_info[2]))
741 self.assertEqual(None, exc.__cause__)
742 self.assertEqual(None, exc.__context__)
743 self.assertEqual(False, exc.__suppress_context__)
744 self.assertEqual(expected_stack, exc.stack)
745 self.assertEqual(exc_info[0], exc.exc_type)
746 self.assertEqual(str(exc_info[1]), str(exc))
747
748 def test_from_exception(self):
749 # Check all the parameters are accepted.
750 def foo():
751 1/0
752 try:
753 foo()
754 except Exception as e:
755 exc_info = sys.exc_info()
756 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300757 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
758 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300759 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300760 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300761 expected_stack = self.expected_stack
762 exc = self.exc
763 self.assertEqual(None, exc.__cause__)
764 self.assertEqual(None, exc.__context__)
765 self.assertEqual(False, exc.__suppress_context__)
766 self.assertEqual(expected_stack, exc.stack)
767 self.assertEqual(exc_info[0], exc.exc_type)
768 self.assertEqual(str(exc_info[1]), str(exc))
769
770 def test_cause(self):
771 try:
772 try:
773 1/0
774 finally:
775 exc_info_context = sys.exc_info()
776 exc_context = traceback.TracebackException(*exc_info_context)
777 cause = Exception("cause")
778 raise Exception("uh oh") from cause
779 except Exception:
780 exc_info = sys.exc_info()
781 exc = traceback.TracebackException(*exc_info)
782 expected_stack = traceback.StackSummary.extract(
783 traceback.walk_tb(exc_info[2]))
784 exc_cause = traceback.TracebackException(Exception, cause, None)
785 self.assertEqual(exc_cause, exc.__cause__)
786 self.assertEqual(exc_context, exc.__context__)
787 self.assertEqual(True, exc.__suppress_context__)
788 self.assertEqual(expected_stack, exc.stack)
789 self.assertEqual(exc_info[0], exc.exc_type)
790 self.assertEqual(str(exc_info[1]), str(exc))
791
792 def test_context(self):
793 try:
794 try:
795 1/0
796 finally:
797 exc_info_context = sys.exc_info()
798 exc_context = traceback.TracebackException(*exc_info_context)
799 raise Exception("uh oh")
800 except Exception:
801 exc_info = sys.exc_info()
802 exc = traceback.TracebackException(*exc_info)
803 expected_stack = traceback.StackSummary.extract(
804 traceback.walk_tb(exc_info[2]))
805 self.assertEqual(None, exc.__cause__)
806 self.assertEqual(exc_context, exc.__context__)
807 self.assertEqual(False, exc.__suppress_context__)
808 self.assertEqual(expected_stack, exc.stack)
809 self.assertEqual(exc_info[0], exc.exc_type)
810 self.assertEqual(str(exc_info[1]), str(exc))
811
812 def test_limit(self):
813 def recurse(n):
814 if n:
815 recurse(n-1)
816 else:
817 1/0
818 try:
819 recurse(10)
820 except Exception:
821 exc_info = sys.exc_info()
822 exc = traceback.TracebackException(*exc_info, limit=5)
823 expected_stack = traceback.StackSummary.extract(
824 traceback.walk_tb(exc_info[2]), limit=5)
825 self.assertEqual(expected_stack, exc.stack)
826
827 def test_lookup_lines(self):
828 linecache.clearcache()
829 e = Exception("uh oh")
830 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300831 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300832 tb = test_tb(f, 6, None)
833 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
834 self.assertEqual({}, linecache.cache)
835 linecache.updatecache('/foo.py', globals())
836 self.assertEqual(exc.stack[0].line, "import sys")
837
Robert Collinsd7c7e0e2015-03-05 20:28:52 +1300838 def test_locals(self):
839 linecache.updatecache('/foo.py', globals())
840 e = Exception("uh oh")
841 c = test_code('/foo.py', 'method')
842 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
843 tb = test_tb(f, 6, None)
844 exc = traceback.TracebackException(
845 Exception, e, tb, capture_locals=True)
846 self.assertEqual(
847 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
848
849 def test_no_locals(self):
850 linecache.updatecache('/foo.py', globals())
851 e = Exception("uh oh")
852 c = test_code('/foo.py', 'method')
853 f = test_frame(c, globals(), {'something': 1})
854 tb = test_tb(f, 6, None)
855 exc = traceback.TracebackException(Exception, e, tb)
856 self.assertEqual(exc.stack[0].locals, None)
857
Berker Peksagc3f417d2015-07-24 17:36:21 +0300858 def test_traceback_header(self):
859 # do not print a traceback header if exc_traceback is None
860 # see issue #24695
861 exc = traceback.TracebackException(Exception, Exception("haven"), None)
862 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
863
Robert Collins6bc2c1e2015-03-05 12:07:57 +1300864
Berker Peksag716b3d32015-04-08 09:47:14 +0300865class MiscTest(unittest.TestCase):
866
867 def test_all(self):
868 expected = set()
869 blacklist = {'print_list'}
870 for name in dir(traceback):
871 if name.startswith('_') or name in blacklist:
872 continue
873 module_object = getattr(traceback, name)
874 if getattr(module_object, '__module__', None) == 'traceback':
875 expected.add(name)
876 self.assertCountEqual(traceback.__all__, expected)
877
Fred Drake2e2be372001-09-20 21:33:42 +0000878
879if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +0300880 unittest.main()