def__call__(self,*args,**kwargs):if args:raise TypeError("hook calling supports only keyword arguments")assertnot self.is_historic()if self.spec and self.spec.argnames:
notincall =(set(self.spec.argnames)-set(["__multicall__"])-set(kwargs.keys()))if notincall:
warnings.warn("Argument(s) {} which are declared in the hookspec ""can not be found in this hook call".format(tuple(notincall)),
stacklevel=2,)return self._hookexec(self, self.get_hookimpls(), kwargs)
if hook isNone:
hook = _HookCaller(name, self._hookexec)
这是PluginManager类的一个方法,找到该方法,发现只是一个封装,继续往上找
def_hookexec(self, hook, methods, kwargs):# called from all hookcaller instances.# enable_tracing will set its own wrapping function at self._inner_hookexecreturn self._inner_hookexec(hook, methods, kwargs)
def_multicall(hook_impls, caller_kwargs, firstresult=False):"""Execute a call into multiple python functions/methods and return the
result(s).
``caller_kwargs`` comes from _HookCaller.__call__().
"""
__tracebackhide__ =True
results =[]
excinfo =Nonetry:# run impl and wrapper setup functions in a loop
teardowns =[]try:for hook_impl inreversed(hook_impls):try:
args =[caller_kwargs[argname]for argname in hook_impl.argnames]except KeyError:for argname in hook_impl.argnames:if argname notin caller_kwargs:raise HookCallError("hook call must provide argument %r"%(argname,))
if hook_impl.hookwrapper:try:
gen = hook_impl.function(*args)next(gen)# first yield
teardowns.append(gen)except StopIteration:
_raise_wrapfail(gen,"did not yield")else:
res = hook_impl.function(*args)if res isnotNone:
results.append(res)if firstresult:# halt further impl callsbreak
gen = hook_impl.function(*args)执行plugin function中yield前的部分,然后停下
next(gen)迭代到plugin function中yield后面的部分
将gen得到的generator加到teardown中,用于后续的callback
nonwrapper
直接调用plugin function
将执行结果保存到result中
finally:if firstresult:# first result hooks return a single value
outcome = _Result(results[0]if results elseNone, excinfo)else:
outcome = _Result(results, excinfo)# run all wrapper post-yield blocksfor gen inreversed(teardowns):try:
gen.send(outcome)
_raise_wrapfail(gen,"has second yield")except StopIteration:passreturn outcome.get_result()
class_Result(object):def__init__(self, result, excinfo):
self._result = result
self._excinfo = excinfo
还有主要方法get_result()
defget_result(self):"""Get the result(s) for this hook call.
If the hook was marked as a ``firstresult`` only a single value
will be returned otherwise a list of results.
"""
__tracebackhide__ =Trueif self._excinfo isNone:return self._result
else:
ex = self._excinfo
if _py3:raise ex[1].with_traceback(ex[2])
_reraise(*ex)# noqa