@@ -1077,6 +1077,7 @@ static PyStructSequence_Field UnraisableHookArgs_fields[] = {
10771077 {"exc_type" , "Exception type" },
10781078 {"exc_value" , "Exception value" },
10791079 {"exc_traceback" , "Exception traceback" },
1080+ {"err_msg" , "Error message" },
10801081 {"object" , "Object causing the exception" },
10811082 {0 }
10821083};
@@ -1085,7 +1086,7 @@ static PyStructSequence_Desc UnraisableHookArgs_desc = {
10851086 .name = "UnraisableHookArgs" ,
10861087 .doc = UnraisableHookArgs__doc__ ,
10871088 .fields = UnraisableHookArgs_fields ,
1088- .n_in_sequence = 4
1089+ .n_in_sequence = 5
10891090};
10901091
10911092
@@ -1104,7 +1105,8 @@ _PyErr_Init(void)
11041105
11051106static PyObject *
11061107make_unraisable_hook_args (PyThreadState * tstate , PyObject * exc_type ,
1107- PyObject * exc_value , PyObject * exc_tb , PyObject * obj )
1108+ PyObject * exc_value , PyObject * exc_tb ,
1109+ PyObject * err_msg , PyObject * obj )
11081110{
11091111 PyObject * args = PyStructSequence_New (& UnraisableHookArgsType );
11101112 if (args == NULL ) {
@@ -1125,6 +1127,7 @@ make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
11251127 ADD_ITEM (exc_type );
11261128 ADD_ITEM (exc_value );
11271129 ADD_ITEM (exc_tb );
1130+ ADD_ITEM (err_msg );
11281131 ADD_ITEM (obj );
11291132#undef ADD_ITEM
11301133
@@ -1145,11 +1148,21 @@ make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type,
11451148static int
11461149write_unraisable_exc_file (PyThreadState * tstate , PyObject * exc_type ,
11471150 PyObject * exc_value , PyObject * exc_tb ,
1148- PyObject * obj , PyObject * file )
1151+ PyObject * err_msg , PyObject * obj , PyObject * file )
11491152{
11501153 if (obj != NULL && obj != Py_None ) {
1151- if (PyFile_WriteString ("Exception ignored in: " , file ) < 0 ) {
1152- return -1 ;
1154+ if (err_msg != NULL && err_msg != Py_None ) {
1155+ if (PyFile_WriteObject (err_msg , file , Py_PRINT_RAW ) < 0 ) {
1156+ return -1 ;
1157+ }
1158+ if (PyFile_WriteString (": " , file ) < 0 ) {
1159+ return -1 ;
1160+ }
1161+ }
1162+ else {
1163+ if (PyFile_WriteString ("Exception ignored in: " , file ) < 0 ) {
1164+ return -1 ;
1165+ }
11531166 }
11541167
11551168 if (PyFile_WriteObject (obj , file , 0 ) < 0 ) {
@@ -1162,6 +1175,14 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
11621175 return -1 ;
11631176 }
11641177 }
1178+ else if (err_msg != NULL && err_msg != Py_None ) {
1179+ if (PyFile_WriteObject (err_msg , file , Py_PRINT_RAW ) < 0 ) {
1180+ return -1 ;
1181+ }
1182+ if (PyFile_WriteString (":\n" , file ) < 0 ) {
1183+ return -1 ;
1184+ }
1185+ }
11651186
11661187 if (exc_tb != NULL && exc_tb != Py_None ) {
11671188 if (PyTraceBack_Print (exc_tb , file ) < 0 ) {
@@ -1178,8 +1199,9 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
11781199 const char * className = PyExceptionClass_Name (exc_type );
11791200 if (className != NULL ) {
11801201 const char * dot = strrchr (className , '.' );
1181- if (dot != NULL )
1202+ if (dot != NULL ) {
11821203 className = dot + 1 ;
1204+ }
11831205 }
11841206
11851207 _Py_IDENTIFIER (__module__ );
@@ -1238,7 +1260,8 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type,
12381260
12391261static int
12401262write_unraisable_exc (PyThreadState * tstate , PyObject * exc_type ,
1241- PyObject * exc_value , PyObject * exc_tb , PyObject * obj )
1263+ PyObject * exc_value , PyObject * exc_tb , PyObject * err_msg ,
1264+ PyObject * obj )
12421265{
12431266 PyObject * file = _PySys_GetObjectId (& PyId_stderr );
12441267 if (file == NULL || file == Py_None ) {
@@ -1249,7 +1272,7 @@ write_unraisable_exc(PyThreadState *tstate, PyObject *exc_type,
12491272 while we use it */
12501273 Py_INCREF (file );
12511274 int res = write_unraisable_exc_file (tstate , exc_type , exc_value , exc_tb ,
1252- obj , file );
1275+ err_msg , obj , file );
12531276 Py_DECREF (file );
12541277
12551278 return res ;
@@ -1272,9 +1295,10 @@ _PyErr_WriteUnraisableDefaultHook(PyObject *args)
12721295 PyObject * exc_type = PyStructSequence_GET_ITEM (args , 0 );
12731296 PyObject * exc_value = PyStructSequence_GET_ITEM (args , 1 );
12741297 PyObject * exc_tb = PyStructSequence_GET_ITEM (args , 2 );
1275- PyObject * obj = PyStructSequence_GET_ITEM (args , 3 );
1298+ PyObject * err_msg = PyStructSequence_GET_ITEM (args , 3 );
1299+ PyObject * obj = PyStructSequence_GET_ITEM (args , 4 );
12761300
1277- if (write_unraisable_exc (tstate , exc_type , exc_value , exc_tb , obj ) < 0 ) {
1301+ if (write_unraisable_exc (tstate , exc_type , exc_value , exc_tb , err_msg , obj ) < 0 ) {
12781302 return NULL ;
12791303 }
12801304 Py_RETURN_NONE ;
@@ -1287,13 +1311,18 @@ _PyErr_WriteUnraisableDefaultHook(PyObject *args)
12871311 for Python to handle it. For example, when a destructor raises an exception
12881312 or during garbage collection (gc.collect()).
12891313
1314+ If err_msg_str is non-NULL, the error message is formatted as:
1315+ "Exception ignored %s" % err_msg_str. Otherwise, use "Exception ignored in"
1316+ error message.
1317+
12901318 An exception must be set when calling this function. */
12911319void
1292- PyErr_WriteUnraisable ( PyObject * obj )
1320+ _PyErr_WriteUnraisableMsg ( const char * err_msg_str , PyObject * obj )
12931321{
12941322 PyThreadState * tstate = _PyThreadState_GET ();
12951323 assert (tstate != NULL );
12961324
1325+ PyObject * err_msg = NULL ;
12971326 PyObject * exc_type , * exc_value , * exc_tb ;
12981327 _PyErr_Fetch (tstate , & exc_type , & exc_value , & exc_tb );
12991328
@@ -1322,13 +1351,20 @@ PyErr_WriteUnraisable(PyObject *obj)
13221351 }
13231352 }
13241353
1354+ if (err_msg_str != NULL ) {
1355+ err_msg = PyUnicode_FromFormat ("Exception ignored %s" , err_msg_str );
1356+ if (err_msg == NULL ) {
1357+ PyErr_Clear ();
1358+ }
1359+ }
1360+
13251361 _Py_IDENTIFIER (unraisablehook );
13261362 PyObject * hook = _PySys_GetObjectId (& PyId_unraisablehook );
13271363 if (hook != NULL && hook != Py_None ) {
13281364 PyObject * hook_args ;
13291365
13301366 hook_args = make_unraisable_hook_args (tstate , exc_type , exc_value ,
1331- exc_tb , obj );
1367+ exc_tb , err_msg , obj );
13321368 if (hook_args != NULL ) {
13331369 PyObject * args [1 ] = {hook_args };
13341370 PyObject * res = _PyObject_FastCall (hook , args , 1 );
@@ -1337,6 +1373,18 @@ PyErr_WriteUnraisable(PyObject *obj)
13371373 Py_DECREF (res );
13381374 goto done ;
13391375 }
1376+
1377+ err_msg_str = "Exception ignored in sys.unraisablehook" ;
1378+ }
1379+ else {
1380+ err_msg_str = ("Exception ignored on building "
1381+ "sys.unraisablehook arguments" );
1382+ }
1383+
1384+ Py_XDECREF (err_msg );
1385+ err_msg = PyUnicode_FromString (err_msg_str );
1386+ if (err_msg == NULL ) {
1387+ PyErr_Clear ();
13401388 }
13411389
13421390 /* sys.unraisablehook failed: log its error using default hook */
@@ -1350,15 +1398,25 @@ PyErr_WriteUnraisable(PyObject *obj)
13501398
13511399default_hook :
13521400 /* Call the default unraisable hook (ignore failure) */
1353- (void )write_unraisable_exc (tstate , exc_type , exc_value , exc_tb , obj );
1401+ (void )write_unraisable_exc (tstate , exc_type , exc_value , exc_tb ,
1402+ err_msg , obj );
13541403
13551404done :
13561405 Py_XDECREF (exc_type );
13571406 Py_XDECREF (exc_value );
13581407 Py_XDECREF (exc_tb );
1408+ Py_XDECREF (err_msg );
13591409 _PyErr_Clear (tstate ); /* Just in case */
13601410}
13611411
1412+
1413+ void
1414+ PyErr_WriteUnraisable (PyObject * obj )
1415+ {
1416+ _PyErr_WriteUnraisableMsg (NULL , obj );
1417+ }
1418+
1419+
13621420extern PyObject * PyModule_GetWarningsModule (void );
13631421
13641422
0 commit comments