| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 1 | """Test cases for traceback module""" | 
 | 2 |  | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 3 | from _testcapi import traceback_print, exception_print | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 4 | from io import StringIO | 
 | 5 | import sys | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 6 | import unittest | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 7 | import re | 
| Benjamin Peterson | 26d64ae | 2010-09-20 21:47:37 +0000 | [diff] [blame] | 8 | from test.support import run_unittest, Error, captured_output | 
| Amaury Forgeot d'Arc | cf8016a | 2008-10-09 23:37:48 +0000 | [diff] [blame] | 9 | from test.support import TESTFN, unlink | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 10 |  | 
 | 11 | import traceback | 
 | 12 |  | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 13 |  | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 14 | class SyntaxTracebackCases(unittest.TestCase): | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 15 |     # For now, a very minimal set of tests.  I want to be sure that | 
 | 16 |     # formatting of SyntaxErrors works based on changes for 2.1. | 
 | 17 |  | 
 | 18 |     def get_exception_format(self, func, exc): | 
 | 19 |         try: | 
 | 20 |             func() | 
| Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 21 |         except exc as value: | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 22 |             return traceback.format_exception_only(exc, value) | 
 | 23 |         else: | 
| Collin Winter | 3add4d7 | 2007-08-29 23:37:32 +0000 | [diff] [blame] | 24 |             raise ValueError("call did not raise exception") | 
| Tim Peters | 7e01e28 | 2001-04-08 07:44:07 +0000 | [diff] [blame] | 25 |  | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 26 |     def syntax_error_with_caret(self): | 
 | 27 |         compile("def fact(x):\n\treturn x!\n", "?", "exec") | 
 | 28 |  | 
| Georg Brandl | 751899a | 2009-06-04 19:41:00 +0000 | [diff] [blame] | 29 |     def syntax_error_with_caret_2(self): | 
 | 30 |         compile("1 +\n", "?", "exec") | 
 | 31 |  | 
| Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 32 |     def syntax_error_bad_indentation(self): | 
| Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 33 |         compile("def spam():\n  print(1)\n print(2)", "?", "exec") | 
| Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 34 |  | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 35 |     def test_caret(self): | 
 | 36 |         err = self.get_exception_format(self.syntax_error_with_caret, | 
 | 37 |                                         SyntaxError) | 
| Guido van Rossum | e61fd5b | 2007-07-11 12:20:59 +0000 | [diff] [blame] | 38 |         self.assertEqual(len(err), 4) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 39 |         self.assertTrue(err[1].strip() == "return x!") | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 40 |         self.assertIn("^", err[2]) # third line has caret | 
| Guido van Rossum | e61fd5b | 2007-07-11 12:20:59 +0000 | [diff] [blame] | 41 |         self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place | 
| Tim Peters | 7e01e28 | 2001-04-08 07:44:07 +0000 | [diff] [blame] | 42 |  | 
| Georg Brandl | 751899a | 2009-06-04 19:41:00 +0000 | [diff] [blame] | 43 |         err = self.get_exception_format(self.syntax_error_with_caret_2, | 
 | 44 |                                         SyntaxError) | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 45 |         self.assertIn("^", err[2]) # third line has caret | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 46 |         self.assertTrue(err[2].count('\n') == 1) # and no additional newline | 
 | 47 |         self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place | 
| Georg Brandl | 751899a | 2009-06-04 19:41:00 +0000 | [diff] [blame] | 48 |  | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 49 |     def test_nocaret(self): | 
| Benjamin Peterson | 26d64ae | 2010-09-20 21:47:37 +0000 | [diff] [blame] | 50 |         exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) | 
 | 51 |         err = traceback.format_exception_only(SyntaxError, exc) | 
| Guido van Rossum | e61fd5b | 2007-07-11 12:20:59 +0000 | [diff] [blame] | 52 |         self.assertEqual(len(err), 3) | 
| Benjamin Peterson | 26d64ae | 2010-09-20 21:47:37 +0000 | [diff] [blame] | 53 |         self.assertEqual(err[1].strip(), "bad syntax") | 
| Jeremy Hylton | 09ccc3a | 2001-03-21 20:33:04 +0000 | [diff] [blame] | 54 |  | 
| Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 55 |     def test_bad_indentation(self): | 
 | 56 |         err = self.get_exception_format(self.syntax_error_bad_indentation, | 
 | 57 |                                         IndentationError) | 
| Guido van Rossum | e61fd5b | 2007-07-11 12:20:59 +0000 | [diff] [blame] | 58 |         self.assertEqual(len(err), 4) | 
 | 59 |         self.assertEqual(err[1].strip(), "print(2)") | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 60 |         self.assertIn("^", err[2]) | 
| Guido van Rossum | e61fd5b | 2007-07-11 12:20:59 +0000 | [diff] [blame] | 61 |         self.assertEqual(err[1].find(")"), err[2].find("^")) | 
| Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 62 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 63 |     def test_base_exception(self): | 
 | 64 |         # Test that exceptions derived from BaseException are formatted right | 
 | 65 |         e = KeyboardInterrupt() | 
 | 66 |         lst = traceback.format_exception_only(e.__class__, e) | 
 | 67 |         self.assertEqual(lst, ['KeyboardInterrupt\n']) | 
 | 68 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 69 |     def test_format_exception_only_bad__str__(self): | 
 | 70 |         class X(Exception): | 
 | 71 |             def __str__(self): | 
 | 72 |                 1/0 | 
 | 73 |         err = traceback.format_exception_only(X, X()) | 
 | 74 |         self.assertEqual(len(err), 1) | 
 | 75 |         str_value = '<unprintable %s object>' % X.__name__ | 
| Georg Brandl | 1a3284e | 2007-12-02 09:40:06 +0000 | [diff] [blame] | 76 |         if X.__module__ in ('__main__', 'builtins'): | 
| Brett Cannon | 44c5261 | 2007-02-27 00:12:43 +0000 | [diff] [blame] | 77 |             str_name = X.__name__ | 
 | 78 |         else: | 
 | 79 |             str_name = '.'.join([X.__module__, X.__name__]) | 
 | 80 |         self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value)) | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 81 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 82 |     def test_without_exception(self): | 
 | 83 |         err = traceback.format_exception_only(None, None) | 
 | 84 |         self.assertEqual(err, ['None\n']) | 
 | 85 |  | 
| Amaury Forgeot d'Arc | cf8016a | 2008-10-09 23:37:48 +0000 | [diff] [blame] | 86 |     def test_encoded_file(self): | 
 | 87 |         # Test that tracebacks are correctly printed for encoded source files: | 
 | 88 |         # - correct line number (Issue2384) | 
 | 89 |         # - respect file encoding (Issue3975) | 
 | 90 |         import tempfile, sys, subprocess, os | 
 | 91 |  | 
 | 92 |         # The spawned subprocess has its stdout redirected to a PIPE, and its | 
 | 93 |         # encoding may be different from the current interpreter, on Windows | 
 | 94 |         # at least. | 
 | 95 |         process = subprocess.Popen([sys.executable, "-c", | 
 | 96 |                                     "import sys; print(sys.stdout.encoding)"], | 
 | 97 |                                    stdout=subprocess.PIPE, | 
 | 98 |                                    stderr=subprocess.STDOUT) | 
 | 99 |         stdout, stderr = process.communicate() | 
 | 100 |         output_encoding = str(stdout, 'ascii').splitlines()[0] | 
 | 101 |  | 
 | 102 |         def do_test(firstlines, message, charset, lineno): | 
 | 103 |             # Raise the message in a subprocess, and catch the output | 
 | 104 |             try: | 
 | 105 |                 output = open(TESTFN, "w", encoding=charset) | 
 | 106 |                 output.write("""{0}if 1: | 
 | 107 |                     import traceback; | 
 | 108 |                     raise RuntimeError('{1}') | 
 | 109 |                     """.format(firstlines, message)) | 
 | 110 |                 output.close() | 
 | 111 |                 process = subprocess.Popen([sys.executable, TESTFN], | 
 | 112 |                     stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 
 | 113 |                 stdout, stderr = process.communicate() | 
 | 114 |                 stdout = stdout.decode(output_encoding).splitlines() | 
 | 115 |             finally: | 
 | 116 |                 unlink(TESTFN) | 
 | 117 |  | 
 | 118 |             # The source lines are encoded with the 'backslashreplace' handler | 
 | 119 |             encoded_message = message.encode(output_encoding, | 
 | 120 |                                              'backslashreplace') | 
 | 121 |             # and we just decoded them with the output_encoding. | 
 | 122 |             message_ascii = encoded_message.decode(output_encoding) | 
 | 123 |  | 
 | 124 |             err_line = "raise RuntimeError('{0}')".format(message_ascii) | 
 | 125 |             err_msg = "RuntimeError: {0}".format(message_ascii) | 
 | 126 |  | 
| Ezio Melotti | b58e0bd | 2010-01-23 15:40:09 +0000 | [diff] [blame] | 127 |             self.assertIn(("line %s" % lineno), stdout[1], | 
| Amaury Forgeot d'Arc | cf8016a | 2008-10-09 23:37:48 +0000 | [diff] [blame] | 128 |                 "Invalid line number: {0!r} instead of {1}".format( | 
 | 129 |                     stdout[1], lineno)) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 130 |             self.assertTrue(stdout[2].endswith(err_line), | 
| Amaury Forgeot d'Arc | cf8016a | 2008-10-09 23:37:48 +0000 | [diff] [blame] | 131 |                 "Invalid traceback line: {0!r} instead of {1!r}".format( | 
 | 132 |                     stdout[2], err_line)) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 133 |             self.assertTrue(stdout[3] == err_msg, | 
| Amaury Forgeot d'Arc | cf8016a | 2008-10-09 23:37:48 +0000 | [diff] [blame] | 134 |                 "Invalid error message: {0!r} instead of {1!r}".format( | 
 | 135 |                     stdout[3], err_msg)) | 
 | 136 |  | 
 | 137 |         do_test("", "foo", "ascii", 3) | 
 | 138 |         for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"): | 
 | 139 |             if charset == "ascii": | 
 | 140 |                 text = "foo" | 
 | 141 |             elif charset == "GBK": | 
 | 142 |                 text = "\u4E02\u5100" | 
 | 143 |             else: | 
 | 144 |                 text = "h\xe9 ho" | 
 | 145 |             do_test("# coding: {0}\n".format(charset), | 
 | 146 |                     text, charset, 4) | 
 | 147 |             do_test("#!shebang\n# coding: {0}\n".format(charset), | 
 | 148 |                     text, charset, 5) | 
 | 149 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 150 |  | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 151 | class TracebackFormatTests(unittest.TestCase): | 
 | 152 |  | 
| Georg Brandl | 236f797 | 2009-04-05 14:28:42 +0000 | [diff] [blame] | 153 |     def test_traceback_format(self): | 
 | 154 |         try: | 
 | 155 |             raise KeyError('blah') | 
 | 156 |         except KeyError: | 
 | 157 |             type_, value, tb = sys.exc_info() | 
 | 158 |             traceback_fmt = 'Traceback (most recent call last):\n' + \ | 
 | 159 |                             ''.join(traceback.format_tb(tb)) | 
 | 160 |             file_ = StringIO() | 
 | 161 |             traceback_print(tb, file_) | 
 | 162 |             python_fmt  = file_.getvalue() | 
 | 163 |         else: | 
 | 164 |             raise Error("unable to create test traceback string") | 
 | 165 |  | 
 | 166 |         # Make sure that Python and the traceback module format the same thing | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 167 |         self.assertEqual(traceback_fmt, python_fmt) | 
| Georg Brandl | 236f797 | 2009-04-05 14:28:42 +0000 | [diff] [blame] | 168 |  | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 169 |         # Make sure that the traceback is properly indented. | 
| Georg Brandl | 236f797 | 2009-04-05 14:28:42 +0000 | [diff] [blame] | 170 |         tb_lines = python_fmt.splitlines() | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 171 |         self.assertEqual(len(tb_lines), 3) | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 172 |         banner, location, source_line = tb_lines | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 173 |         self.assertTrue(banner.startswith('Traceback')) | 
 | 174 |         self.assertTrue(location.startswith('  File')) | 
 | 175 |         self.assertTrue(source_line.startswith('    raise')) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 176 |  | 
 | 177 |  | 
 | 178 | cause_message = ( | 
 | 179 |     "\nThe above exception was the direct cause " | 
 | 180 |     "of the following exception:\n\n") | 
 | 181 |  | 
 | 182 | context_message = ( | 
 | 183 |     "\nDuring handling of the above exception, " | 
 | 184 |     "another exception occurred:\n\n") | 
 | 185 |  | 
 | 186 | boundaries = re.compile( | 
 | 187 |     '(%s|%s)' % (re.escape(cause_message), re.escape(context_message))) | 
 | 188 |  | 
 | 189 |  | 
 | 190 | class BaseExceptionReportingTests: | 
 | 191 |  | 
 | 192 |     def get_exception(self, exception_or_callable): | 
 | 193 |         if isinstance(exception_or_callable, Exception): | 
 | 194 |             return exception_or_callable | 
 | 195 |         try: | 
 | 196 |             exception_or_callable() | 
 | 197 |         except Exception as e: | 
 | 198 |             return e | 
 | 199 |  | 
 | 200 |     def zero_div(self): | 
 | 201 |         1/0 # In zero_div | 
 | 202 |  | 
 | 203 |     def check_zero_div(self, msg): | 
 | 204 |         lines = msg.splitlines() | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 205 |         self.assertTrue(lines[-3].startswith('  File')) | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 206 |         self.assertIn('1/0 # In zero_div', lines[-2]) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 207 |         self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1]) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 208 |  | 
 | 209 |     def test_simple(self): | 
 | 210 |         try: | 
 | 211 |             1/0 # Marker | 
 | 212 |         except ZeroDivisionError as _: | 
 | 213 |             e = _ | 
 | 214 |         lines = self.get_report(e).splitlines() | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 215 |         self.assertEqual(len(lines), 4) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 216 |         self.assertTrue(lines[0].startswith('Traceback')) | 
 | 217 |         self.assertTrue(lines[1].startswith('  File')) | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 218 |         self.assertIn('1/0 # Marker', lines[2]) | 
| Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 219 |         self.assertTrue(lines[3].startswith('ZeroDivisionError')) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 220 |  | 
 | 221 |     def test_cause(self): | 
 | 222 |         def inner_raise(): | 
 | 223 |             try: | 
 | 224 |                 self.zero_div() | 
 | 225 |             except ZeroDivisionError as e: | 
 | 226 |                 raise KeyError from e | 
 | 227 |         def outer_raise(): | 
 | 228 |             inner_raise() # Marker | 
 | 229 |         blocks = boundaries.split(self.get_report(outer_raise)) | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 230 |         self.assertEqual(len(blocks), 3) | 
 | 231 |         self.assertEqual(blocks[1], cause_message) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 232 |         self.check_zero_div(blocks[0]) | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 233 |         self.assertIn('inner_raise() # Marker', blocks[2]) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 234 |  | 
 | 235 |     def test_context(self): | 
 | 236 |         def inner_raise(): | 
 | 237 |             try: | 
 | 238 |                 self.zero_div() | 
 | 239 |             except ZeroDivisionError: | 
 | 240 |                 raise KeyError | 
 | 241 |         def outer_raise(): | 
 | 242 |             inner_raise() # Marker | 
 | 243 |         blocks = boundaries.split(self.get_report(outer_raise)) | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 244 |         self.assertEqual(len(blocks), 3) | 
 | 245 |         self.assertEqual(blocks[1], context_message) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 246 |         self.check_zero_div(blocks[0]) | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 247 |         self.assertIn('inner_raise() # Marker', blocks[2]) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 248 |  | 
| Nick Coghlan | ab7bf21 | 2012-02-26 17:49:52 +1000 | [diff] [blame] | 249 |     def test_context_suppression(self): | 
 | 250 |         try: | 
 | 251 |             try: | 
 | 252 |                 raise Exception | 
 | 253 |             except: | 
 | 254 |                 raise ZeroDivisionError from None | 
 | 255 |         except ZeroDivisionError as _: | 
 | 256 |             e = _ | 
 | 257 |         lines = self.get_report(e).splitlines() | 
 | 258 |         self.assertEqual(len(lines), 4) | 
 | 259 |         self.assertTrue(lines[0].startswith('Traceback')) | 
 | 260 |         self.assertTrue(lines[1].startswith('  File')) | 
 | 261 |         self.assertIn('ZeroDivisionError from None', lines[2]) | 
 | 262 |         self.assertTrue(lines[3].startswith('ZeroDivisionError')) | 
 | 263 |  | 
| Antoine Pitrou | 7b0d4a2 | 2009-11-28 16:12:28 +0000 | [diff] [blame] | 264 |     def test_cause_and_context(self): | 
 | 265 |         # When both a cause and a context are set, only the cause should be | 
 | 266 |         # displayed and the context should be muted. | 
 | 267 |         def inner_raise(): | 
 | 268 |             try: | 
 | 269 |                 self.zero_div() | 
 | 270 |             except ZeroDivisionError as _e: | 
 | 271 |                 e = _e | 
 | 272 |             try: | 
 | 273 |                 xyzzy | 
 | 274 |             except NameError: | 
 | 275 |                 raise KeyError from e | 
 | 276 |         def outer_raise(): | 
 | 277 |             inner_raise() # Marker | 
 | 278 |         blocks = boundaries.split(self.get_report(outer_raise)) | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 279 |         self.assertEqual(len(blocks), 3) | 
 | 280 |         self.assertEqual(blocks[1], cause_message) | 
| Antoine Pitrou | 7b0d4a2 | 2009-11-28 16:12:28 +0000 | [diff] [blame] | 281 |         self.check_zero_div(blocks[0]) | 
| Ezio Melotti | b58e0bd | 2010-01-23 15:40:09 +0000 | [diff] [blame] | 282 |         self.assertIn('inner_raise() # Marker', blocks[2]) | 
| Antoine Pitrou | 7b0d4a2 | 2009-11-28 16:12:28 +0000 | [diff] [blame] | 283 |  | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 284 |     def test_cause_recursive(self): | 
 | 285 |         def inner_raise(): | 
 | 286 |             try: | 
 | 287 |                 try: | 
 | 288 |                     self.zero_div() | 
 | 289 |                 except ZeroDivisionError as e: | 
 | 290 |                     z = e | 
 | 291 |                     raise KeyError from e | 
 | 292 |             except KeyError as e: | 
 | 293 |                 raise z from e | 
 | 294 |         def outer_raise(): | 
 | 295 |             inner_raise() # Marker | 
 | 296 |         blocks = boundaries.split(self.get_report(outer_raise)) | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 297 |         self.assertEqual(len(blocks), 3) | 
 | 298 |         self.assertEqual(blocks[1], cause_message) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 299 |         # The first block is the KeyError raised from the ZeroDivisionError | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 300 |         self.assertIn('raise KeyError from e', blocks[0]) | 
 | 301 |         self.assertNotIn('1/0', blocks[0]) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 302 |         # The second block (apart from the boundary) is the ZeroDivisionError | 
 | 303 |         # re-raised from the KeyError | 
| Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 304 |         self.assertIn('inner_raise() # Marker', blocks[2]) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 305 |         self.check_zero_div(blocks[2]) | 
 | 306 |  | 
| Benjamin Peterson | 503d6c5 | 2010-10-24 02:52:05 +0000 | [diff] [blame] | 307 |     def test_syntax_error_offset_at_eol(self): | 
 | 308 |         # See #10186. | 
 | 309 |         def e(): | 
 | 310 |             raise SyntaxError('', ('', 0, 5, 'hello')) | 
 | 311 |         msg = self.get_report(e).splitlines() | 
 | 312 |         self.assertEqual(msg[-2], "        ^") | 
| Benjamin Peterson | a95e977 | 2010-10-29 03:28:14 +0000 | [diff] [blame] | 313 |         def e(): | 
 | 314 |             exec("x = 5 | 4 |") | 
 | 315 |         msg = self.get_report(e).splitlines() | 
 | 316 |         self.assertEqual(msg[-2], '              ^') | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 317 |  | 
 | 318 |  | 
 | 319 | class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): | 
 | 320 |     # | 
 | 321 |     # This checks reporting through the 'traceback' module, with both | 
 | 322 |     # format_exception() and print_exception(). | 
 | 323 |     # | 
 | 324 |  | 
 | 325 |     def get_report(self, e): | 
 | 326 |         e = self.get_exception(e) | 
 | 327 |         s = ''.join( | 
 | 328 |             traceback.format_exception(type(e), e, e.__traceback__)) | 
 | 329 |         with captured_output("stderr") as sio: | 
 | 330 |             traceback.print_exception(type(e), e, e.__traceback__) | 
| Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 331 |         self.assertEqual(sio.getvalue(), s) | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 332 |         return s | 
 | 333 |  | 
 | 334 |  | 
 | 335 | class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): | 
 | 336 |     # | 
 | 337 |     # This checks built-in reporting by the interpreter. | 
 | 338 |     # | 
 | 339 |  | 
 | 340 |     def get_report(self, e): | 
 | 341 |         e = self.get_exception(e) | 
 | 342 |         with captured_output("stderr") as s: | 
 | 343 |             exception_print(e) | 
 | 344 |         return s.getvalue() | 
| Christian Heimes | 81ee3ef | 2008-05-04 22:42:01 +0000 | [diff] [blame] | 345 |  | 
 | 346 |  | 
| Fred Drake | 2e2be37 | 2001-09-20 21:33:42 +0000 | [diff] [blame] | 347 | def test_main(): | 
| Benjamin Peterson | e652821 | 2008-07-15 15:32:09 +0000 | [diff] [blame] | 348 |     run_unittest(__name__) | 
| Fred Drake | 2e2be37 | 2001-09-20 21:33:42 +0000 | [diff] [blame] | 349 |  | 
 | 350 | if __name__ == "__main__": | 
 | 351 |     test_main() |