@@ -448,3 +448,59 @@ def conflict(self) -> None:
448
448
"Hook 'conflict' is already registered within namespace "
449
449
"<class 'test_hookcaller.test_hook_conflict.<locals>.Api1'>"
450
450
)
451
+
452
+
453
+ def test_hook_multi_impl (pm : PluginManager ) -> None :
454
+ """Since plugins' impls are able to (optionally) specify a spec name, it is possible for a plugin to implement
455
+ the same spec multiple times."""
456
+
457
+ class Api :
458
+ @hookspec
459
+ def hello (self , arg : object ) -> None :
460
+ "api hook 1"
461
+
462
+ pm .add_hookspecs (Api )
463
+ hook = pm .hook
464
+ test_hc = hook .hello
465
+
466
+ class Plugin :
467
+ @hookimpl
468
+ def hello (self , arg ):
469
+ return arg + 1
470
+
471
+ @hookimpl (specname = "hello" )
472
+ def hello_again (self , arg ):
473
+ return arg + 100
474
+
475
+ plugin = Plugin ()
476
+
477
+ # Confirm that registration puts the impls into all the right registries
478
+ pm .register (plugin )
479
+ out = test_hc (arg = 3 )
480
+ assert out == [103 , 4 ]
481
+
482
+ assert len (pm .get_plugins ()) == 1
483
+
484
+ hookimpls = test_hc .get_hookimpls ()
485
+ hook_plugins = [item .plugin for item in hookimpls ]
486
+ assert hook_plugins == [plugin , plugin ]
487
+ for impl in hookimpls :
488
+ pm ._verify_hook (test_hc , impl )
489
+
490
+ hook_callers = pm .get_hookcallers (plugin )
491
+ assert (
492
+ len (hook_callers ) == 2
493
+ ), "This should return two callers. Same spec but different impls."
494
+ assert hook_callers [0 ].spec == hook_callers [1 ].spec
495
+
496
+ subset_caller = pm .subset_hook_caller ("hello" , [plugin ])
497
+ out = subset_caller (arg = 3 )
498
+ assert out == []
499
+
500
+ # Confirm that 'unregistering' does the converse
501
+ pm .unregister (plugin )
502
+ assert test_hc (arg = 3 ) == []
503
+ hookimpls = test_hc .get_hookimpls ()
504
+ assert hookimpls == []
505
+ hook_callers = pm .get_hookcallers (plugin )
506
+ assert hook_callers is None
0 commit comments