@@ -384,3 +384,145 @@ def test_real_oserror():
384384 assert isinstance (exc , OSError )
385385 assert exc .errno == 2
386386 assert str_output == str (exc )
387+
388+
389+ @pytest .mark .skipif (not has_python311 , reason = 'ExceptionGroup needs Python 3.11' )
390+ def test_exception_group ():
391+ errors = []
392+ try :
393+ e = CustomWithAttributesException ('bar' , 1 , 2 , 3 )
394+ e .add_note ('test_custom_with_attributes' )
395+ raise e
396+ except Exception as e :
397+ errors .append (e )
398+
399+ try :
400+ e = CustomOSError ('bar' , 2 , 'err' , 3 , None , 5 )
401+ e .add_note ('test_custom_oserror' )
402+ raise e
403+ except Exception as e :
404+ errors .append (e )
405+
406+ try :
407+ e = OSError (2 , 'err' , 3 , None , 5 )
408+ e .add_note ('test_oserror' )
409+ raise e
410+ except Exception as e :
411+ errors .append (e )
412+
413+ try :
414+ bad_open ()
415+ except Exception as e :
416+ e .add_note ('test_permissionerror' )
417+ errors .append (e )
418+
419+ try :
420+ raise BadError
421+ except Exception as e :
422+ e .add_note ('test_baderror' )
423+ errors .append (e )
424+
425+ try :
426+ e = BadError2 ('123' )
427+ e .add_note ('test_baderror2' )
428+ raise e
429+ except Exception as e :
430+ errors .append (e )
431+
432+ try :
433+ e = CustomReduceException ('foo' , 1 , 2 , 3 )
434+ e .add_note ('test_custom_reduce' )
435+ raise e
436+ except Exception as e :
437+ errors .append (e )
438+
439+ try :
440+ e = OSError (13 , 'Permission denied' )
441+ e .add_note ('test_oserror_simple' )
442+ raise e
443+ except Exception as e :
444+ errors .append (e )
445+
446+ try :
447+ os .open ('non-existing-file' , os .O_RDONLY )
448+ except Exception as e :
449+ e .add_note ('test_real_oserror' )
450+ real_oserror_str = str (e )
451+ errors .append (e )
452+ else :
453+ pytest .fail ('os.open should have raised an OSError' )
454+
455+ try :
456+ raise ExceptionGroup ('group error' , errors ) # noqa: F821
457+ except Exception as e :
458+ exc = e
459+
460+ assert len (exc .exceptions ) == 9 # before pickling
461+
462+ tblib .pickling_support .install ()
463+ exc = pickle .loads (pickle .dumps (exc ))
464+
465+ assert len (exc .exceptions ) == 9 # after unpickling
466+
467+ assert exc .exceptions [0 ].__notes__ == ['test_custom_with_attributes' ]
468+ assert isinstance (exc .exceptions [0 ], CustomWithAttributesException )
469+ assert exc .exceptions [0 ].args == ('bar' ,)
470+ assert exc .exceptions [0 ].values12 == (1 , 2 )
471+ assert exc .exceptions [0 ].value3 == 3
472+ assert exc .exceptions [0 ].__traceback__ is not None
473+
474+ assert exc .exceptions [1 ].__notes__ == ['test_custom_oserror' ]
475+ assert isinstance (exc .exceptions [1 ], CustomOSError )
476+ assert exc .exceptions [1 ].message == 'bar'
477+ assert exc .exceptions [1 ].errno == 2
478+ assert exc .exceptions [1 ].strerror == 'err'
479+ assert exc .exceptions [1 ].filename == 3
480+ assert exc .exceptions [1 ].filename2 == 5
481+ assert exc .exceptions [1 ].__traceback__ is not None
482+
483+ assert exc .exceptions [2 ].__notes__ == ['test_oserror' ]
484+ assert isinstance (exc .exceptions [2 ], OSError )
485+ assert exc .exceptions [2 ].errno == 2
486+ assert exc .exceptions [2 ].strerror == 'err'
487+ assert exc .exceptions [2 ].filename == 3
488+ assert exc .exceptions [2 ].filename2 == 5
489+ assert exc .exceptions [2 ].__traceback__ is not None
490+
491+ assert exc .exceptions [3 ].__notes__ == ['test_permissionerror' ]
492+ assert isinstance (exc .exceptions [3 ], OpenError )
493+ assert exc .exceptions [3 ].__traceback__ is not None
494+ assert repr (exc .exceptions [3 ]) == "OpenError(PermissionError(13, 'Booboo'))"
495+ assert str (exc .exceptions [3 ]) == "[Errno 13] Booboo: 'filename'"
496+ assert exc .exceptions [3 ].args [0 ].errno == 13
497+ assert exc .exceptions [3 ].args [0 ].strerror == 'Booboo'
498+ assert exc .exceptions [3 ].args [0 ].filename == 'filename'
499+
500+ assert exc .exceptions [4 ].__notes__ == ['test_baderror' ]
501+ assert isinstance (exc .exceptions [4 ], BadError )
502+ assert exc .exceptions [4 ].args == ('Bad Bad Bad!' ,)
503+ assert exc .exceptions [4 ].__traceback__ is not None
504+
505+ assert exc .exceptions [5 ].__notes__ == ['test_baderror2' ]
506+ assert isinstance (exc .exceptions [5 ], BadError2 )
507+ assert exc .exceptions [5 ].args == ()
508+ assert exc .exceptions [5 ].stuff == '123'
509+ assert exc .exceptions [5 ].__traceback__ is not None
510+
511+ assert exc .exceptions [6 ].__notes__ == ['test_custom_reduce' ]
512+ assert isinstance (exc .exceptions [6 ], CustomReduceException )
513+ assert exc .exceptions [6 ].args == ('foo' ,)
514+ assert exc .exceptions [6 ].values12 == (1 , 2 )
515+ assert exc .exceptions [6 ].value3 == 3
516+ assert exc .exceptions [6 ].__traceback__ is not None
517+
518+ assert exc .exceptions [7 ].__notes__ == ['test_oserror_simple' ]
519+ assert isinstance (exc .exceptions [7 ], OSError )
520+ assert exc .exceptions [7 ].args == (13 , 'Permission denied' )
521+ assert exc .exceptions [7 ].errno == 13
522+ assert exc .exceptions [7 ].strerror == 'Permission denied'
523+ assert exc .exceptions [7 ].__traceback__ is not None
524+
525+ assert exc .exceptions [8 ].__notes__ == ['test_real_oserror' ]
526+ assert isinstance (exc .exceptions [8 ], OSError )
527+ assert exc .exceptions [8 ].errno == 2
528+ assert str (exc .exceptions [8 ]) == real_oserror_str
0 commit comments