@@ -336,5 +336,98 @@ def test_no_more_ids_available(self):
336
336
self .add_watcher ()
337
337
338
338
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
+
339
432
if __name__ == "__main__" :
340
433
unittest .main ()
0 commit comments