blob: ba03ce46294c578ec9f095c67b1f1a2115286794 [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
Guido van Rossum15bc9ab2020-05-14 19:22:48 -0700788 def test_syntax_error_various_offsets(self):
789 for offset in range(-5, 10):
790 for add in [0, 2]:
791 text = " "*add + "text%d" % offset
792 expected = [' File "file.py", line 1']
793 if offset < 1:
794 expected.append(" %s" % text.lstrip())
795 elif offset <= 6:
796 expected.append(" %s" % text.lstrip())
797 expected.append(" %s^" % (" "*(offset-1)))
798 else:
799 expected.append(" %s" % text.lstrip())
800 expected.append(" %s^" % (" "*5))
801 expected.append("SyntaxError: msg")
802 expected.append("")
803 err = self.get_report(SyntaxError("msg", ("file.py", 1, offset+add, text)))
804 exp = "\n".join(expected)
805 self.assertEqual(exp, err)
806
Miss Islington (bot)6b996d62021-09-08 09:32:19 -0700807 def test_format_exception_only_qualname(self):
808 class A:
809 class B:
810 class X(Exception):
811 def __str__(self):
812 return "I am X"
813 pass
814 err = self.get_report(A.B.X())
815 str_value = 'I am X'
816 str_name = '.'.join([A.B.X.__module__, A.B.X.__qualname__])
817 exp = "%s: %s\n" % (str_name, str_value)
818 self.assertEqual(exp, err)
819
Benjamin Petersone6528212008-07-15 15:32:09 +0000820
821class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
822 #
823 # This checks reporting through the 'traceback' module, with both
824 # format_exception() and print_exception().
825 #
826
827 def get_report(self, e):
828 e = self.get_exception(e)
829 s = ''.join(
830 traceback.format_exception(type(e), e, e.__traceback__))
831 with captured_output("stderr") as sio:
832 traceback.print_exception(type(e), e, e.__traceback__)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000833 self.assertEqual(sio.getvalue(), s)
Benjamin Petersone6528212008-07-15 15:32:09 +0000834 return s
835
836
837class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
838 #
839 # This checks built-in reporting by the interpreter.
840 #
841
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200842 @cpython_only
Benjamin Petersone6528212008-07-15 15:32:09 +0000843 def get_report(self, e):
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200844 from _testcapi import exception_print
Benjamin Petersone6528212008-07-15 15:32:09 +0000845 e = self.get_exception(e)
846 with captured_output("stderr") as s:
847 exception_print(e)
848 return s.getvalue()
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000849
850
Serhiy Storchaka24559e42015-05-03 13:19:46 +0300851class LimitTests(unittest.TestCase):
852
853 ''' Tests for limit argument.
854 It's enough to test extact_tb, extract_stack and format_exception '''
855
856 def last_raises1(self):
857 raise Exception('Last raised')
858
859 def last_raises2(self):
860 self.last_raises1()
861
862 def last_raises3(self):
863 self.last_raises2()
864
865 def last_raises4(self):
866 self.last_raises3()
867
868 def last_raises5(self):
869 self.last_raises4()
870
871 def last_returns_frame1(self):
872 return sys._getframe()
873
874 def last_returns_frame2(self):
875 return self.last_returns_frame1()
876
877 def last_returns_frame3(self):
878 return self.last_returns_frame2()
879
880 def last_returns_frame4(self):
881 return self.last_returns_frame3()
882
883 def last_returns_frame5(self):
884 return self.last_returns_frame4()
885
886 def test_extract_stack(self):
887 frame = self.last_returns_frame5()
888 def extract(**kwargs):
889 return traceback.extract_stack(frame, **kwargs)
890 def assertEqualExcept(actual, expected, ignore):
891 self.assertEqual(actual[:ignore], expected[:ignore])
892 self.assertEqual(actual[ignore+1:], expected[ignore+1:])
893 self.assertEqual(len(actual), len(expected))
894
895 with support.swap_attr(sys, 'tracebacklimit', 1000):
896 nolim = extract()
897 self.assertGreater(len(nolim), 5)
898 self.assertEqual(extract(limit=2), nolim[-2:])
899 assertEqualExcept(extract(limit=100), nolim[-100:], -5-1)
900 self.assertEqual(extract(limit=-2), nolim[:2])
901 assertEqualExcept(extract(limit=-100), nolim[:100], len(nolim)-5-1)
902 self.assertEqual(extract(limit=0), [])
903 del sys.tracebacklimit
904 assertEqualExcept(extract(), nolim, -5-1)
905 sys.tracebacklimit = 2
906 self.assertEqual(extract(), nolim[-2:])
907 self.assertEqual(extract(limit=3), nolim[-3:])
908 self.assertEqual(extract(limit=-3), nolim[:3])
909 sys.tracebacklimit = 0
910 self.assertEqual(extract(), [])
911 sys.tracebacklimit = -1
912 self.assertEqual(extract(), [])
913
914 def test_extract_tb(self):
915 try:
916 self.last_raises5()
917 except Exception:
918 exc_type, exc_value, tb = sys.exc_info()
919 def extract(**kwargs):
920 return traceback.extract_tb(tb, **kwargs)
921
922 with support.swap_attr(sys, 'tracebacklimit', 1000):
923 nolim = extract()
924 self.assertEqual(len(nolim), 5+1)
925 self.assertEqual(extract(limit=2), nolim[:2])
926 self.assertEqual(extract(limit=10), nolim)
927 self.assertEqual(extract(limit=-2), nolim[-2:])
928 self.assertEqual(extract(limit=-10), nolim)
929 self.assertEqual(extract(limit=0), [])
930 del sys.tracebacklimit
931 self.assertEqual(extract(), nolim)
932 sys.tracebacklimit = 2
933 self.assertEqual(extract(), nolim[:2])
934 self.assertEqual(extract(limit=3), nolim[:3])
935 self.assertEqual(extract(limit=-3), nolim[-3:])
936 sys.tracebacklimit = 0
937 self.assertEqual(extract(), [])
938 sys.tracebacklimit = -1
939 self.assertEqual(extract(), [])
940
941 def test_format_exception(self):
942 try:
943 self.last_raises5()
944 except Exception:
945 exc_type, exc_value, tb = sys.exc_info()
946 # [1:-1] to exclude "Traceback (...)" header and
947 # exception type and value
948 def extract(**kwargs):
949 return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1]
950
951 with support.swap_attr(sys, 'tracebacklimit', 1000):
952 nolim = extract()
953 self.assertEqual(len(nolim), 5+1)
954 self.assertEqual(extract(limit=2), nolim[:2])
955 self.assertEqual(extract(limit=10), nolim)
956 self.assertEqual(extract(limit=-2), nolim[-2:])
957 self.assertEqual(extract(limit=-10), nolim)
958 self.assertEqual(extract(limit=0), [])
959 del sys.tracebacklimit
960 self.assertEqual(extract(), nolim)
961 sys.tracebacklimit = 2
962 self.assertEqual(extract(), nolim[:2])
963 self.assertEqual(extract(limit=3), nolim[:3])
964 self.assertEqual(extract(limit=-3), nolim[-3:])
965 sys.tracebacklimit = 0
966 self.assertEqual(extract(), [])
967 sys.tracebacklimit = -1
968 self.assertEqual(extract(), [])
969
970
Andrew Kuchling173a1572013-09-15 18:15:56 -0400971class MiscTracebackCases(unittest.TestCase):
972 #
973 # Check non-printing functions in traceback module
974 #
975
976 def test_clear(self):
977 def outer():
978 middle()
979 def middle():
980 inner()
981 def inner():
982 i = 1
983 1/0
984
985 try:
986 outer()
987 except:
988 type_, value, tb = sys.exc_info()
989
990 # Initial assertion: there's one local in the inner frame.
991 inner_frame = tb.tb_next.tb_next.tb_next.tb_frame
992 self.assertEqual(len(inner_frame.f_locals), 1)
993
994 # Clear traceback frames
995 traceback.clear_frames(tb)
996
997 # Local variable dict should now be empty.
998 self.assertEqual(len(inner_frame.f_locals), 0)
999
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001000 def test_extract_stack(self):
1001 def extract():
1002 return traceback.extract_stack()
1003 result = extract()
1004 lineno = extract.__code__.co_firstlineno
Serhiy Storchaka3066fc42015-09-29 22:33:36 +03001005 self.assertEqual(result[-2:], [
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001006 (__file__, lineno+2, 'test_extract_stack', 'result = extract()'),
1007 (__file__, lineno+1, 'extract', 'return traceback.extract_stack()'),
1008 ])
Berker Peksag9797b7a2018-09-10 20:02:33 +03001009 self.assertEqual(len(result[0]), 4)
Serhiy Storchakae953ba72015-09-18 10:04:47 +03001010
Andrew Kuchling173a1572013-09-15 18:15:56 -04001011
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001012class TestFrame(unittest.TestCase):
1013
1014 def test_basics(self):
1015 linecache.clearcache()
1016 linecache.lazycache("f", globals())
1017 f = traceback.FrameSummary("f", 1, "dummy")
Serhiy Storchaka3066fc42015-09-29 22:33:36 +03001018 self.assertEqual(f,
1019 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
1020 self.assertEqual(tuple(f),
1021 ("f", 1, "dummy", '"""Test cases for traceback module"""'))
1022 self.assertEqual(f, traceback.FrameSummary("f", 1, "dummy"))
1023 self.assertEqual(f, tuple(f))
1024 # Since tuple.__eq__ doesn't support FrameSummary, the equality
1025 # operator fallbacks to FrameSummary.__eq__.
1026 self.assertEqual(tuple(f), f)
1027 self.assertIsNone(f.locals)
Serhiy Storchaka662db122019-08-08 08:42:54 +03001028 self.assertNotEqual(f, object())
1029 self.assertEqual(f, ALWAYS_EQ)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001030
1031 def test_lazy_lines(self):
1032 linecache.clearcache()
1033 f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False)
1034 self.assertEqual(None, f._line)
1035 linecache.lazycache("f", globals())
1036 self.assertEqual(
1037 '"""Test cases for traceback module"""',
1038 f.line)
1039
Pablo Galindo61eb9b52021-07-08 17:47:12 +01001040 def test_no_line(self):
1041 f = traceback.FrameSummary("f", None, "dummy")
1042 self.assertEqual(f.line, None)
1043
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001044 def test_explicit_line(self):
1045 f = traceback.FrameSummary("f", 1, "dummy", line="line")
1046 self.assertEqual("line", f.line)
1047
Berker Peksag9797b7a2018-09-10 20:02:33 +03001048 def test_len(self):
1049 f = traceback.FrameSummary("f", 1, "dummy", line="line")
1050 self.assertEqual(len(f), 4)
1051
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001052
1053class TestStack(unittest.TestCase):
1054
1055 def test_walk_stack(self):
Serhiy Storchaka1c1130f2016-10-07 23:45:42 +03001056 def deeper():
1057 return list(traceback.walk_stack(None))
1058 s1 = list(traceback.walk_stack(None))
1059 s2 = deeper()
1060 self.assertEqual(len(s2) - len(s1), 1)
1061 self.assertEqual(s2[1:], s1)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001062
1063 def test_walk_tb(self):
1064 try:
1065 1/0
1066 except Exception:
1067 _, _, tb = sys.exc_info()
1068 s = list(traceback.walk_tb(tb))
1069 self.assertEqual(len(s), 1)
1070
1071 def test_extract_stack(self):
1072 s = traceback.StackSummary.extract(traceback.walk_stack(None))
1073 self.assertIsInstance(s, traceback.StackSummary)
1074
1075 def test_extract_stack_limit(self):
1076 s = traceback.StackSummary.extract(traceback.walk_stack(None), limit=5)
1077 self.assertEqual(len(s), 5)
1078
1079 def test_extract_stack_lookup_lines(self):
1080 linecache.clearcache()
1081 linecache.updatecache('/foo.py', globals())
1082 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001083 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001084 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=True)
1085 linecache.clearcache()
1086 self.assertEqual(s[0].line, "import sys")
1087
1088 def test_extract_stackup_deferred_lookup_lines(self):
1089 linecache.clearcache()
1090 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001091 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001092 s = traceback.StackSummary.extract(iter([(f, 6)]), lookup_lines=False)
1093 self.assertEqual({}, linecache.cache)
1094 linecache.updatecache('/foo.py', globals())
1095 self.assertEqual(s[0].line, "import sys")
1096
1097 def test_from_list(self):
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001098 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001099 self.assertEqual(
1100 [' File "foo.py", line 1, in fred\n line\n'],
1101 s.format())
1102
Robert Collinsbbb8ade2015-03-16 15:27:16 +13001103 def test_from_list_edited_stack(self):
1104 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
1105 s[0] = ('foo.py', 2, 'fred', 'line')
1106 s2 = traceback.StackSummary.from_list(s)
1107 self.assertEqual(
1108 [' File "foo.py", line 2, in fred\n line\n'],
1109 s2.format())
1110
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001111 def test_format_smoke(self):
1112 # For detailed tests see the format_list tests, which consume the same
1113 # code.
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001114 s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001115 self.assertEqual(
1116 [' File "foo.py", line 1, in fred\n line\n'],
1117 s.format())
1118
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001119 def test_locals(self):
1120 linecache.updatecache('/foo.py', globals())
1121 c = test_code('/foo.py', 'method')
1122 f = test_frame(c, globals(), {'something': 1})
1123 s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True)
1124 self.assertEqual(s[0].locals, {'something': '1'})
1125
1126 def test_no_locals(self):
1127 linecache.updatecache('/foo.py', globals())
1128 c = test_code('/foo.py', 'method')
1129 f = test_frame(c, globals(), {'something': 1})
1130 s = traceback.StackSummary.extract(iter([(f, 6)]))
1131 self.assertEqual(s[0].locals, None)
1132
1133 def test_format_locals(self):
1134 def some_inner(k, v):
1135 a = 1
1136 b = 2
1137 return traceback.StackSummary.extract(
1138 traceback.walk_stack(None), capture_locals=True, limit=1)
1139 s = some_inner(3, 4)
1140 self.assertEqual(
Serhiy Storchaka24559e42015-05-03 13:19:46 +03001141 [' File "%s", line %d, in some_inner\n'
Serhiy Storchakada8d72c2018-09-17 15:17:29 +03001142 ' return traceback.StackSummary.extract(\n'
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001143 ' a = 1\n'
1144 ' b = 2\n'
1145 ' k = 3\n'
Serhiy Storchakada8d72c2018-09-17 15:17:29 +03001146 ' v = 4\n' % (__file__, some_inner.__code__.co_firstlineno + 3)
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001147 ], s.format())
1148
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001149class TestTracebackException(unittest.TestCase):
1150
1151 def test_smoke(self):
1152 try:
1153 1/0
1154 except Exception:
1155 exc_info = sys.exc_info()
1156 exc = traceback.TracebackException(*exc_info)
1157 expected_stack = traceback.StackSummary.extract(
1158 traceback.walk_tb(exc_info[2]))
1159 self.assertEqual(None, exc.__cause__)
1160 self.assertEqual(None, exc.__context__)
1161 self.assertEqual(False, exc.__suppress_context__)
1162 self.assertEqual(expected_stack, exc.stack)
1163 self.assertEqual(exc_info[0], exc.exc_type)
1164 self.assertEqual(str(exc_info[1]), str(exc))
1165
1166 def test_from_exception(self):
1167 # Check all the parameters are accepted.
1168 def foo():
1169 1/0
1170 try:
1171 foo()
1172 except Exception as e:
1173 exc_info = sys.exc_info()
1174 self.expected_stack = traceback.StackSummary.extract(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001175 traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False,
1176 capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001177 self.exc = traceback.TracebackException.from_exception(
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001178 e, limit=1, lookup_lines=False, capture_locals=True)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001179 expected_stack = self.expected_stack
1180 exc = self.exc
1181 self.assertEqual(None, exc.__cause__)
1182 self.assertEqual(None, exc.__context__)
1183 self.assertEqual(False, exc.__suppress_context__)
1184 self.assertEqual(expected_stack, exc.stack)
1185 self.assertEqual(exc_info[0], exc.exc_type)
1186 self.assertEqual(str(exc_info[1]), str(exc))
1187
1188 def test_cause(self):
1189 try:
1190 try:
1191 1/0
1192 finally:
1193 exc_info_context = sys.exc_info()
1194 exc_context = traceback.TracebackException(*exc_info_context)
1195 cause = Exception("cause")
1196 raise Exception("uh oh") from cause
1197 except Exception:
1198 exc_info = sys.exc_info()
1199 exc = traceback.TracebackException(*exc_info)
1200 expected_stack = traceback.StackSummary.extract(
1201 traceback.walk_tb(exc_info[2]))
1202 exc_cause = traceback.TracebackException(Exception, cause, None)
1203 self.assertEqual(exc_cause, exc.__cause__)
1204 self.assertEqual(exc_context, exc.__context__)
1205 self.assertEqual(True, exc.__suppress_context__)
1206 self.assertEqual(expected_stack, exc.stack)
1207 self.assertEqual(exc_info[0], exc.exc_type)
1208 self.assertEqual(str(exc_info[1]), str(exc))
1209
1210 def test_context(self):
1211 try:
1212 try:
1213 1/0
1214 finally:
1215 exc_info_context = sys.exc_info()
1216 exc_context = traceback.TracebackException(*exc_info_context)
1217 raise Exception("uh oh")
1218 except Exception:
1219 exc_info = sys.exc_info()
1220 exc = traceback.TracebackException(*exc_info)
1221 expected_stack = traceback.StackSummary.extract(
1222 traceback.walk_tb(exc_info[2]))
1223 self.assertEqual(None, exc.__cause__)
1224 self.assertEqual(exc_context, exc.__context__)
1225 self.assertEqual(False, exc.__suppress_context__)
1226 self.assertEqual(expected_stack, exc.stack)
1227 self.assertEqual(exc_info[0], exc.exc_type)
1228 self.assertEqual(str(exc_info[1]), str(exc))
1229
Irit Katriel6dfd1732021-01-12 22:14:27 +00001230 def test_long_context_chain(self):
1231 def f():
1232 try:
1233 1/0
1234 except:
1235 f()
1236
1237 try:
1238 f()
1239 except RecursionError:
1240 exc_info = sys.exc_info()
1241 else:
1242 self.fail("Exception not raised")
1243
1244 te = traceback.TracebackException(*exc_info)
1245 res = list(te.format())
1246
1247 # many ZeroDiv errors followed by the RecursionError
1248 self.assertGreater(len(res), sys.getrecursionlimit())
1249 self.assertGreater(
1250 len([l for l in res if 'ZeroDivisionError:' in l]),
1251 sys.getrecursionlimit() * 0.5)
1252 self.assertIn(
1253 "RecursionError: maximum recursion depth exceeded", res[-1])
1254
Irit Katriel4c94d742021-01-15 02:45:02 +00001255 def test_compact_with_cause(self):
1256 try:
1257 try:
1258 1/0
1259 finally:
1260 cause = Exception("cause")
1261 raise Exception("uh oh") from cause
1262 except Exception:
1263 exc_info = sys.exc_info()
1264 exc = traceback.TracebackException(*exc_info, compact=True)
1265 expected_stack = traceback.StackSummary.extract(
1266 traceback.walk_tb(exc_info[2]))
1267 exc_cause = traceback.TracebackException(Exception, cause, None)
1268 self.assertEqual(exc_cause, exc.__cause__)
1269 self.assertEqual(None, exc.__context__)
1270 self.assertEqual(True, exc.__suppress_context__)
1271 self.assertEqual(expected_stack, exc.stack)
1272 self.assertEqual(exc_info[0], exc.exc_type)
1273 self.assertEqual(str(exc_info[1]), str(exc))
1274
1275 def test_compact_no_cause(self):
1276 try:
1277 try:
1278 1/0
1279 finally:
1280 exc_info_context = sys.exc_info()
1281 exc_context = traceback.TracebackException(*exc_info_context)
1282 raise Exception("uh oh")
1283 except Exception:
1284 exc_info = sys.exc_info()
1285 exc = traceback.TracebackException(*exc_info, compact=True)
1286 expected_stack = traceback.StackSummary.extract(
1287 traceback.walk_tb(exc_info[2]))
1288 self.assertEqual(None, exc.__cause__)
1289 self.assertEqual(exc_context, exc.__context__)
1290 self.assertEqual(False, exc.__suppress_context__)
1291 self.assertEqual(expected_stack, exc.stack)
1292 self.assertEqual(exc_info[0], exc.exc_type)
1293 self.assertEqual(str(exc_info[1]), str(exc))
1294
Irit Katriel427613f2020-12-01 01:35:25 +00001295 def test_no_refs_to_exception_and_traceback_objects(self):
1296 try:
1297 1/0
1298 except Exception:
1299 exc_info = sys.exc_info()
1300
1301 refcnt1 = sys.getrefcount(exc_info[1])
1302 refcnt2 = sys.getrefcount(exc_info[2])
1303 exc = traceback.TracebackException(*exc_info)
1304 self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1)
1305 self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2)
1306
Irit Katriel44ca05a2020-11-27 16:38:54 +00001307 def test_comparison_basic(self):
Serhiy Storchaka662db122019-08-08 08:42:54 +03001308 try:
1309 1/0
1310 except Exception:
1311 exc_info = sys.exc_info()
1312 exc = traceback.TracebackException(*exc_info)
1313 exc2 = traceback.TracebackException(*exc_info)
1314 self.assertIsNot(exc, exc2)
1315 self.assertEqual(exc, exc2)
1316 self.assertNotEqual(exc, object())
1317 self.assertEqual(exc, ALWAYS_EQ)
1318
Irit Katriel44ca05a2020-11-27 16:38:54 +00001319 def test_comparison_params_variations(self):
1320 def raise_exc():
1321 try:
1322 raise ValueError('bad value')
1323 except:
1324 raise
1325
1326 def raise_with_locals():
1327 x, y = 1, 2
1328 raise_exc()
1329
1330 try:
1331 raise_with_locals()
1332 except Exception:
1333 exc_info = sys.exc_info()
1334
1335 exc = traceback.TracebackException(*exc_info)
1336 exc1 = traceback.TracebackException(*exc_info, limit=10)
1337 exc2 = traceback.TracebackException(*exc_info, limit=2)
1338
1339 self.assertEqual(exc, exc1) # limit=10 gets all frames
1340 self.assertNotEqual(exc, exc2) # limit=2 truncates the output
1341
1342 # locals change the output
1343 exc3 = traceback.TracebackException(*exc_info, capture_locals=True)
1344 self.assertNotEqual(exc, exc3)
1345
1346 # there are no locals in the innermost frame
1347 exc4 = traceback.TracebackException(*exc_info, limit=-1)
1348 exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True)
1349 self.assertEqual(exc4, exc5)
1350
1351 # there are locals in the next-to-innermost frame
1352 exc6 = traceback.TracebackException(*exc_info, limit=-2)
1353 exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True)
1354 self.assertNotEqual(exc6, exc7)
1355
Irit Katriel427613f2020-12-01 01:35:25 +00001356 def test_comparison_equivalent_exceptions_are_equal(self):
1357 excs = []
1358 for _ in range(2):
1359 try:
1360 1/0
1361 except:
1362 excs.append(traceback.TracebackException(*sys.exc_info()))
1363 self.assertEqual(excs[0], excs[1])
1364 self.assertEqual(list(excs[0].format()), list(excs[1].format()))
1365
Zane Bitterde860732017-10-17 17:29:39 -04001366 def test_unhashable(self):
1367 class UnhashableException(Exception):
1368 def __eq__(self, other):
1369 return True
1370
1371 ex1 = UnhashableException('ex1')
1372 ex2 = UnhashableException('ex2')
1373 try:
1374 raise ex2 from ex1
1375 except UnhashableException:
1376 try:
1377 raise ex1
1378 except UnhashableException:
1379 exc_info = sys.exc_info()
1380 exc = traceback.TracebackException(*exc_info)
1381 formatted = list(exc.format())
1382 self.assertIn('UnhashableException: ex2\n', formatted[2])
1383 self.assertIn('UnhashableException: ex1\n', formatted[6])
1384
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001385 def test_limit(self):
1386 def recurse(n):
1387 if n:
1388 recurse(n-1)
1389 else:
1390 1/0
1391 try:
1392 recurse(10)
1393 except Exception:
1394 exc_info = sys.exc_info()
1395 exc = traceback.TracebackException(*exc_info, limit=5)
1396 expected_stack = traceback.StackSummary.extract(
1397 traceback.walk_tb(exc_info[2]), limit=5)
1398 self.assertEqual(expected_stack, exc.stack)
1399
1400 def test_lookup_lines(self):
1401 linecache.clearcache()
1402 e = Exception("uh oh")
1403 c = test_code('/foo.py', 'method')
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001404 f = test_frame(c, None, None)
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001405 tb = test_tb(f, 6, None)
1406 exc = traceback.TracebackException(Exception, e, tb, lookup_lines=False)
Irit Katriel44ca05a2020-11-27 16:38:54 +00001407 self.assertEqual(linecache.cache, {})
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001408 linecache.updatecache('/foo.py', globals())
1409 self.assertEqual(exc.stack[0].line, "import sys")
1410
Robert Collinsd7c7e0e2015-03-05 20:28:52 +13001411 def test_locals(self):
1412 linecache.updatecache('/foo.py', globals())
1413 e = Exception("uh oh")
1414 c = test_code('/foo.py', 'method')
1415 f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
1416 tb = test_tb(f, 6, None)
1417 exc = traceback.TracebackException(
1418 Exception, e, tb, capture_locals=True)
1419 self.assertEqual(
1420 exc.stack[0].locals, {'something': '1', 'other': "'string'"})
1421
1422 def test_no_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})
1427 tb = test_tb(f, 6, None)
1428 exc = traceback.TracebackException(Exception, e, tb)
1429 self.assertEqual(exc.stack[0].locals, None)
1430
Berker Peksagc3f417d2015-07-24 17:36:21 +03001431 def test_traceback_header(self):
1432 # do not print a traceback header if exc_traceback is None
1433 # see issue #24695
1434 exc = traceback.TracebackException(Exception, Exception("haven"), None)
1435 self.assertEqual(list(exc.format()), ["Exception: haven\n"])
1436
Robert Collins6bc2c1e2015-03-05 12:07:57 +13001437
Berker Peksag716b3d32015-04-08 09:47:14 +03001438class MiscTest(unittest.TestCase):
1439
1440 def test_all(self):
1441 expected = set()
Victor Stinnerfabd7bb2020-08-11 15:26:59 +02001442 denylist = {'print_list'}
Berker Peksag716b3d32015-04-08 09:47:14 +03001443 for name in dir(traceback):
Victor Stinnerfabd7bb2020-08-11 15:26:59 +02001444 if name.startswith('_') or name in denylist:
Berker Peksag716b3d32015-04-08 09:47:14 +03001445 continue
1446 module_object = getattr(traceback, name)
1447 if getattr(module_object, '__module__', None) == 'traceback':
1448 expected.add(name)
1449 self.assertCountEqual(traceback.__all__, expected)
1450
Fred Drake2e2be372001-09-20 21:33:42 +00001451
1452if __name__ == "__main__":
Berker Peksag716b3d32015-04-08 09:47:14 +03001453 unittest.main()