blob: 18cd4aba24af260fc6a10398de4fabb388e9e084 [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
Miss Islington (bot)eb0a6802021-06-17 09:41:46 -07007import inspect
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +00008import unittest
Benjamin Petersone6528212008-07-15 15:32:09 +00009import re
Serhiy Storchaka24559e42015-05-03 13:19:46 +030010from test import support
Hai Shideb01622020-07-06 20:29:49 +080011from test.support import Error, captured_output, cpython_only, ALWAYS_EQ
12from test.support.os_helper import TESTFN, unlink
Berker Peksagce643912015-05-06 06:33:17 +030013from test.support.script_helper import assert_python_ok
Victor Stinner9d279b82014-12-05 10:18:30 +010014import textwrap
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000015
16import traceback
17
Christian Heimes81ee3ef2008-05-04 22:42:01 +000018
Robert Collins6bc2c1e2015-03-05 12:07:57 +130019test_code = namedtuple('code', ['co_filename', 'co_name'])
Robert Collinsd7c7e0e2015-03-05 20:28:52 +130020test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
Robert Collins6bc2c1e2015-03-05 12:07:57 +130021test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next'])
22
23
Martin Panterbb8b1cb2016-09-22 09:37:39 +000024class TracebackCases(unittest.TestCase):
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000025 # For now, a very minimal set of tests. I want to be sure that
26 # formatting of SyntaxErrors works based on changes for 2.1.
27
28 def get_exception_format(self, func, exc):
29 try:
30 func()
Guido van Rossumb940e112007-01-10 16:19:56 +000031 except exc as value:
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000032 return traceback.format_exception_only(exc, value)
33 else:
Collin Winter3add4d72007-08-29 23:37:32 +000034 raise ValueError("call did not raise exception")
Tim Peters7e01e282001-04-08 07:44:07 +000035
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000036 def syntax_error_with_caret(self):
37 compile("def fact(x):\n\treturn x!\n", "?", "exec")
38
Georg Brandl751899a2009-06-04 19:41:00 +000039 def syntax_error_with_caret_2(self):
40 compile("1 +\n", "?", "exec")
41
Miss Islington (bot)c7fdd682021-09-27 14:26:39 -070042 def syntax_error_with_caret_range(self):
43 compile("f(x, y for y in range(30), z)", "?", "exec")
44
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000045 def syntax_error_bad_indentation(self):
Georg Brandl88fc6642007-02-09 21:28:07 +000046 compile("def spam():\n print(1)\n print(2)", "?", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000047
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020048 def syntax_error_with_caret_non_ascii(self):
49 compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec")
50
Florent Xicluna758fa5e2014-01-22 01:11:43 +010051 def syntax_error_bad_indentation2(self):
52 compile(" print(2)", "?", "exec")
53
Miss Islington (bot)5df35fa2021-10-16 10:51:05 -070054 def tokenizer_error_with_caret_range(self):
55 compile("blech ( ", "?", "exec")
56
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000057 def test_caret(self):
58 err = self.get_exception_format(self.syntax_error_with_caret,
59 SyntaxError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000060 self.assertEqual(len(err), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000061 self.assertTrue(err[1].strip() == "return x!")
Benjamin Peterson577473f2010-01-19 00:09:57 +000062 self.assertIn("^", err[2]) # third line has caret
Guido van Rossume61fd5b2007-07-11 12:20:59 +000063 self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place
Miss Islington (bot)c7fdd682021-09-27 14:26:39 -070064 self.assertEqual(err[2].count("^"), 1)
Tim Peters7e01e282001-04-08 07:44:07 +000065
Georg Brandl751899a2009-06-04 19:41:00 +000066 err = self.get_exception_format(self.syntax_error_with_caret_2,
67 SyntaxError)
Benjamin Peterson577473f2010-01-19 00:09:57 +000068 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010069 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
Guido van Rossum15bc9ab2020-05-14 19:22:48 -070070 self.assertEqual(err[1].find("+") + 1, err[2].find("^")) # in the right place
Miss Islington (bot)c7fdd682021-09-27 14:26:39 -070071 self.assertEqual(err[2].count("^"), 1)
Georg Brandl751899a2009-06-04 19:41:00 +000072
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020073 err = self.get_exception_format(self.syntax_error_with_caret_non_ascii,
74 SyntaxError)
75 self.assertIn("^", err[2]) # third line has caret
Florent Xicluna758fa5e2014-01-22 01:11:43 +010076 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
Guido van Rossum15bc9ab2020-05-14 19:22:48 -070077 self.assertEqual(err[1].find("+") + 1, err[2].find("^")) # in the right place
Miss Islington (bot)c7fdd682021-09-27 14:26:39 -070078 self.assertEqual(err[2].count("^"), 1)
79
80 err = self.get_exception_format(self.syntax_error_with_caret_range,
81 SyntaxError)
82 self.assertIn("^", err[2]) # third line has caret
83 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
84 self.assertEqual(err[1].find("y"), err[2].find("^")) # in the right place
85 self.assertEqual(err[2].count("^"), len("y for y in range(30)"))
Serhiy Storchaka65fd0592014-01-21 22:26:52 +020086
Miss Islington (bot)5df35fa2021-10-16 10:51:05 -070087 err = self.get_exception_format(self.tokenizer_error_with_caret_range,
88 SyntaxError)
89 self.assertIn("^", err[2]) # third line has caret
90 self.assertEqual(err[2].count('\n'), 1) # and no additional newline
91 self.assertEqual(err[1].find("("), err[2].find("^")) # in the right place
92 self.assertEqual(err[2].count("^"), 1)
93
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000094 def test_nocaret(self):
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000095 exc = SyntaxError("error", ("x.py", 23, None, "bad syntax"))
96 err = traceback.format_exception_only(SyntaxError, exc)
Guido van Rossume61fd5b2007-07-11 12:20:59 +000097 self.assertEqual(len(err), 3)
Benjamin Peterson26d64ae2010-09-20 21:47:37 +000098 self.assertEqual(err[1].strip(), "bad syntax")
Jeremy Hylton09ccc3a2001-03-21 20:33:04 +000099
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000100 def test_bad_indentation(self):
101 err = self.get_exception_format(self.syntax_error_bad_indentation,
102 IndentationError)
Guido van Rossume61fd5b2007-07-11 12:20:59 +0000103 self.assertEqual(len(err), 4)
104 self.assertEqual(err[1].strip(), "print(2)")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000105 self.assertIn("^", err[2])
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700106 self.assertEqual(err[1].find(")") + 1, err[2].find("^"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000107
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700108 # No caret for "unexpected indent"
Florent Xicluna758fa5e2014-01-22 01:11:43 +0100109 err = self.get_exception_format(self.syntax_error_bad_indentation2,
110 IndentationError)
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700111 self.assertEqual(len(err), 3)
Florent Xicluna758fa5e2014-01-22 01:11:43 +0100112 self.assertEqual(err[1].strip(), "print(2)")
Florent Xicluna758fa5e2014-01-22 01:11:43 +0100113
Thomas Wouters477c8d52006-05-27 19:21:47 +0000114 def test_base_exception(self):
115 # Test that exceptions derived from BaseException are formatted right
116 e = KeyboardInterrupt()
117 lst = traceback.format_exception_only(e.__class__, e)
118 self.assertEqual(lst, ['KeyboardInterrupt\n'])
119
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000120 def test_format_exception_only_bad__str__(self):
121 class X(Exception):
122 def __str__(self):
123 1/0
124 err = traceback.format_exception_only(X, X())
125 self.assertEqual(len(err), 1)
126 str_value = '<unprintable %s object>' % X.__name__
Georg Brandl1a3284e2007-12-02 09:40:06 +0000127 if X.__module__ in ('__main__', 'builtins'):
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300128 str_name = X.__qualname__
Brett Cannon44c52612007-02-27 00:12:43 +0000129 else:
Serhiy Storchaka521e5862014-07-22 15:00:37 +0300130 str_name = '.'.join([X.__module__, X.__qualname__])
Brett Cannon44c52612007-02-27 00:12:43 +0000131 self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000132
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000133 def test_encoded_file(self):
134 # Test that tracebacks are correctly printed for encoded source files:
135 # - correct line number (Issue2384)
136 # - respect file encoding (Issue3975)
Srinivas Thatiparthy (శ్రీనివాస్ తాటిపర్తి)90d0cfb2018-11-16 21:02:58 +0530137 import sys, subprocess
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000138
139 # The spawned subprocess has its stdout redirected to a PIPE, and its
140 # encoding may be different from the current interpreter, on Windows
141 # at least.
142 process = subprocess.Popen([sys.executable, "-c",
143 "import sys; print(sys.stdout.encoding)"],
144 stdout=subprocess.PIPE,
145 stderr=subprocess.STDOUT)
146 stdout, stderr = process.communicate()
147 output_encoding = str(stdout, 'ascii').splitlines()[0]
148
149 def do_test(firstlines, message, charset, lineno):
150 # Raise the message in a subprocess, and catch the output
151 try:
Victor Stinner51d8c522016-02-08 17:57:02 +0100152 with open(TESTFN, "w", encoding=charset) as output:
153 output.write("""{0}if 1:
154 import traceback;
155 raise RuntimeError('{1}')
156 """.format(firstlines, message))
157
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000158 process = subprocess.Popen([sys.executable, TESTFN],
159 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
160 stdout, stderr = process.communicate()
161 stdout = stdout.decode(output_encoding).splitlines()
162 finally:
163 unlink(TESTFN)
164
165 # The source lines are encoded with the 'backslashreplace' handler
166 encoded_message = message.encode(output_encoding,
167 'backslashreplace')
168 # and we just decoded them with the output_encoding.
169 message_ascii = encoded_message.decode(output_encoding)
170
171 err_line = "raise RuntimeError('{0}')".format(message_ascii)
172 err_msg = "RuntimeError: {0}".format(message_ascii)
173
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000174 self.assertIn(("line %s" % lineno), stdout[1],
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000175 "Invalid line number: {0!r} instead of {1}".format(
176 stdout[1], lineno))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000177 self.assertTrue(stdout[2].endswith(err_line),
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000178 "Invalid traceback line: {0!r} instead of {1!r}".format(
179 stdout[2], err_line))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000180 self.assertTrue(stdout[3] == err_msg,
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000181 "Invalid error message: {0!r} instead of {1!r}".format(
182 stdout[3], err_msg))
183
184 do_test("", "foo", "ascii", 3)
185 for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"):
186 if charset == "ascii":
187 text = "foo"
188 elif charset == "GBK":
189 text = "\u4E02\u5100"
190 else:
191 text = "h\xe9 ho"
192 do_test("# coding: {0}\n".format(charset),
193 text, charset, 4)
194 do_test("#!shebang\n# coding: {0}\n".format(charset),
195 text, charset, 5)
Serhiy Storchaka1064a132014-01-09 20:12:49 +0200196 do_test(" \t\f\n# coding: {0}\n".format(charset),
197 text, charset, 5)
Martin Panter614827c2016-04-19 04:05:59 +0000198 # Issue #18960: coding spec should have no effect
Victor Stinner51d8c522016-02-08 17:57:02 +0100199 do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
Amaury Forgeot d'Arccf8016a2008-10-09 23:37:48 +0000200
Victor Stinner9d279b82014-12-05 10:18:30 +0100201 def test_print_traceback_at_exit(self):
202 # Issue #22599: Ensure that it is possible to use the traceback module
203 # to display an exception at Python exit
204 code = textwrap.dedent("""
205 import sys
206 import traceback
207
208 class PrintExceptionAtExit(object):
209 def __init__(self):
210 try:
211 x = 1 / 0
212 except Exception:
213 self.exc_info = sys.exc_info()
214 # self.exc_info[1] (traceback) contains frames:
215 # explicitly clear the reference to self in the current
216 # frame to break a reference cycle
217 self = None
218
219 def __del__(self):
220 traceback.print_exception(*self.exc_info)
221
222 # Keep a reference in the module namespace to call the destructor
223 # when the module is unloaded
224 obj = PrintExceptionAtExit()
225 """)
226 rc, stdout, stderr = assert_python_ok('-c', code)
227 expected = [b'Traceback (most recent call last):',
228 b' File "<string>", line 8, in __init__',
229 b'ZeroDivisionError: division by zero']
230 self.assertEqual(stderr.splitlines(), expected)
231
Berker Peksagc3f417d2015-07-24 17:36:21 +0300232 def test_print_exception(self):
233 output = StringIO()
234 traceback.print_exception(
235 Exception, Exception("projector"), None, file=output
236 )
237 self.assertEqual(output.getvalue(), "Exception: projector\n")
238
Zackery Spytz91e93792020-11-05 15:18:44 -0700239 def test_print_exception_exc(self):
240 output = StringIO()
241 traceback.print_exception(Exception("projector"), file=output)
242 self.assertEqual(output.getvalue(), "Exception: projector\n")
243
244 def test_format_exception_exc(self):
245 e = Exception("projector")
246 output = traceback.format_exception(e)
247 self.assertEqual(output, ["Exception: projector\n"])
248 with self.assertRaisesRegex(ValueError, 'Both or neither'):
249 traceback.format_exception(e.__class__, e)
250 with self.assertRaisesRegex(ValueError, 'Both or neither'):
251 traceback.format_exception(e.__class__, tb=e.__traceback__)
252 with self.assertRaisesRegex(TypeError, 'positional-only'):
253 traceback.format_exception(exc=e)
254
255 def test_format_exception_only_exc(self):
256 output = traceback.format_exception_only(Exception("projector"))
257 self.assertEqual(output, ["Exception: projector\n"])
258
Irit Katriel26f18b82021-02-23 14:58:47 +0000259 def test_exception_is_None(self):
260 NONE_EXC_STRING = 'NoneType: None\n'
261 excfile = StringIO()
Irit Katrielb798ab02021-02-23 17:43:04 +0000262 traceback.print_exception(None, file=excfile)
263 self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
264
265 excfile = StringIO()
Irit Katriel26f18b82021-02-23 14:58:47 +0000266 traceback.print_exception(None, None, None, file=excfile)
267 self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
268
269 excfile = StringIO()
270 traceback.print_exc(None, file=excfile)
271 self.assertEqual(excfile.getvalue(), NONE_EXC_STRING)
272
273 self.assertEqual(traceback.format_exc(None), NONE_EXC_STRING)
Irit Katrielb798ab02021-02-23 17:43:04 +0000274 self.assertEqual(traceback.format_exception(None), [NONE_EXC_STRING])
Irit Katriel26f18b82021-02-23 14:58:47 +0000275 self.assertEqual(
276 traceback.format_exception(None, None, None), [NONE_EXC_STRING])
277 self.assertEqual(
278 traceback.format_exception_only(None), [NONE_EXC_STRING])
279 self.assertEqual(
280 traceback.format_exception_only(None, None), [NONE_EXC_STRING])
281
Miss Islington (bot)eb0a6802021-06-17 09:41:46 -0700282 def test_signatures(self):
283 self.assertEqual(
284 str(inspect.signature(traceback.print_exception)),
285 ('(exc, /, value=<implicit>, tb=<implicit>, '
286 'limit=None, file=None, chain=True)'))
287
288 self.assertEqual(
289 str(inspect.signature(traceback.format_exception)),
290 ('(exc, /, value=<implicit>, tb=<implicit>, limit=None, '
291 'chain=True)'))
292
293 self.assertEqual(
294 str(inspect.signature(traceback.format_exception_only)),
295 '(exc, /, value=<implicit>)')
296
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000297
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000298class TracebackFormatTests(unittest.TestCase):
299
Antoine Pitrou58720d62013-08-05 23:26:40 +0200300 def some_exception(self):
301 raise KeyError('blah')
302
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200303 @cpython_only
Antoine Pitrou58720d62013-08-05 23:26:40 +0200304 def check_traceback_format(self, cleanup_func=None):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200305 from _testcapi import traceback_print
Georg Brandl236f7972009-04-05 14:28:42 +0000306 try:
Antoine Pitrou58720d62013-08-05 23:26:40 +0200307 self.some_exception()
Georg Brandl236f7972009-04-05 14:28:42 +0000308 except KeyError:
309 type_, value, tb = sys.exc_info()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200310 if cleanup_func is not None:
311 # Clear the inner frames, not this one
312 cleanup_func(tb.tb_next)
Georg Brandl236f7972009-04-05 14:28:42 +0000313 traceback_fmt = 'Traceback (most recent call last):\n' + \
314 ''.join(traceback.format_tb(tb))
315 file_ = StringIO()
316 traceback_print(tb, file_)
317 python_fmt = file_.getvalue()
Benjamin Petersond9fec152013-04-29 16:09:39 -0400318 # Call all _tb and _exc functions
319 with captured_output("stderr") as tbstderr:
320 traceback.print_tb(tb)
321 tbfile = StringIO()
322 traceback.print_tb(tb, file=tbfile)
323 with captured_output("stderr") as excstderr:
324 traceback.print_exc()
325 excfmt = traceback.format_exc()
326 excfile = StringIO()
327 traceback.print_exc(file=excfile)
Georg Brandl236f7972009-04-05 14:28:42 +0000328 else:
329 raise Error("unable to create test traceback string")
330
331 # Make sure that Python and the traceback module format the same thing
Ezio Melottib3aedd42010-11-20 19:04:17 +0000332 self.assertEqual(traceback_fmt, python_fmt)
Benjamin Petersond9fec152013-04-29 16:09:39 -0400333 # Now verify the _tb func output
334 self.assertEqual(tbstderr.getvalue(), tbfile.getvalue())
335 # Now verify the _exc func output
336 self.assertEqual(excstderr.getvalue(), excfile.getvalue())
337 self.assertEqual(excfmt, excfile.getvalue())
Georg Brandl236f7972009-04-05 14:28:42 +0000338
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000339 # Make sure that the traceback is properly indented.
Georg Brandl236f7972009-04-05 14:28:42 +0000340 tb_lines = python_fmt.splitlines()
Antoine Pitrou58720d62013-08-05 23:26:40 +0200341 self.assertEqual(len(tb_lines), 5)
342 banner = tb_lines[0]
343 location, source_line = tb_lines[-2:]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000344 self.assertTrue(banner.startswith('Traceback'))
345 self.assertTrue(location.startswith(' File'))
346 self.assertTrue(source_line.startswith(' raise'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000347
Antoine Pitrou58720d62013-08-05 23:26:40 +0200348 def test_traceback_format(self):
349 self.check_traceback_format()
350
351 def test_traceback_format_with_cleared_frames(self):
352 # Check that traceback formatting also works with a clear()ed frame
353 def cleanup_tb(tb):
354 tb.tb_frame.clear()
355 self.check_traceback_format(cleanup_tb)
356
Benjamin Petersond9fec152013-04-29 16:09:39 -0400357 def test_stack_format(self):
358 # Verify _stack functions. Note we have to use _getframe(1) to
359 # compare them without this frame appearing in the output
360 with captured_output("stderr") as ststderr:
361 traceback.print_stack(sys._getframe(1))
362 stfile = StringIO()
363 traceback.print_stack(sys._getframe(1), file=stfile)
364 self.assertEqual(ststderr.getvalue(), stfile.getvalue())
365
366 stfmt = traceback.format_stack(sys._getframe(1))
367
368 self.assertEqual(ststderr.getvalue(), "".join(stfmt))
369
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300370 def test_print_stack(self):
371 def prn():
372 traceback.print_stack()
373 with captured_output("stderr") as stderr:
374 prn()
375 lineno = prn.__code__.co_firstlineno
376 self.assertEqual(stderr.getvalue().splitlines()[-4:], [
377 ' File "%s", line %d, in test_print_stack' % (__file__, lineno+3),
378 ' prn()',
379 ' File "%s", line %d, in prn' % (__file__, lineno+1),
380 ' traceback.print_stack()',
381 ])
382
Nick Coghland0034232016-08-15 13:11:34 +1000383 # issue 26823 - Shrink recursive tracebacks
384 def _check_recursive_traceback_display(self, render_exc):
385 # Always show full diffs when this test fails
386 # Note that rearranging things may require adjusting
387 # the relative line numbers in the expected tracebacks
388 self.maxDiff = None
389
390 # Check hitting the recursion limit
391 def f():
392 f()
393
394 with captured_output("stderr") as stderr_f:
395 try:
396 f()
Pablo Galindo293dd232019-11-19 21:34:03 +0000397 except RecursionError:
Nick Coghland0034232016-08-15 13:11:34 +1000398 render_exc()
399 else:
400 self.fail("no recursion occurred")
401
402 lineno_f = f.__code__.co_firstlineno
403 result_f = (
404 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400405 f' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000406 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400407 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000408 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400409 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000410 ' f()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400411 f' File "{__file__}", line {lineno_f+1}, in f\n'
Nick Coghland0034232016-08-15 13:11:34 +1000412 ' f()\n'
413 # XXX: The following line changes depending on whether the tests
414 # are run through the interactive interpreter or with -m
415 # It also varies depending on the platform (stack size)
416 # Fortunately, we don't care about exactness here, so we use regex
417 r' \[Previous line repeated (\d+) more times\]' '\n'
418 'RecursionError: maximum recursion depth exceeded\n'
419 )
420
421 expected = result_f.splitlines()
422 actual = stderr_f.getvalue().splitlines()
423
424 # Check the output text matches expectations
425 # 2nd last line contains the repetition count
426 self.assertEqual(actual[:-2], expected[:-2])
427 self.assertRegex(actual[-2], expected[-2])
codedragon3480ef92017-05-24 14:23:46 -0700428 # last line can have additional text appended
429 self.assertIn(expected[-1], actual[-1])
Nick Coghland0034232016-08-15 13:11:34 +1000430
431 # Check the recursion count is roughly as expected
432 rec_limit = sys.getrecursionlimit()
Serhiy Storchakab7281052016-09-12 00:52:40 +0300433 self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
Nick Coghland0034232016-08-15 13:11:34 +1000434
435 # Check a known (limited) number of recursive invocations
436 def g(count=10):
437 if count:
438 return g(count-1)
439 raise ValueError
440
441 with captured_output("stderr") as stderr_g:
442 try:
443 g()
Pablo Galindo293dd232019-11-19 21:34:03 +0000444 except ValueError:
Nick Coghland0034232016-08-15 13:11:34 +1000445 render_exc()
446 else:
447 self.fail("no value error was raised")
448
449 lineno_g = g.__code__.co_firstlineno
450 result_g = (
Eric V. Smith451d0e32016-09-09 21:56:20 -0400451 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000452 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400453 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000454 ' return g(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400455 f' File "{__file__}", line {lineno_g+2}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000456 ' return g(count-1)\n'
Benjamin Petersond5458692018-09-10 08:43:10 -0700457 ' [Previous line repeated 7 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400458 f' File "{__file__}", line {lineno_g+3}, in g\n'
Nick Coghland0034232016-08-15 13:11:34 +1000459 ' raise ValueError\n'
460 'ValueError\n'
461 )
462 tb_line = (
463 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400464 f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000465 ' g()\n'
466 )
467 expected = (tb_line + result_g).splitlines()
468 actual = stderr_g.getvalue().splitlines()
469 self.assertEqual(actual, expected)
470
471 # Check 2 different repetitive sections
472 def h(count=10):
473 if count:
474 return h(count-1)
475 g()
476
477 with captured_output("stderr") as stderr_h:
478 try:
479 h()
Pablo Galindo293dd232019-11-19 21:34:03 +0000480 except ValueError:
Nick Coghland0034232016-08-15 13:11:34 +1000481 render_exc()
482 else:
483 self.fail("no value error was raised")
484
485 lineno_h = h.__code__.co_firstlineno
486 result_h = (
487 'Traceback (most recent call last):\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400488 f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display\n'
Nick Coghland0034232016-08-15 13:11:34 +1000489 ' h()\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400490 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000491 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400492 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000493 ' return h(count-1)\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400494 f' File "{__file__}", line {lineno_h+2}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000495 ' return h(count-1)\n'
Benjamin Petersond5458692018-09-10 08:43:10 -0700496 ' [Previous line repeated 7 more times]\n'
Eric V. Smith451d0e32016-09-09 21:56:20 -0400497 f' File "{__file__}", line {lineno_h+3}, in h\n'
Nick Coghland0034232016-08-15 13:11:34 +1000498 ' g()\n'
499 )
500 expected = (result_h + result_g).splitlines()
501 actual = stderr_h.getvalue().splitlines()
502 self.assertEqual(actual, expected)
503
Benjamin Petersond5458692018-09-10 08:43:10 -0700504 # Check the boundary conditions. First, test just below the cutoff.
505 with captured_output("stderr") as stderr_g:
506 try:
507 g(traceback._RECURSIVE_CUTOFF)
Pablo Galindo293dd232019-11-19 21:34:03 +0000508 except ValueError:
Benjamin Petersond5458692018-09-10 08:43:10 -0700509 render_exc()
510 else:
511 self.fail("no error raised")
512 result_g = (
513 f' File "{__file__}", line {lineno_g+2}, in g\n'
514 ' return g(count-1)\n'
515 f' File "{__file__}", line {lineno_g+2}, in g\n'
516 ' return g(count-1)\n'
517 f' File "{__file__}", line {lineno_g+2}, in g\n'
518 ' return g(count-1)\n'
519 f' File "{__file__}", line {lineno_g+3}, in g\n'
520 ' raise ValueError\n'
521 'ValueError\n'
522 )
523 tb_line = (
524 'Traceback (most recent call last):\n'
525 f' File "{__file__}", line {lineno_g+71}, in _check_recursive_traceback_display\n'
526 ' g(traceback._RECURSIVE_CUTOFF)\n'
527 )
528 expected = (tb_line + result_g).splitlines()
529 actual = stderr_g.getvalue().splitlines()
530 self.assertEqual(actual, expected)
531
532 # Second, test just above the cutoff.
533 with captured_output("stderr") as stderr_g:
534 try:
535 g(traceback._RECURSIVE_CUTOFF + 1)
Pablo Galindo293dd232019-11-19 21:34:03 +0000536 except ValueError:
Benjamin Petersond5458692018-09-10 08:43:10 -0700537 render_exc()
538 else:
539 self.fail("no error raised")
540 result_g = (
541 f' File "{__file__}", line {lineno_g+2}, in g\n'
542 ' return g(count-1)\n'
543 f' File "{__file__}", line {lineno_g+2}, in g\n'
544 ' return g(count-1)\n'
545 f' File "{__file__}", line {lineno_g+2}, in g\n'
546 ' return g(count-1)\n'
547 ' [Previous line repeated 1 more time]\n'
548 f' File "{__file__}", line {lineno_g+3}, in g\n'
549 ' raise ValueError\n'
550 'ValueError\n'
551 )
552 tb_line = (
553 'Traceback (most recent call last):\n'
554 f' File "{__file__}", line {lineno_g+99}, in _check_recursive_traceback_display\n'
555 ' g(traceback._RECURSIVE_CUTOFF + 1)\n'
556 )
557 expected = (tb_line + result_g).splitlines()
558 actual = stderr_g.getvalue().splitlines()
559 self.assertEqual(actual, expected)
560
Nick Coghland0034232016-08-15 13:11:34 +1000561 def test_recursive_traceback_python(self):
562 self._check_recursive_traceback_display(traceback.print_exc)
563
564 @cpython_only
565 def test_recursive_traceback_cpython_internal(self):
566 from _testcapi import exception_print
567 def render_exc():
568 exc_type, exc_value, exc_tb = sys.exc_info()
569 exception_print(exc_value)
570 self._check_recursive_traceback_display(render_exc)
571
Serhiy Storchakae953ba72015-09-18 10:04:47 +0300572 def test_format_stack(self):
573 def fmt():
574 return traceback.format_stack()
575 result = fmt()
576 lineno = fmt.__code__.co_firstlineno
577 self.assertEqual(result[-2:], [
578 ' File "%s", line %d, in test_format_stack\n'
579 ' result = fmt()\n' % (__file__, lineno+2),
580 ' File "%s", line %d, in fmt\n'
581 ' return traceback.format_stack()\n' % (__file__, lineno+1),
582 ])
583
Zane Bitterde860732017-10-17 17:29:39 -0400584 @cpython_only
585 def test_unhashable(self):
586 from _testcapi import exception_print
587
588 class UnhashableException(Exception):
589 def __eq__(self, other):
590 return True
591
592 ex1 = UnhashableException('ex1')
593 ex2 = UnhashableException('ex2')
594 try:
595 raise ex2 from ex1
596 except UnhashableException:
597 try:
598 raise ex1
599 except UnhashableException:
600 exc_type, exc_val, exc_tb = sys.exc_info()
601
602 with captured_output("stderr") as stderr_f:
603 exception_print(exc_val)
604
605 tb = stderr_f.getvalue().strip().splitlines()
606 self.assertEqual(11, len(tb))
607 self.assertEqual(context_message.strip(), tb[5])
608 self.assertIn('UnhashableException: ex2', tb[3])
609 self.assertIn('UnhashableException: ex1', tb[10])
610
Benjamin Petersone6528212008-07-15 15:32:09 +0000611
612cause_message = (
613 "\nThe above exception was the direct cause "
614 "of the following exception:\n\n")
615
616context_message = (
617 "\nDuring handling of the above exception, "
618 "another exception occurred:\n\n")
619
620boundaries = re.compile(
621 '(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
622
623
624class BaseExceptionReportingTests:
625
626 def get_exception(self, exception_or_callable):
627 if isinstance(exception_or_callable, Exception):
628 return exception_or_callable
629 try:
630 exception_or_callable()
631 except Exception as e:
632 return e
633
634 def zero_div(self):
635 1/0 # In zero_div
636
637 def check_zero_div(self, msg):
638 lines = msg.splitlines()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000639 self.assertTrue(lines[-3].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000640 self.assertIn('1/0 # In zero_div', lines[-2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000641 self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1])
Benjamin Petersone6528212008-07-15 15:32:09 +0000642
643 def test_simple(self):
644 try:
645 1/0 # Marker
646 except ZeroDivisionError as _:
647 e = _
648 lines = self.get_report(e).splitlines()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000649 self.assertEqual(len(lines), 4)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000650 self.assertTrue(lines[0].startswith('Traceback'))
651 self.assertTrue(lines[1].startswith(' File'))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000652 self.assertIn('1/0 # Marker', lines[2])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000653 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
Benjamin Petersone6528212008-07-15 15:32:09 +0000654
655 def test_cause(self):
656 def inner_raise():
657 try:
658 self.zero_div()
659 except ZeroDivisionError as e:
660 raise KeyError from e
661 def outer_raise():
662 inner_raise() # Marker
663 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000664 self.assertEqual(len(blocks), 3)
665 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000666 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000667 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000668
669 def test_context(self):
670 def inner_raise():
671 try:
672 self.zero_div()
673 except ZeroDivisionError:
674 raise KeyError
675 def outer_raise():
676 inner_raise() # Marker
677 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000678 self.assertEqual(len(blocks), 3)
679 self.assertEqual(blocks[1], context_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000680 self.check_zero_div(blocks[0])
Benjamin Peterson577473f2010-01-19 00:09:57 +0000681 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000682
Nick Coghlanab7bf212012-02-26 17:49:52 +1000683 def test_context_suppression(self):
684 try:
685 try:
686 raise Exception
687 except:
688 raise ZeroDivisionError from None
689 except ZeroDivisionError as _:
690 e = _
691 lines = self.get_report(e).splitlines()
692 self.assertEqual(len(lines), 4)
693 self.assertTrue(lines[0].startswith('Traceback'))
694 self.assertTrue(lines[1].startswith(' File'))
695 self.assertIn('ZeroDivisionError from None', lines[2])
696 self.assertTrue(lines[3].startswith('ZeroDivisionError'))
697
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000698 def test_cause_and_context(self):
699 # When both a cause and a context are set, only the cause should be
700 # displayed and the context should be muted.
701 def inner_raise():
702 try:
703 self.zero_div()
704 except ZeroDivisionError as _e:
705 e = _e
706 try:
707 xyzzy
708 except NameError:
709 raise KeyError from e
710 def outer_raise():
711 inner_raise() # Marker
712 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000713 self.assertEqual(len(blocks), 3)
714 self.assertEqual(blocks[1], cause_message)
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000715 self.check_zero_div(blocks[0])
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000716 self.assertIn('inner_raise() # Marker', blocks[2])
Antoine Pitrou7b0d4a22009-11-28 16:12:28 +0000717
Benjamin Petersone6528212008-07-15 15:32:09 +0000718 def test_cause_recursive(self):
719 def inner_raise():
720 try:
721 try:
722 self.zero_div()
723 except ZeroDivisionError as e:
724 z = e
725 raise KeyError from e
726 except KeyError as e:
727 raise z from e
728 def outer_raise():
729 inner_raise() # Marker
730 blocks = boundaries.split(self.get_report(outer_raise))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000731 self.assertEqual(len(blocks), 3)
732 self.assertEqual(blocks[1], cause_message)
Benjamin Petersone6528212008-07-15 15:32:09 +0000733 # The first block is the KeyError raised from the ZeroDivisionError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000734 self.assertIn('raise KeyError from e', blocks[0])
735 self.assertNotIn('1/0', blocks[0])
Benjamin Petersone6528212008-07-15 15:32:09 +0000736 # The second block (apart from the boundary) is the ZeroDivisionError
737 # re-raised from the KeyError
Benjamin Peterson577473f2010-01-19 00:09:57 +0000738 self.assertIn('inner_raise() # Marker', blocks[2])
Benjamin Petersone6528212008-07-15 15:32:09 +0000739 self.check_zero_div(blocks[2])
740
Benjamin Peterson503d6c52010-10-24 02:52:05 +0000741 def test_syntax_error_offset_at_eol(self):
742 # See #10186.
743 def e():
744 raise SyntaxError('', ('', 0, 5, 'hello'))
745 msg = self.get_report(e).splitlines()
746 self.assertEqual(msg[-2], " ^")
Benjamin Petersona95e9772010-10-29 03:28:14 +0000747 def e():
748 exec("x = 5 | 4 |")
749 msg = self.get_report(e).splitlines()
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700750 self.assertEqual(msg[-2], ' ^')
Benjamin Petersone6528212008-07-15 15:32:09 +0000751
Irit Katriel069560b2020-12-22 19:53:09 +0000752 def test_syntax_error_no_lineno(self):
753 # See #34463.
754
755 # Without filename
756 e = SyntaxError('bad syntax')
757 msg = self.get_report(e).splitlines()
758 self.assertEqual(msg,
759 ['SyntaxError: bad syntax'])
760 e.lineno = 100
761 msg = self.get_report(e).splitlines()
762 self.assertEqual(msg,
763 [' File "<string>", line 100', 'SyntaxError: bad syntax'])
764
765 # With filename
766 e = SyntaxError('bad syntax')
767 e.filename = 'myfile.py'
768
769 msg = self.get_report(e).splitlines()
770 self.assertEqual(msg,
771 ['SyntaxError: bad syntax (myfile.py)'])
772 e.lineno = 100
773 msg = self.get_report(e).splitlines()
774 self.assertEqual(msg,
775 [' File "myfile.py", line 100', 'SyntaxError: bad syntax'])
776
Martin Panterbb8b1cb2016-09-22 09:37:39 +0000777 def test_message_none(self):
778 # A message that looks like "None" should not be treated specially
779 err = self.get_report(Exception(None))
780 self.assertIn('Exception: None\n', err)
781 err = self.get_report(Exception('None'))
782 self.assertIn('Exception: None\n', err)
783 err = self.get_report(Exception())
784 self.assertIn('Exception\n', err)
785 err = self.get_report(Exception(''))
786 self.assertIn('Exception\n', err)
787
Irit Katriel4d2cc3e2021-11-29 10:07:24 +0000788 def test_exception_modulename_not_unicode(self):
789 class X(Exception):
790 def __str__(self):
791 return "I am X"
792
793 X.__module__ = 42
794
795 err = self.get_report(X())
796 exp = f'<unknown>.{X.__qualname__}: I am X\n'
797 self.assertEqual(exp, err)
798
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700799 def test_syntax_error_various_offsets(self):
800 for offset in range(-5, 10):
801 for add in [0, 2]:
802 text = " "*add + "text%d" % offset
803 expected = [' File "file.py", line 1']
804 if offset < 1:
805 expected.append(" %s" % text.lstrip())
806 elif offset <= 6:
807 expected.append(" %s" % text.lstrip())
808 expected.append(" %s^" % (" "*(offset-1)))
809 else:
810 expected.append(" %s" % text.lstrip())
811 expected.append(" %s^" % (" "*5))
812 expected.append("SyntaxError: msg")
813 expected.append("")
814 err = self.get_report(SyntaxError("msg", ("file.py", 1, offset+add, text)))
815 exp = "\n".join(expected)
816 self.assertEqual(exp, err)
817
Miss Islington (bot)6b996d62021-09-08 09:32:19 -0700818 def test_format_exception_only_qualname(self):
819 class A:
820 class B:
821 class X(Exception):
822 def __str__(self):
823 return "I am X"
824 pass
825 err = self.get_report(A.B.X())
826 str_value = 'I am X'
827 str_name = '.'.join([A.B.X.__module__, A.B.X.__qualname__])
828 exp = "%s: %s\n" % (str_name, str_value)
829 self.assertEqual(exp, err)
830
Benjamin Petersone6528212008-07-15 15:32:09 +0000831
832class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
833 #
834 # This checks reporting through the 'traceback' module, with both
835 # format_exception() and print_exception().
836 #
837
838 def get_report(self, e):
839 e = self.get_exception(e)
840 s = ''.join(
841 traceback.format_exception(type(e), e, e.__traceback__))
842 with captured_output("stderr") as sio:
843 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000844 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000845 return s
846
847
848class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
849 #
850 # This checks built-in reporting by the interpreter.
851 #
852
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200853 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000854 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200855 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000856 e = self.get_exception(e)
857 with captured_output("stderr") as s:
858 exception_print(e)
859 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000860
861
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300862class LimitTests(unittest.TestCase):
863
864 ''' Tests for limit argument.
865 It's enough to test extact_tb, extract_stack and format_exception '''
866
867 def last_raises1(self):
868 raise Exception('Last raised')
869
870 def last_raises2(self):
871 self.last_raises1()
872
873 def last_raises3(self):
874 self.last_raises2()
875
876 def last_raises4(self):
877 self.last_raises3()
878
879 def last_raises5(self):
880 self.last_raises4()
881
882 def last_returns_frame1(self):
883 return sys._getframe()
884
885 def last_returns_frame2(self):
886 return self.last_returns_frame1()
887
888 def last_returns_frame3(self):
889 return self.last_returns_frame2()
890
891 def last_returns_frame4(self):
892 return self.last_returns_frame3()
893
894 def last_returns_frame5(self):
895 return self.last_returns_frame4()
896
897 def test_extract_stack(self):
898 frame = self.last_returns_frame5()
899 def extract(**kwargs):
900 return traceback.extract_stack(frame, **kwargs)
901 def assertEqualExcept(actual, expected, ignore):
902 self.assertEqual(actual[:ignore], expected[:ignore])
903 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
904 self.assertEqual(len(actual), len(expected))
905
906 with support.swap_attr(sys, 'tracebacklimit', 1000):
907 nolim = extract()
908 self.assertGreater(len(nolim), 5)
909 self.assertEqual(extract(limit=2), nolim[-2:])
910 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
911 self.assertEqual(extract(limit=-2), nolim[:2])
912 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
913 self.assertEqual(extract(limit=0), [])
914 del sys.tracebacklimit
915 assertEqualExcept(extract(), nolim, -5-1)
916 sys.tracebacklimit = 2
917 self.assertEqual(extract(), nolim[-2:])
918 self.assertEqual(extract(limit=3), nolim[-3:])
919 self.assertEqual(extract(limit=-3), nolim[:3])
920 sys.tracebacklimit = 0
921 self.assertEqual(extract(), [])
922 sys.tracebacklimit = -1
923 self.assertEqual(extract(), [])
924
925 def test_extract_tb(self):
926 try:
927 self.last_raises5()
928 except Exception:
929 exc_type, exc_value, tb = sys.exc_info()
930 def extract(**kwargs):
931 return traceback.extract_tb(tb, **kwargs)
932
933 with support.swap_attr(sys, 'tracebacklimit', 1000):
934 nolim = extract()
935 self.assertEqual(len(nolim), 5+1)
936 self.assertEqual(extract(limit=2), nolim[:2])
937 self.assertEqual(extract(limit=10), nolim)
938 self.assertEqual(extract(limit=-2), nolim[-2:])
939 self.assertEqual(extract(limit=-10), nolim)
940 self.assertEqual(extract(limit=0), [])
941 del sys.tracebacklimit
942 self.assertEqual(extract(), nolim)
943 sys.tracebacklimit = 2
944 self.assertEqual(extract(), nolim[:2])
945 self.assertEqual(extract(limit=3), nolim[:3])
946 self.assertEqual(extract(limit=-3), nolim[-3:])
947 sys.tracebacklimit = 0
948 self.assertEqual(extract(), [])
949 sys.tracebacklimit = -1
950 self.assertEqual(extract(), [])
951
952 def test_format_exception(self):
953 try:
954 self.last_raises5()
955 except Exception:
956 exc_type, exc_value, tb = sys.exc_info()
957 # [1:-1] to exclude "Traceback (...)" header and
958 # exception type and value
959 def extract(**kwargs):
960 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
961
962 with support.swap_attr(sys, 'tracebacklimit', 1000):
963 nolim = extract()
964 self.assertEqual(len(nolim), 5+1)
965 self.assertEqual(extract(limit=2), nolim[:2])
966 self.assertEqual(extract(limit=10), nolim)
967 self.assertEqual(extract(limit=-2), nolim[-2:])
968 self.assertEqual(extract(limit=-10), nolim)
969 self.assertEqual(extract(limit=0), [])
970 del sys.tracebacklimit
971 self.assertEqual(extract(), nolim)
972 sys.tracebacklimit = 2
973 self.assertEqual(extract(), nolim[:2])
974 self.assertEqual(extract(limit=3), nolim[:3])
975 self.assertEqual(extract(limit=-3), nolim[-3:])
976 sys.tracebacklimit = 0
977 self.assertEqual(extract(), [])
978 sys.tracebacklimit = -1
979 self.assertEqual(extract(), [])
980
981
Andrew Kuchling173a1572013-09-15 18:15:56 -0400982class MiscTracebackCases(unittest.TestCase):
983 #
984 # Check non-printing functions in traceback module
985 #
986
987 def test_clear(self):
988 def outer():
989 middle()
990 def middle():
991 inner()
992 def inner():
993 i = 1
994 1/0
995
996 try:
997 outer()
998 except:
999 type_, value, tb = sys.exc_info()
1000
1001 # Initial assertion: there's one local in the inner frame.
1002 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
1003 self.assertEqual(len(inner_frame.f_locals), 1)
1004
1005 # Clear traceback frames
1006 traceback.clear_frames(tb)
1007
1008 # Local variable dict should now be empty.
1009 self.assertEqual(len(inner_frame.f_locals), 0)
1010
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001011 def test_extract_stack(self):
1012 def extract():
1013 return traceback.extract_stack()
1014 result = extract()
1015 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +03001016 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001017 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
1018 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
1019 ])
Berker Peksag9797b7a2018-09-10 20:02:33 +03001020 self.assertEqual(len(result[0]), 4)
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001021
Andrew Kuchling173a1572013-09-15 18:15:56 -04001022
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001023class TestFrame(unittest.TestCase):
1024
1025 def test_basics(self):
1026 linecache.clearcache()
1027 linecache.lazycache("f", globals())
1028 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +03001029 self.assertEqual(f,
1030 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
1031 self.assertEqual(tuple(f),
1032 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
1033 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
1034 self.assertEqual(f, tuple(f))
1035 # Since tuple.__eq__ doesn't support FrameSummary, the equality
1036 # operator fallbacks to FrameSummary.__eq__.
1037 self.assertEqual(tuple(f), f)
1038 self.assertIsNone(f.locals)
Serhiy Storchaka662db122019-08-08 08:42:54 +03001039 self.assertNotEqual(f, object())
1040 self.assertEqual(f, ALWAYS_EQ)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001041
1042 def test_lazy_lines(self):
1043 linecache.clearcache()
1044 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
1045 self.assertEqual(None, f._line)
1046 linecache.lazycache("f", globals())
1047 self.assertEqual(
1048 '"""Test cases for traceback module"""',
1049 f.line)
1050
Pablo Galindo61eb9b52021-07-08 17:47:12 +01001051 def test_no_line(self):
1052 f = traceback.FrameSummary("f", None, "dummy")
1053 self.assertEqual(f.line, None)
1054
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001055 def test_explicit_line(self):
1056 f = traceback.FrameSummary("f", 1, "dummy", line="line")
1057 self.assertEqual("line", f.line)
1058
Berker Peksag9797b7a2018-09-10 20:02:33 +03001059 def test_len(self):
1060 f = traceback.FrameSummary("f", 1, "dummy", line="line")
1061 self.assertEqual(len(f), 4)
1062
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001063
1064class TestStack(unittest.TestCase):
1065
1066 def test_walk_stack(self):
Serhiy Storchaka1c1130f2016-10-07 23:45:42 +03001067 def deeper():
1068 return list(traceback.walk_stack(None))
1069 s1 = list(traceback.walk_stack(None))
1070 s2 = deeper()
1071 self.assertEqual(len(s2) - len(s1), 1)
1072 self.assertEqual(s2[1:], s1)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001073
1074 def test_walk_tb(self):
1075 try:
1076 1/0
1077 except Exception:
1078 _, _, tb = sys.exc_info()
1079 s = list(traceback.walk_tb(tb))
1080 self.assertEqual(len(s), 1)
1081
1082 def test_extract_stack(self):
1083 s = traceback.StackSummary.extract(traceback.walk_stack(None))
1084 self.assertIsInstance(s, traceback.StackSummary)
1085
1086 def test_extract_stack_limit(self):
1087 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
1088 self.assertEqual(len(s), 5)
1089
1090 def test_extract_stack_lookup_lines(self):
1091 linecache.clearcache()
1092 linecache.updatecache('/foo.py', globals())
1093 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001094 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001095 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
1096 linecache.clearcache()
1097 self.assertEqual(s[0].line, "import sys")
1098
1099 def test_extract_stackup_deferred_lookup_lines(self):
1100 linecache.clearcache()
1101 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001102 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001103 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
1104 self.assertEqual({}, linecache.cache)
1105 linecache.updatecache('/foo.py', globals())
1106 self.assertEqual(s[0].line, "import sys")
1107
1108 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001109 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001110 self.assertEqual(
1111 [' File "foo.py", line 1, in fred\n line\n'],
1112 s.format())
1113
Robert Collinsbbb8ade2015-03-16 15:27:16 +13001114 def test_from_list_edited_stack(self):
1115 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
1116 s[0] = ('foo.py', 2, 'fred', 'line')
1117 s2 = traceback.StackSummary.from_list(s)
1118 self.assertEqual(
1119 [' File "foo.py", line 2, in fred\n line\n'],
1120 s2.format())
1121
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001122 def test_format_smoke(self):
1123 # For detailed tests see the format_list tests, which consume the same
1124 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001125 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001126 self.assertEqual(
1127 [' File "foo.py", line 1, in fred\n line\n'],
1128 s.format())
1129
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001130 def test_locals(self):
1131 linecache.updatecache('/foo.py', globals())
1132 c = test_code('/foo.py', 'method')
1133 f = test_frame(c, globals(), {'something': 1})
1134 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
1135 self.assertEqual(s[0].locals, {'something': '1'})
1136
1137 def test_no_locals(self):
1138 linecache.updatecache('/foo.py', globals())
1139 c = test_code('/foo.py', 'method')
1140 f = test_frame(c, globals(), {'something': 1})
1141 s = traceback.StackSummary.extract(iter([(f, 6)]))
1142 self.assertEqual(s[0].locals, None)
1143
1144 def test_format_locals(self):
1145 def some_inner(k, v):
1146 a = 1
1147 b = 2
1148 return traceback.StackSummary.extract(
1149 traceback.walk_stack(None), capture_locals=True, limit=1)
1150 s = some_inner(3, 4)
1151 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +03001152 [' File "%s", line %d, in some_inner\n'
Serhiy Storchakada8d72c2018-09-17 15:17:29 +03001153 ' return traceback.StackSummary.extract(\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001154 ' a = 1\n'
1155 ' b = 2\n'
1156 ' k = 3\n'
Serhiy Storchakada8d72c2018-09-17 15:17:29 +03001157 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 3)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001158 ], s.format())
1159
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001160class TestTracebackException(unittest.TestCase):
1161
1162 def test_smoke(self):
1163 try:
1164 1/0
1165 except Exception:
1166 exc_info = sys.exc_info()
1167 exc = traceback.TracebackException(*exc_info)
1168 expected_stack = traceback.StackSummary.extract(
1169 traceback.walk_tb(exc_info[2]))
1170 self.assertEqual(None, exc.__cause__)
1171 self.assertEqual(None, exc.__context__)
1172 self.assertEqual(False, exc.__suppress_context__)
1173 self.assertEqual(expected_stack, exc.stack)
1174 self.assertEqual(exc_info[0], exc.exc_type)
1175 self.assertEqual(str(exc_info[1]), str(exc))
1176
1177 def test_from_exception(self):
1178 # Check all the parameters are accepted.
1179 def foo():
1180 1/0
1181 try:
1182 foo()
1183 except Exception as e:
1184 exc_info = sys.exc_info()
1185 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001186 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
1187 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001188 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001189 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001190 expected_stack = self.expected_stack
1191 exc = self.exc
1192 self.assertEqual(None, exc.__cause__)
1193 self.assertEqual(None, exc.__context__)
1194 self.assertEqual(False, exc.__suppress_context__)
1195 self.assertEqual(expected_stack, exc.stack)
1196 self.assertEqual(exc_info[0], exc.exc_type)
1197 self.assertEqual(str(exc_info[1]), str(exc))
1198
1199 def test_cause(self):
1200 try:
1201 try:
1202 1/0
1203 finally:
1204 exc_info_context = sys.exc_info()
1205 exc_context = traceback.TracebackException(*exc_info_context)
1206 cause = Exception("cause")
1207 raise Exception("uh oh") from cause
1208 except Exception:
1209 exc_info = sys.exc_info()
1210 exc = traceback.TracebackException(*exc_info)
1211 expected_stack = traceback.StackSummary.extract(
1212 traceback.walk_tb(exc_info[2]))
1213 exc_cause = traceback.TracebackException(Exception, cause, None)
1214 self.assertEqual(exc_cause, exc.__cause__)
1215 self.assertEqual(exc_context, exc.__context__)
1216 self.assertEqual(True, exc.__suppress_context__)
1217 self.assertEqual(expected_stack, exc.stack)
1218 self.assertEqual(exc_info[0], exc.exc_type)
1219 self.assertEqual(str(exc_info[1]), str(exc))
1220
1221 def test_context(self):
1222 try:
1223 try:
1224 1/0
1225 finally:
1226 exc_info_context = sys.exc_info()
1227 exc_context = traceback.TracebackException(*exc_info_context)
1228 raise Exception("uh oh")
1229 except Exception:
1230 exc_info = sys.exc_info()
1231 exc = traceback.TracebackException(*exc_info)
1232 expected_stack = traceback.StackSummary.extract(
1233 traceback.walk_tb(exc_info[2]))
1234 self.assertEqual(None, exc.__cause__)
1235 self.assertEqual(exc_context, exc.__context__)
1236 self.assertEqual(False, exc.__suppress_context__)
1237 self.assertEqual(expected_stack, exc.stack)
1238 self.assertEqual(exc_info[0], exc.exc_type)
1239 self.assertEqual(str(exc_info[1]), str(exc))
1240
Irit Katriel6dfd1732021-01-12 22:14:27 +00001241 def test_long_context_chain(self):
1242 def f():
1243 try:
1244 1/0
1245 except:
1246 f()
1247
1248 try:
1249 f()
1250 except RecursionError:
1251 exc_info = sys.exc_info()
1252 else:
1253 self.fail("Exception not raised")
1254
1255 te = traceback.TracebackException(*exc_info)
1256 res = list(te.format())
1257
1258 # many ZeroDiv errors followed by the RecursionError
1259 self.assertGreater(len(res), sys.getrecursionlimit())
1260 self.assertGreater(
1261 len([l for l in res if 'ZeroDivisionError:' in l]),
1262 sys.getrecursionlimit() * 0.5)
1263 self.assertIn(
1264 "RecursionError: maximum recursion depth exceeded", res[-1])
1265
Irit Katriel4c94d742021-01-15 02:45:02 +00001266 def test_compact_with_cause(self):
1267 try:
1268 try:
1269 1/0
1270 finally:
1271 cause = Exception("cause")
1272 raise Exception("uh oh") from cause
1273 except Exception:
1274 exc_info = sys.exc_info()
1275 exc = traceback.TracebackException(*exc_info, compact=True)
1276 expected_stack = traceback.StackSummary.extract(
1277 traceback.walk_tb(exc_info[2]))
1278 exc_cause = traceback.TracebackException(Exception, cause, None)
1279 self.assertEqual(exc_cause, exc.__cause__)
1280 self.assertEqual(None, exc.__context__)
1281 self.assertEqual(True, exc.__suppress_context__)
1282 self.assertEqual(expected_stack, exc.stack)
1283 self.assertEqual(exc_info[0], exc.exc_type)
1284 self.assertEqual(str(exc_info[1]), str(exc))
1285
1286 def test_compact_no_cause(self):
1287 try:
1288 try:
1289 1/0
1290 finally:
1291 exc_info_context = sys.exc_info()
1292 exc_context = traceback.TracebackException(*exc_info_context)
1293 raise Exception("uh oh")
1294 except Exception:
1295 exc_info = sys.exc_info()
1296 exc = traceback.TracebackException(*exc_info, compact=True)
1297 expected_stack = traceback.StackSummary.extract(
1298 traceback.walk_tb(exc_info[2]))
1299 self.assertEqual(None, exc.__cause__)
1300 self.assertEqual(exc_context, exc.__context__)
1301 self.assertEqual(False, exc.__suppress_context__)
1302 self.assertEqual(expected_stack, exc.stack)
1303 self.assertEqual(exc_info[0], exc.exc_type)
1304 self.assertEqual(str(exc_info[1]), str(exc))
1305
Irit Katriel427613f2020-12-01 01:35:25 +00001306 def test_no_refs_to_exception_and_traceback_objects(self):
1307 try:
1308 1/0
1309 except Exception:
1310 exc_info = sys.exc_info()
1311
1312 refcnt1 = sys.getrefcount(exc_info[1])
1313 refcnt2 = sys.getrefcount(exc_info[2])
1314 exc = traceback.TracebackException(*exc_info)
1315 self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1)
1316 self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2)
1317
Irit Katriel44ca05a2020-11-27 16:38:54 +00001318 def test_comparison_basic(self):
Serhiy Storchaka662db122019-08-08 08:42:54 +03001319 try:
1320 1/0
1321 except Exception:
1322 exc_info = sys.exc_info()
1323 exc = traceback.TracebackException(*exc_info)
1324 exc2 = traceback.TracebackException(*exc_info)
1325 self.assertIsNot(exc, exc2)
1326 self.assertEqual(exc, exc2)
1327 self.assertNotEqual(exc, object())
1328 self.assertEqual(exc, ALWAYS_EQ)
1329
Irit Katriel44ca05a2020-11-27 16:38:54 +00001330 def test_comparison_params_variations(self):
1331 def raise_exc():
1332 try:
1333 raise ValueError('bad value')
1334 except:
1335 raise
1336
1337 def raise_with_locals():
1338 x, y = 1, 2
1339 raise_exc()
1340
1341 try:
1342 raise_with_locals()
1343 except Exception:
1344 exc_info = sys.exc_info()
1345
1346 exc = traceback.TracebackException(*exc_info)
1347 exc1 = traceback.TracebackException(*exc_info, limit=10)
1348 exc2 = traceback.TracebackException(*exc_info, limit=2)
1349
1350 self.assertEqual(exc, exc1) # limit=10 gets all frames
1351 self.assertNotEqual(exc, exc2) # limit=2 truncates the output
1352
1353 # locals change the output
1354 exc3 = traceback.TracebackException(*exc_info, capture_locals=True)
1355 self.assertNotEqual(exc, exc3)
1356
1357 # there are no locals in the innermost frame
1358 exc4 = traceback.TracebackException(*exc_info, limit=-1)
1359 exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True)
1360 self.assertEqual(exc4, exc5)
1361
1362 # there are locals in the next-to-innermost frame
1363 exc6 = traceback.TracebackException(*exc_info, limit=-2)
1364 exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True)
1365 self.assertNotEqual(exc6, exc7)
1366
Irit Katriel427613f2020-12-01 01:35:25 +00001367 def test_comparison_equivalent_exceptions_are_equal(self):
1368 excs = []
1369 for _ in range(2):
1370 try:
1371 1/0
1372 except:
1373 excs.append(traceback.TracebackException(*sys.exc_info()))
1374 self.assertEqual(excs[0], excs[1])
1375 self.assertEqual(list(excs[0].format()), list(excs[1].format()))
1376
Zane Bitterde860732017-10-17 17:29:39 -04001377 def test_unhashable(self):
1378 class UnhashableException(Exception):
1379 def __eq__(self, other):
1380 return True
1381
1382 ex1 = UnhashableException('ex1')
1383 ex2 = UnhashableException('ex2')
1384 try:
1385 raise ex2 from ex1
1386 except UnhashableException:
1387 try:
1388 raise ex1
1389 except UnhashableException:
1390 exc_info = sys.exc_info()
1391 exc = traceback.TracebackException(*exc_info)
1392 formatted = list(exc.format())
1393 self.assertIn('UnhashableException: ex2\n', formatted[2])
1394 self.assertIn('UnhashableException: ex1\n', formatted[6])
1395
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001396 def test_limit(self):
1397 def recurse(n):
1398 if n:
1399 recurse(n-1)
1400 else:
1401 1/0
1402 try:
1403 recurse(10)
1404 except Exception:
1405 exc_info = sys.exc_info()
1406 exc = traceback.TracebackException(*exc_info, limit=5)
1407 expected_stack = traceback.StackSummary.extract(
1408 traceback.walk_tb(exc_info[2]), limit=5)
1409 self.assertEqual(expected_stack, exc.stack)
1410
1411 def test_lookup_lines(self):
1412 linecache.clearcache()
1413 e = Exception("uh oh")
1414 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001415 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001416 tb = test_tb(f, 6, None)
1417 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
Irit Katriel44ca05a2020-11-27 16:38:54 +00001418 self.assertEqual(linecache.cache, {})
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001419 linecache.updatecache('/foo.py', globals())
1420 self.assertEqual(exc.stack[0].line, "import sys")
1421
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001422 def test_locals(self):
1423 linecache.updatecache('/foo.py', globals())
1424 e = Exception("uh oh")
1425 c = test_code('/foo.py', 'method')
1426 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
1427 tb = test_tb(f, 6, None)
1428 exc = traceback.TracebackException(
1429 Exception, e, tb, capture_locals=True)
1430 self.assertEqual(
1431 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
1432
1433 def test_no_locals(self):
1434 linecache.updatecache('/foo.py', globals())
1435 e = Exception("uh oh")
1436 c = test_code('/foo.py', 'method')
1437 f = test_frame(c, globals(), {'something': 1})
1438 tb = test_tb(f, 6, None)
1439 exc = traceback.TracebackException(Exception, e, tb)
1440 self.assertEqual(exc.stack[0].locals, None)
1441
Berker Peksagc3f417d2015-07-24 17:36:21 +03001442 def test_traceback_header(self):
1443 # do not print a traceback header if exc_traceback is None
1444 # see issue #24695
1445 exc = traceback.TracebackException(Exception, Exception("haven"), None)
1446 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
1447
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001448
Berker Peksag716b3d32015-04-08 09:47:14 +03001449class MiscTest(unittest.TestCase):
1450
1451 def test_all(self):
1452 expected = set()
Victor Stinnerfabd7bb2020-08-11 15:26:59 +02001453 denylist = {'print_list'}
Berker Peksag716b3d32015-04-08 09:47:14 +03001454 for name in dir(traceback):
Victor Stinnerfabd7bb2020-08-11 15:26:59 +02001455 if name.startswith('_') or name in denylist:
Berker Peksag716b3d32015-04-08 09:47:14 +03001456 continue
1457 module_object = getattr(traceback, name)
1458 if getattr(module_object, '__module__', None) == 'traceback':
1459 expected.add(name)
1460 self.assertCountEqual(traceback.__all__, expected)
1461
Fred Drake2e2be372001-09-20 21:33:42 +00001462
1463if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +03001464 unittest.main()