@@ -231,7 +231,10 @@ def __init__(self, project_name, implprefix=None):
231231 self ._implprefix = implprefix
232232 self ._inner_hookexec = lambda hook , methods , kwargs : \
233233 hook .multicall (
234- methods , kwargs , specopts = hook .spec_opts , hook = hook
234+ methods ,
235+ kwargs ,
236+ specopts = hook .spec .opts ['firstresult' ] if hook .spec else False ,
237+ hook = hook
235238 ).execute ()
236239
237240 def _hookexec (self , hook , methods , kwargs ):
@@ -379,7 +382,7 @@ def _verify_hook(self, hook, hookimpl):
379382 (hookimpl .plugin_name , hook .name ))
380383
381384 # positional arg checking
382- notinspec = set (hookimpl .argnames ) - set (hook .argnames )
385+ notinspec = set (hookimpl .argnames ) - set (hook .spec . argnames )
383386 if notinspec :
384387 raise PluginValidationError (
385388 "Plugin %r for hook %r\n hookimpl definition: %s\n "
@@ -472,8 +475,8 @@ def subset_hook_caller(self, name, remove_plugins):
472475 orig = getattr (self .hook , name )
473476 plugins_to_remove = [plug for plug in remove_plugins if hasattr (plug , name )]
474477 if plugins_to_remove :
475- hc = _HookCaller (orig .name , orig ._hookexec , orig ._specmodule_or_class ,
476- orig .spec_opts )
478+ hc = _HookCaller (orig .name , orig ._hookexec , orig .spec . namespace ,
479+ orig .spec . opts )
477480 for hookimpl in (orig ._wrappers + orig ._nonwrappers ):
478481 plugin = hookimpl .plugin
479482 if plugin not in plugins_to_remove :
@@ -494,17 +497,18 @@ class _LegacyMultiCall(object):
494497 # so we can remove it soon, allowing to avoid the below recursion
495498 # in execute() and simplify/speed up the execute loop.
496499
497- def __init__ (self , hook_impls , kwargs , specopts = {}, hook = None ):
498- self .hook = hook
500+ def __init__ (self , hook_impls , kwargs , firstresult = False , hook = None ):
499501 self .hook_impls = hook_impls
500502 self .caller_kwargs = kwargs # come from _HookCaller.__call__()
501503 self .caller_kwargs ["__multicall__" ] = self
502- self .specopts = hook .spec_opts if hook else specopts
504+ self .firstresult = firstresult
505+ self .hook = hook
506+ self .spec = hook .spec if hook else None
503507
504508 def execute (self ):
505509 caller_kwargs = self .caller_kwargs
506510 self .results = results = []
507- firstresult = self .specopts . get ( " firstresult" )
511+ firstresult = self .firstresult
508512
509513 while self .hook_impls :
510514 hook_impl = self .hook_impls .pop ()
@@ -515,8 +519,10 @@ def execute(self):
515519 if argname not in caller_kwargs :
516520 raise HookCallError (
517521 "hook call must provide argument %r" % (argname ,))
522+
518523 if hook_impl .hookwrapper :
519524 return _wrapped_call (hook_impl .function (* args ), self .execute )
525+
520526 res = hook_impl .function (* args )
521527 if res is not None :
522528 if firstresult :
@@ -603,26 +609,23 @@ def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None)
603609 self .argnames = None
604610 self .kwargnames = None
605611 self .multicall = _MultiCall
612+ self .spec = None
613+ self ._call_history = None
606614 if specmodule_or_class is not None :
607615 assert spec_opts is not None
608616 self .set_specification (specmodule_or_class , spec_opts )
609617
610618 def has_spec (self ):
611- return hasattr ( self , "_specmodule_or_class" )
619+ return self . spec is not None
612620
613621 def set_specification (self , specmodule_or_class , spec_opts ):
614622 assert not self .has_spec ()
615- self ._specmodule_or_class = specmodule_or_class
616- specfunc = getattr (specmodule_or_class , self .name )
617- # get spec arg signature
618- argnames , self .kwargnames = varnames (specfunc )
619- self .argnames = ["__multicall__" ] + list (argnames )
620- self .spec_opts = spec_opts
623+ self .spec = HookSpec (specmodule_or_class , self .name , spec_opts )
621624 if spec_opts .get ("historic" ):
622625 self ._call_history = []
623626
624627 def is_historic (self ):
625- return hasattr ( self , " _call_history" )
628+ return self . _call_history is not None
626629
627630 def _remove_plugin (self , plugin ):
628631 def remove (wrappers ):
@@ -668,8 +671,8 @@ def __call__(self, *args, **kwargs):
668671 if args :
669672 raise TypeError ("hook calling supports only keyword arguments" )
670673 assert not self .is_historic ()
671- if self .argnames :
672- notincall = set (self .argnames ) - set (['__multicall__' ]) - set (
674+ if self .spec :
675+ notincall = set (self .spec . argnames ) - set (['__multicall__' ]) - set (
673676 kwargs .keys ())
674677 if notincall :
675678 warnings .warn (
@@ -715,6 +718,16 @@ def _maybe_apply_history(self, method):
715718 proc (res [0 ])
716719
717720
721+ class HookSpec (object ):
722+ def __init__ (self , namespace , name , opts ):
723+ self .namespace = namespace
724+ self .function = function = getattr (namespace , name )
725+ self .name = name
726+ self .argnames , self .kwargnames = varnames (function )
727+ self .opts = opts
728+ self .argnames = ["__multicall__" ] + list (self .argnames )
729+
730+
718731class HookImpl (object ):
719732 def __init__ (self , plugin , plugin_name , function , hook_impl_opts ):
720733 self .function = function
0 commit comments