@@ -341,8 +341,8 @@ def __init__(self, project_name, implprefix=None):
341341 self ._implprefix = implprefix
342342 self ._inner_hookexec = lambda hook , methods , kwargs : \
343343 _MultiCall (
344- methods , kwargs , specopts = hook .spec_opts , hook = hook
345- ).execute ()
344+ methods , kwargs , firstresult = hook .spec . opts [ 'firstresult' ],
345+ hook = hook ).execute ()
346346
347347 def _hookexec (self , hook , methods , kwargs ):
348348 # called from all hookcaller instances.
@@ -489,7 +489,7 @@ def _verify_hook(self, hook, hookimpl):
489489 (hookimpl .plugin_name , hook .name ))
490490
491491 # positional arg checking
492- notinspec = set (hookimpl .argnames ) - set (hook .argnames )
492+ notinspec = set (hookimpl .argnames ) - set (hook .spec . argnames )
493493 if notinspec :
494494 raise PluginValidationError (
495495 "Plugin %r for hook %r\n hookimpl definition: %s\n "
@@ -582,8 +582,8 @@ def subset_hook_caller(self, name, remove_plugins):
582582 orig = getattr (self .hook , name )
583583 plugins_to_remove = [plug for plug in remove_plugins if hasattr (plug , name )]
584584 if plugins_to_remove :
585- hc = _HookCaller (orig .name , orig ._hookexec , orig ._specmodule_or_class ,
586- orig .spec_opts )
585+ hc = _HookCaller (orig .name , orig ._hookexec , orig .spec . namespace ,
586+ orig .spec . opts )
587587 for hookimpl in (orig ._wrappers + orig ._nonwrappers ):
588588 plugin = hookimpl .plugin
589589 if plugin not in plugins_to_remove :
@@ -604,29 +604,40 @@ class _MultiCall:
604604 # so we can remove it soon, allowing to avoid the below recursion
605605 # in execute() and simplify/speed up the execute loop.
606606
607- def __init__ (self , hook_impls , kwargs , specopts = {} , hook = None ):
607+ def __init__ (self , hook_impls , kwargs , firstresult = False , hook = None ):
608608 self .hook = hook
609609 self .hook_impls = hook_impls
610610 self .caller_kwargs = kwargs # come from _HookCaller.__call__()
611611 self .caller_kwargs ["__multicall__" ] = self
612- self .specopts = hook . spec_opts if hook else specopts
612+ self .firstresult = firstresult
613613
614614 def execute (self ):
615615 caller_kwargs = self .caller_kwargs
616616 self .results = results = []
617- firstresult = self .specopts . get ( " firstresult" )
617+ firstresult = self .firstresult
618618
619619 while self .hook_impls :
620620 hook_impl = self .hook_impls .pop ()
621621 try :
622622 args = [caller_kwargs [argname ] for argname in hook_impl .argnames ]
623+ # get any caller provided kwargs declared in our
624+ # hookimpl and fail over to the spec's value if provided
625+ if self .hook and hook_impl .kwargnames :
626+ args += [
627+ caller_kwargs .get (
628+ argname , self .hook .spec .kwargs .get (
629+ argname , hook_impl .kwargs [argname ]))
630+ for argname in hook_impl .kwargnames
631+ ]
623632 except KeyError :
624633 for argname in hook_impl .argnames :
625634 if argname not in caller_kwargs :
626635 raise HookCallError (
627636 "hook call must provide argument %r" % (argname ,))
637+
628638 if hook_impl .hookwrapper :
629639 return _wrapped_call (hook_impl .function (* args ), self .execute )
640+
630641 res = hook_impl .function (* args )
631642 if res is not None :
632643 if firstresult :
@@ -710,28 +721,23 @@ def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None)
710721 self ._wrappers = []
711722 self ._nonwrappers = []
712723 self ._hookexec = hook_execute
713- self .argnames = None
714- self .kwargnames = None
724+ self .spec = None
725+ self ._call_history = None
715726 if specmodule_or_class is not None :
716727 assert spec_opts is not None
717728 self .set_specification (specmodule_or_class , spec_opts )
718729
719730 def has_spec (self ):
720- return hasattr ( self , "_specmodule_or_class" )
731+ return self . spec is not None
721732
722733 def set_specification (self , specmodule_or_class , spec_opts ):
723734 assert not self .has_spec ()
724- self ._specmodule_or_class = specmodule_or_class
725- specfunc = getattr (specmodule_or_class , self .name )
726- # get spec arg signature
727- argnames , self .kwargnames = varnames (specfunc )
728- self .argnames = ["__multicall__" ] + list (argnames )
729- self .spec_opts = spec_opts
735+ self .spec = HookSpec (specmodule_or_class , self .name , spec_opts )
730736 if spec_opts .get ("historic" ):
731737 self ._call_history = []
732738
733739 def is_historic (self ):
734- return hasattr ( self , " _call_history" )
740+ return self . _call_history is not None
735741
736742 def _remove_plugin (self , plugin ):
737743 def remove (wrappers ):
@@ -767,7 +773,7 @@ def __repr__(self):
767773
768774 def __call__ (self , ** kwargs ):
769775 assert not self .is_historic ()
770- notincall = set (self .argnames ) - set (kwargs .keys ())
776+ notincall = set (self .spec . argnames ) - set (kwargs .keys ())
771777 if notincall :
772778 warnings .warn (
773779 "Positional arg(s) %s are declared in the hookspec "
@@ -812,10 +818,30 @@ def _maybe_apply_history(self, method):
812818 proc (res [0 ])
813819
814820
821+ class HookSpec :
822+ def __init__ (self , namespace , name , hook_spec_opts ):
823+ self .namespace = namespace
824+ self .function = function = getattr (namespace , name )
825+ self .name = name
826+ self .argnames , self .kwargnames = varnames (function )
827+ self .kwargvalues = inspect .getargspec (function ).defaults
828+ self .kwargs = dict (
829+ ((name , value ) for name , value in
830+ zip (self .kwargnames , inspect .getargspec (function ).defaults ))
831+ ) if self .kwargvalues else {}
832+ self .opts = hook_spec_opts
833+ self .argnames = ["__multicall__" ] + list (self .argnames )
834+
835+
815836class HookImpl :
816837 def __init__ (self , plugin , plugin_name , function , hook_impl_opts ):
817838 self .function = function
818839 self .argnames , self .kwargnames = varnames (self .function )
840+ self .kwargvalues = inspect .getargspec (function ).defaults
841+ self .kwargs = dict (
842+ ((name , value ) for name , value in
843+ zip (self .kwargnames , inspect .getargspec (function ).defaults ))
844+ ) if self .kwargvalues else {}
819845 self .plugin = plugin
820846 self .opts = hook_impl_opts
821847 self .plugin_name = plugin_name
0 commit comments