@@ -19,7 +19,9 @@ def assert_raises_unraisable(self, exc_type, func, *args):
1919 atexit .register (func , * args )
2020 atexit ._run_exitfuncs ()
2121
22- self .assertEqual (cm .unraisable .object , func )
22+ self .assertIsNone (cm .unraisable .object )
23+ self .assertEqual (cm .unraisable .err_msg ,
24+ f'Exception ignored in atexit callback { func !r} ' )
2325 self .assertEqual (cm .unraisable .exc_type , exc_type )
2426 self .assertEqual (type (cm .unraisable .exc_value ), exc_type )
2527
@@ -45,19 +47,22 @@ def func2(*args, **kwargs):
4547 ('func2' , (), {}),
4648 ('func1' , (1 , 2 ), {})])
4749
50+ @unittest .expectedFailure # TODO: RUSTPYTHON
4851 def test_badargs (self ):
4952 def func ():
5053 pass
5154
5255 # func() has no parameter, but it's called with 2 parameters
5356 self .assert_raises_unraisable (TypeError , func , 1 ,2 )
5457
58+ @unittest .expectedFailure # TODO: RUSTPYTHON
5559 def test_raise (self ):
5660 def raise_type_error ():
5761 raise TypeError
5862
5963 self .assert_raises_unraisable (TypeError , raise_type_error )
6064
65+ @unittest .expectedFailure # TODO: RUSTPYTHON
6166 def test_raise_unnormalized (self ):
6267 # bpo-10756: Make sure that an unnormalized exception is handled
6368 # properly.
@@ -66,6 +71,7 @@ def div_zero():
6671
6772 self .assert_raises_unraisable (ZeroDivisionError , div_zero )
6873
74+ @unittest .expectedFailure # TODO: RUSTPYTHON
6975 def test_exit (self ):
7076 self .assert_raises_unraisable (SystemExit , sys .exit )
7177
@@ -116,6 +122,7 @@ def test_bound_methods(self):
116122 atexit ._run_exitfuncs ()
117123 self .assertEqual (l , [5 ])
118124
125+ @unittest .expectedFailure # TODO: RUSTPYTHON
119126 def test_atexit_with_unregistered_function (self ):
120127 # See bpo-46025 for more info
121128 def func ():
@@ -125,12 +132,63 @@ def func():
125132 try :
126133 with support .catch_unraisable_exception () as cm :
127134 atexit ._run_exitfuncs ()
128- self .assertEqual (cm .unraisable .object , func )
135+ self .assertIsNone (cm .unraisable .object )
136+ self .assertEqual (cm .unraisable .err_msg ,
137+ f'Exception ignored in atexit callback { func !r} ' )
129138 self .assertEqual (cm .unraisable .exc_type , ZeroDivisionError )
130139 self .assertEqual (type (cm .unraisable .exc_value ), ZeroDivisionError )
131140 finally :
132141 atexit .unregister (func )
133142
143+ @unittest .skip ("TODO: RUSTPYTHON; Hangs" )
144+ def test_eq_unregister_clear (self ):
145+ # Issue #112127: callback's __eq__ may call unregister or _clear
146+ class Evil :
147+ def __eq__ (self , other ):
148+ action (other )
149+ return NotImplemented
150+
151+ for action in atexit .unregister , lambda o : atexit ._clear ():
152+ with self .subTest (action = action ):
153+ atexit .register (lambda : None )
154+ atexit .unregister (Evil ())
155+ atexit ._clear ()
156+
157+ @unittest .skip ("TODO: RUSTPYTHON; Hangs" )
158+ def test_eq_unregister (self ):
159+ # Issue #112127: callback's __eq__ may call unregister
160+ def f1 ():
161+ log .append (1 )
162+ def f2 ():
163+ log .append (2 )
164+ def f3 ():
165+ log .append (3 )
166+
167+ class Pred :
168+ def __eq__ (self , other ):
169+ nonlocal cnt
170+ cnt += 1
171+ if cnt == when :
172+ atexit .unregister (what )
173+ if other is f2 :
174+ return True
175+ return False
176+
177+ for what , expected in (
178+ (f1 , [3 ]),
179+ (f2 , [3 , 1 ]),
180+ (f3 , [1 ]),
181+ ):
182+ for when in range (1 , 4 ):
183+ with self .subTest (what = what .__name__ , when = when ):
184+ cnt = 0
185+ log = []
186+ for f in (f1 , f2 , f3 ):
187+ atexit .register (f )
188+ atexit .unregister (Pred ())
189+ atexit ._run_exitfuncs ()
190+ self .assertEqual (log , expected )
191+
134192
135193if __name__ == "__main__" :
136194 unittest .main ()
0 commit comments