@@ -315,6 +315,63 @@ def test_err_writeunraisable(self):
315315 # CRASHES writeunraisable(NULL, hex)
316316 # CRASHES writeunraisable(NULL, NULL)
317317
318+ def test_err_formatunraisable (self ):
319+ # Test PyErr_FormatUnraisable()
320+ formatunraisable = _testcapi .err_formatunraisable
321+ firstline = self .test_err_formatunraisable .__code__ .co_firstlineno
322+
323+ with support .catch_unraisable_exception () as cm :
324+ formatunraisable (CustomError ('oops!' ), b'Error in %R' , [])
325+ self .assertEqual (cm .unraisable .exc_type , CustomError )
326+ self .assertEqual (str (cm .unraisable .exc_value ), 'oops!' )
327+ self .assertEqual (cm .unraisable .exc_traceback .tb_lineno ,
328+ firstline + 6 )
329+ self .assertEqual (cm .unraisable .err_msg , 'Error in []' )
330+ self .assertIsNone (cm .unraisable .object )
331+
332+ with support .catch_unraisable_exception () as cm :
333+ formatunraisable (CustomError ('oops!' ), b'undecodable \xff ' )
334+ self .assertEqual (cm .unraisable .exc_type , CustomError )
335+ self .assertEqual (str (cm .unraisable .exc_value ), 'oops!' )
336+ self .assertEqual (cm .unraisable .exc_traceback .tb_lineno ,
337+ firstline + 15 )
338+ self .assertIsNone (cm .unraisable .err_msg )
339+ self .assertIsNone (cm .unraisable .object )
340+
341+ with support .catch_unraisable_exception () as cm :
342+ formatunraisable (CustomError ('oops!' ), NULL )
343+ self .assertEqual (cm .unraisable .exc_type , CustomError )
344+ self .assertEqual (str (cm .unraisable .exc_value ), 'oops!' )
345+ self .assertEqual (cm .unraisable .exc_traceback .tb_lineno ,
346+ firstline + 24 )
347+ self .assertIsNone (cm .unraisable .err_msg )
348+ self .assertIsNone (cm .unraisable .object )
349+
350+ with (support .swap_attr (sys , 'unraisablehook' , None ),
351+ support .captured_stderr () as stderr ):
352+ formatunraisable (CustomError ('oops!' ), b'Error in %R' , [])
353+ lines = stderr .getvalue ().splitlines ()
354+ self .assertEqual (lines [0 ], f'Error in []:' )
355+ self .assertEqual (lines [1 ], 'Traceback (most recent call last):' )
356+ self .assertEqual (lines [- 1 ], f'{ __name__ } .CustomError: oops!' )
357+
358+ with (support .swap_attr (sys , 'unraisablehook' , None ),
359+ support .captured_stderr () as stderr ):
360+ formatunraisable (CustomError ('oops!' ), b'undecodable \xff ' )
361+ lines = stderr .getvalue ().splitlines ()
362+ self .assertEqual (lines [0 ], 'Traceback (most recent call last):' )
363+ self .assertEqual (lines [- 1 ], f'{ __name__ } .CustomError: oops!' )
364+
365+ with (support .swap_attr (sys , 'unraisablehook' , None ),
366+ support .captured_stderr () as stderr ):
367+ formatunraisable (CustomError ('oops!' ), NULL )
368+ lines = stderr .getvalue ().splitlines ()
369+ self .assertEqual (lines [0 ], 'Traceback (most recent call last):' )
370+ self .assertEqual (lines [- 1 ], f'{ __name__ } .CustomError: oops!' )
371+
372+ # CRASHES formatunraisable(NULL, b'Error in %R', [])
373+ # CRASHES formatunraisable(NULL, NULL)
374+
318375
319376class Test_PyUnstable_Exc_PrepReraiseStar (ExceptionIsLikeMixin , unittest .TestCase ):
320377
0 commit comments