Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pluggy/_callers.py: 8%
40 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
1"""
2Call loop machinery
3"""
4import sys
6from ._result import HookCallError, _Result, _raise_wrapfail
9def _multicall(hook_name, hook_impls, caller_kwargs, firstresult):
10 """Execute a call into multiple python functions/methods and return the
11 result(s).
13 ``caller_kwargs`` comes from _HookCaller.__call__().
14 """
15 __tracebackhide__ = True
16 results = []
17 excinfo = None
18 try: # run impl and wrapper setup functions in a loop
19 teardowns = []
20 try:
21 for hook_impl in reversed(hook_impls):
22 try:
23 args = [caller_kwargs[argname] for argname in hook_impl.argnames]
24 except KeyError:
25 for argname in hook_impl.argnames:
26 if argname not in caller_kwargs:
27 raise HookCallError(
28 f"hook call must provide argument {argname!r}"
29 )
31 if hook_impl.hookwrapper:
32 try:
33 gen = hook_impl.function(*args)
34 next(gen) # first yield
35 teardowns.append(gen)
36 except StopIteration:
37 _raise_wrapfail(gen, "did not yield")
38 else:
39 res = hook_impl.function(*args)
40 if res is not None:
41 results.append(res)
42 if firstresult: # halt further impl calls
43 break
44 except BaseException:
45 excinfo = sys.exc_info()
46 finally:
47 if firstresult: # first result hooks return a single value
48 outcome = _Result(results[0] if results else None, excinfo)
49 else:
50 outcome = _Result(results, excinfo)
52 # run all wrapper post-yield blocks
53 for gen in reversed(teardowns):
54 try:
55 gen.send(outcome)
56 _raise_wrapfail(gen, "has second yield")
57 except StopIteration:
58 pass
60 return outcome.get_result()