@@ -336,5 +336,98 @@ def test_no_more_ids_available(self):
336336 self .add_watcher ()
337337
338338
339+ class TestFuncWatchers (unittest .TestCase ):
340+ @contextmanager
341+ def add_watcher (self , func ):
342+ wid = _testcapi .add_func_watcher (func )
343+ try :
344+ yield
345+ finally :
346+ _testcapi .clear_func_watcher (wid )
347+
348+ def test_func_events_dispatched (self ):
349+ events = []
350+ def watcher (* args ):
351+ events .append (args )
352+
353+ with self .add_watcher (watcher ):
354+ def myfunc ():
355+ pass
356+ self .assertIn ((_testcapi .PYFUNC_EVENT_CREATE , myfunc , None ), events )
357+ myfunc_id = id (myfunc )
358+
359+ new_code = self .test_func_events_dispatched .__code__
360+ myfunc .__code__ = new_code
361+ self .assertIn ((_testcapi .PYFUNC_EVENT_MODIFY_CODE , myfunc , new_code ), events )
362+
363+ new_defaults = (123 ,)
364+ myfunc .__defaults__ = new_defaults
365+ self .assertIn ((_testcapi .PYFUNC_EVENT_MODIFY_DEFAULTS , myfunc , new_defaults ), events )
366+
367+ new_defaults = (456 ,)
368+ _testcapi .set_func_defaults_via_capi (myfunc , new_defaults )
369+ self .assertIn ((_testcapi .PYFUNC_EVENT_MODIFY_DEFAULTS , myfunc , new_defaults ), events )
370+
371+ new_kwdefaults = {"self" : 123 }
372+ myfunc .__kwdefaults__ = new_kwdefaults
373+ self .assertIn ((_testcapi .PYFUNC_EVENT_MODIFY_KWDEFAULTS , myfunc , new_kwdefaults ), events )
374+
375+ new_kwdefaults = {"self" : 456 }
376+ _testcapi .set_func_kwdefaults_via_capi (myfunc , new_kwdefaults )
377+ self .assertIn ((_testcapi .PYFUNC_EVENT_MODIFY_KWDEFAULTS , myfunc , new_kwdefaults ), events )
378+
379+ # Clear events reference to func
380+ events = []
381+ del myfunc
382+ self .assertIn ((_testcapi .PYFUNC_EVENT_DESTROY , myfunc_id , None ), events )
383+
384+ def test_multiple_watchers (self ):
385+ events0 = []
386+ def first_watcher (* args ):
387+ events0 .append (args )
388+
389+ events1 = []
390+ def second_watcher (* args ):
391+ events1 .append (args )
392+
393+ with self .add_watcher (first_watcher ):
394+ with self .add_watcher (second_watcher ):
395+ def myfunc ():
396+ pass
397+
398+ event = (_testcapi .PYFUNC_EVENT_CREATE , myfunc , None )
399+ self .assertIn (event , events0 )
400+ self .assertIn (event , events1 )
401+
402+ def test_watcher_raises_error (self ):
403+ class MyError (Exception ):
404+ pass
405+
406+ def watcher (* args ):
407+ raise MyError ("testing 123" )
408+
409+ with self .add_watcher (watcher ):
410+ with catch_unraisable_exception () as cm :
411+ def myfunc ():
412+ pass
413+
414+ self .assertIs (cm .unraisable .object , myfunc )
415+ self .assertIsInstance (cm .unraisable .exc_value , MyError )
416+
417+ def test_clear_out_of_range_watcher_id (self ):
418+ with self .assertRaisesRegex (ValueError , r"invalid func watcher ID -1" ):
419+ _testcapi .clear_func_watcher (- 1 )
420+ with self .assertRaisesRegex (ValueError , r"invalid func watcher ID 8" ):
421+ _testcapi .clear_func_watcher (8 ) # FUNC_MAX_WATCHERS = 8
422+
423+ def test_clear_unassigned_watcher_id (self ):
424+ with self .assertRaisesRegex (ValueError , r"no func watcher set for ID 1" ):
425+ _testcapi .clear_func_watcher (1 )
426+
427+ def test_allocate_too_many_watchers (self ):
428+ with self .assertRaisesRegex (RuntimeError , r"no more func watcher IDs" ):
429+ _testcapi .allocate_too_many_func_watchers ()
430+
431+
339432if __name__ == "__main__" :
340433 unittest .main ()
0 commit comments