diff options
author | Martin Panter <vadmium+py@gmail.com> | 2016-02-28 03:16:11 (GMT) |
---|---|---|
committer | Martin Panter <vadmium+py@gmail.com> | 2016-02-28 03:16:11 (GMT) |
commit | 3263f6874a96c7b2862bd91460a28e66ac039dbe (patch) | |
tree | 7a730e6a8890fa5909b5500966cc838eac4862a5 /Lib | |
parent | 738f88f688b7e490725bdcc9186a888998ca0370 (diff) | |
download | cpython-3263f6874a96c7b2862bd91460a28e66ac039dbe.zip cpython-3263f6874a96c7b2862bd91460a28e66ac039dbe.tar.gz cpython-3263f6874a96c7b2862bd91460a28e66ac039dbe.tar.bz2 |
Issue #22836: Keep exception reports sensible despite errors
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_exceptions.py | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 8a49045..458ddc1 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -7,7 +7,7 @@ import pickle import weakref import errno -from test.support import (TESTFN, captured_output, check_impl_detail, +from test.support import (TESTFN, captured_stderr, check_impl_detail, check_warnings, cpython_only, gc_collect, run_unittest, no_tracing, unlink, import_module) @@ -20,6 +20,10 @@ class SlottedNaiveException(Exception): def __init__(self, x): self.x = x +class BrokenStrException(Exception): + def __str__(self): + raise Exception("str() is broken") + # XXX This is not really enough, each *operation* should be tested! class ExceptionTests(unittest.TestCase): @@ -882,7 +886,7 @@ class ExceptionTests(unittest.TestCase): class MyException(Exception, metaclass=Meta): pass - with captured_output("stderr") as stderr: + with captured_stderr() as stderr: try: raise KeyError() except MyException as e: @@ -1011,6 +1015,66 @@ class ExceptionTests(unittest.TestCase): os.listdir(__file__) self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception) + def test_unraisable(self): + # Issue #22836: PyErr_WriteUnraisable() should give sensible reports + class BrokenDel: + def __del__(self): + exc = ValueError("del is broken") + # The following line is included in the traceback report: + raise exc + + class BrokenRepr(BrokenDel): + def __repr__(self): + raise AttributeError("repr() is broken") + + class BrokenExceptionDel: + def __del__(self): + exc = BrokenStrException() + # The following line is included in the traceback report: + raise exc + + for test_class in (BrokenDel, BrokenRepr, BrokenExceptionDel): + with self.subTest(test_class): + obj = test_class() + with captured_stderr() as stderr: + del obj + report = stderr.getvalue() + self.assertIn("Exception ignored", report) + if test_class is BrokenRepr: + self.assertIn("<object repr() failed>", report) + else: + self.assertIn(test_class.__del__.__qualname__, report) + self.assertIn("test_exceptions.py", report) + self.assertIn("raise exc", report) + if test_class is BrokenExceptionDel: + self.assertIn("BrokenStrException", report) + self.assertIn("<exception str() failed>", report) + else: + self.assertIn("ValueError", report) + self.assertIn("del is broken", report) + self.assertTrue(report.endswith("\n")) + + def test_unhandled(self): + # Check for sensible reporting of unhandled exceptions + for exc_type in (ValueError, BrokenStrException): + with self.subTest(exc_type): + try: + exc = exc_type("test message") + # The following line is included in the traceback report: + raise exc + except exc_type: + with captured_stderr() as stderr: + sys.__excepthook__(*sys.exc_info()) + report = stderr.getvalue() + self.assertIn("test_exceptions.py", report) + self.assertIn("raise exc", report) + self.assertIn(exc_type.__name__, report) + if exc_type is BrokenStrException: + self.assertIn("<exception str() failed>", report) + else: + self.assertIn("test message", report) + self.assertTrue(report.endswith("\n")) + class ImportErrorTests(unittest.TestCase): |