@@ -342,8 +342,8 @@ def __init__(self, project_name, implprefix=None):
342342 self ._implprefix = implprefix
343343 self ._inner_hookexec = lambda hook , methods , kwargs : \
344344 _MultiCall (
345- methods , kwargs , specopts = hook .spec_opts , hook = hook
346- ).execute ()
345+ methods , kwargs , firstresult = hook .spec . opts [ 'firstresult' ],
346+ hook = hook ).execute ()
347347
348348 def _hookexec (self , hook , methods , kwargs ):
349349 # called from all hookcaller instances.
@@ -490,7 +490,7 @@ def _verify_hook(self, hook, hookimpl):
490490 (hookimpl .plugin_name , hook .name ))
491491
492492 # positional arg checking
493- notinspec = set (hookimpl .argnames ) - set (hook .argnames )
493+ notinspec = set (hookimpl .argnames ) - set (hook .spec . argnames )
494494 if notinspec :
495495 raise PluginValidationError (
496496 "Plugin %r for hook %r\n hookimpl definition: %s\n "
@@ -583,8 +583,8 @@ def subset_hook_caller(self, name, remove_plugins):
583583 orig = getattr (self .hook , name )
584584 plugins_to_remove = [plug for plug in remove_plugins if hasattr (plug , name )]
585585 if plugins_to_remove :
586- hc = _HookCaller (orig .name , orig ._hookexec , orig ._specmodule_or_class ,
587- orig .spec_opts )
586+ hc = _HookCaller (orig .name , orig ._hookexec , orig .spec . namespace ,
587+ orig .spec . opts )
588588 for hookimpl in (orig ._wrappers + orig ._nonwrappers ):
589589 plugin = hookimpl .plugin
590590 if plugin not in plugins_to_remove :
@@ -605,29 +605,40 @@ class _MultiCall:
605605 # so we can remove it soon, allowing to avoid the below recursion
606606 # in execute() and simplify/speed up the execute loop.
607607
608- def __init__ (self , hook_impls , kwargs , specopts = {} , hook = None ):
608+ def __init__ (self , hook_impls , kwargs , firstresult = False , hook = None ):
609609 self .hook = hook
610610 self .hook_impls = hook_impls
611611 self .caller_kwargs = kwargs # come from _HookCaller.__call__()
612612 self .caller_kwargs ["__multicall__" ] = self
613- self .specopts = hook . spec_opts if hook else specopts
613+ self .firstresult = firstresult
614614
615615 def execute (self ):
616616 caller_kwargs = self .caller_kwargs
617617 self .results = results = []
618- firstresult = self .specopts . get ( " firstresult" )
618+ firstresult = self .firstresult
619619
620620 while self .hook_impls :
621621 hook_impl = self .hook_impls .pop ()
622622 try :
623623 args = [caller_kwargs [argname ] for argname in hook_impl .argnames ]
624+ # get any caller provided kwargs declared in our
625+ # hookimpl and fail over to the spec's value if provided
626+ if self .hook and hook_impl .kwargnames :
627+ args += [
628+ caller_kwargs .get (
629+ argname , self .hook .spec .kwargs .get (
630+ argname , hook_impl .kwargs [argname ]))
631+ for argname in hook_impl .kwargnames
632+ ]
624633 except KeyError :
625634 for argname in hook_impl .argnames :
626635 if argname not in caller_kwargs :
627636 raise HookCallError (
628637 "hook call must provide argument %r" % (argname ,))
638+
629639 if hook_impl .hookwrapper :
630640 return _wrapped_call (hook_impl .function (* args ), self .execute )
641+
631642 res = hook_impl .function (* args )
632643 if res is not None :
633644 if firstresult :
@@ -711,28 +722,23 @@ def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None)
711722 self ._wrappers = []
712723 self ._nonwrappers = []
713724 self ._hookexec = hook_execute
714- self .argnames = None
715- self .kwargnames = None
725+ self .spec = None
726+ self ._call_history = None
716727 if specmodule_or_class is not None :
717728 assert spec_opts is not None
718729 self .set_specification (specmodule_or_class , spec_opts )
719730
720731 def has_spec (self ):
721- return hasattr ( self , "_specmodule_or_class" )
732+ return self . spec is not None
722733
723734 def set_specification (self , specmodule_or_class , spec_opts ):
724735 assert not self .has_spec ()
725- self ._specmodule_or_class = specmodule_or_class
726- specfunc = getattr (specmodule_or_class , self .name )
727- # get spec arg signature
728- argnames , self .kwargnames = varnames (specfunc )
729- self .argnames = ["__multicall__" ] + list (argnames )
730- self .spec_opts = spec_opts
736+ self .spec = HookSpec (specmodule_or_class , self .name , spec_opts )
731737 if spec_opts .get ("historic" ):
732738 self ._call_history = []
733739
734740 def is_historic (self ):
735- return hasattr ( self , " _call_history" )
741+ return self . _call_history is not None
736742
737743 def _remove_plugin (self , plugin ):
738744 def remove (wrappers ):
@@ -768,7 +774,7 @@ def __repr__(self):
768774
769775 def __call__ (self , ** kwargs ):
770776 assert not self .is_historic ()
771- notincall = set (self .argnames ) - set (kwargs .keys ())
777+ notincall = set (self .spec . argnames ) - set (kwargs .keys ())
772778 if notincall :
773779 warnings .warn (
774780 "Positional arg(s) %s are declared in the hookspec "
@@ -813,10 +819,30 @@ def _maybe_apply_history(self, method):
813819 proc (res [0 ])
814820
815821
822+ class HookSpec :
823+ def __init__ (self , namespace , name , hook_spec_opts ):
824+ self .namespace = namespace
825+ self .function = function = getattr (namespace , name )
826+ self .name = name
827+ self .argnames , self .kwargnames = varnames (function )
828+ self .kwargvalues = inspect .getargspec (function ).defaults
829+ self .kwargs = dict (
830+ ((name , value ) for name , value in
831+ zip (self .kwargnames , inspect .getargspec (function ).defaults ))
832+ ) if self .kwargvalues else {}
833+ self .opts = hook_spec_opts
834+ self .argnames = ["__multicall__" ] + list (self .argnames )
835+
836+
816837class HookImpl :
817838 def __init__ (self , plugin , plugin_name , function , hook_impl_opts ):
818839 self .function = function
819840 self .argnames , self .kwargnames = varnames (self .function )
841+ self .kwargvalues = inspect .getargspec (function ).defaults
842+ self .kwargs = dict (
843+ ((name , value ) for name , value in
844+ zip (self .kwargnames , inspect .getargspec (function ).defaults ))
845+ ) if self .kwargvalues else {}
820846 self .plugin = plugin
821847 self .opts = hook_impl_opts
822848 self .plugin_name = plugin_name
0 commit comments