@@ -909,6 +909,47 @@ def test_original_unraisablehook(self):
909909 self .assertIn ('Traceback (most recent call last):\n ' , err )
910910 self .assertIn ('ValueError: 42\n ' , err )
911911
912+ def test_original_unraisablehook_err (self ):
913+ # bpo-22836: PyErr_WriteUnraisable() should give sensible reports
914+ class BrokenDel :
915+ def __del__ (self ):
916+ exc = ValueError ("del is broken" )
917+ # The following line is included in the traceback report:
918+ raise exc
919+
920+ class BrokenStrException (Exception ):
921+ def __str__ (self ):
922+ raise Exception ("str() is broken" )
923+
924+ class BrokenExceptionDel :
925+ def __del__ (self ):
926+ exc = BrokenStrException ()
927+ # The following line is included in the traceback report:
928+ raise exc
929+
930+ for test_class in (BrokenDel , BrokenExceptionDel ):
931+ with self .subTest (test_class ):
932+ obj = test_class ()
933+ with test .support .captured_stderr () as stderr , \
934+ test .support .swap_attr (sys , 'unraisablehook' ,
935+ sys .__unraisablehook__ ):
936+ # Trigger obj.__del__()
937+ del obj
938+
939+ report = stderr .getvalue ()
940+ self .assertIn ("Exception ignored" , report )
941+ self .assertIn (test_class .__del__ .__qualname__ , report )
942+ self .assertIn ("test_sys.py" , report )
943+ self .assertIn ("raise exc" , report )
944+ if test_class is BrokenExceptionDel :
945+ self .assertIn ("BrokenStrException" , report )
946+ self .assertIn ("<exception str() failed>" , report )
947+ else :
948+ self .assertIn ("ValueError" , report )
949+ self .assertIn ("del is broken" , report )
950+ self .assertTrue (report .endswith ("\n " ))
951+
952+
912953 def test_original_unraisablehook_wrong_type (self ):
913954 exc = ValueError (42 )
914955 with test .support .swap_attr (sys , 'unraisablehook' ,
0 commit comments