summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgoodboy <291685+goodboy@users.noreply.github.com>2020-07-02 09:15:31 -0500
committerGitHub <noreply@github.com>2020-07-02 09:15:31 -0500
commit0a064fe275060dbdb1fe6e10c888e72bc400fb33 (patch)
tree278fcbcc1fee9f0eced27996fb61587ffe7853dd
parent656bc3d04d3b452d501cfd955c53c5e724a61bc5 (diff)
parent0aa2462ebd8639fe888a7a632b2f16727c2702b3 (diff)
downloadpluggy-0a064fe275060dbdb1fe6e10c888e72bc400fb33.tar.gz
Merge pull request #280 from bluetech/optimize-call2
Optimize hook calling a bit
-rw-r--r--src/pluggy/callers.py2
-rw-r--r--src/pluggy/hooks.py34
-rw-r--r--src/pluggy/manager.py20
-rw-r--r--testing/benchmark.py25
-rw-r--r--testing/test_multicall.py2
5 files changed, 44 insertions, 39 deletions
diff --git a/src/pluggy/callers.py b/src/pluggy/callers.py
index f66cc94..f4719fa 100644
--- a/src/pluggy/callers.py
+++ b/src/pluggy/callers.py
@@ -6,7 +6,7 @@ import sys
from ._result import HookCallError, _Result, _raise_wrapfail
-def _multicall(hook_impls, caller_kwargs, firstresult=False):
+def _multicall(hook_name, hook_impls, caller_kwargs, firstresult):
"""Execute a call into multiple python functions/methods and return the
result(s).
diff --git a/src/pluggy/hooks.py b/src/pluggy/hooks.py
index 572c02e..cbd1022 100644
--- a/src/pluggy/hooks.py
+++ b/src/pluggy/hooks.py
@@ -247,15 +247,23 @@ class _HookCaller:
raise TypeError("hook calling supports only keyword arguments")
assert not self.is_historic()
- if self.spec and self.spec.argnames:
- notincall = set(self.spec.argnames) - 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)
+ # This is written to avoid expensive operations when not needed.
+ if self.spec:
+ for argname in self.spec.argnames:
+ if argname not in kwargs:
+ notincall = tuple(set(self.spec.argnames) - kwargs.keys())
+ warnings.warn(
+ "Argument(s) {} which are declared in the hookspec "
+ "can not be found in this hook call".format(notincall),
+ stacklevel=2,
+ )
+ break
+
+ firstresult = self.spec.opts.get("firstresult")
+ else:
+ firstresult = False
+
+ return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
def call_historic(self, result_callback=None, kwargs=None):
"""Call the hook with given ``kwargs`` for all registered plugins and
@@ -265,11 +273,11 @@ class _HookCaller:
non-``None`` result obtained from a hook implementation.
"""
self._call_history.append((kwargs or {}, result_callback))
- # historizing hooks don't return results
- res = self._hookexec(self, self.get_hookimpls(), kwargs)
+ # Historizing hooks don't return results.
+ # Remember firstresult isn't compatible with historic.
+ res = self._hookexec(self.name, self.get_hookimpls(), kwargs, False)
if result_callback is None:
return
- # XXX: remember firstresult isn't compat with historic
for x in res or []:
result_callback(x)
@@ -291,7 +299,7 @@ class _HookCaller:
"""
if self.is_historic():
for kwargs, result_callback in self._call_history:
- res = self._hookexec(self, [method], kwargs)
+ res = self._hookexec(self.name, [method], kwargs, False)
if res and result_callback is not None:
result_callback(res[0])
diff --git a/src/pluggy/manager.py b/src/pluggy/manager.py
index 7f37822..bba2f95 100644
--- a/src/pluggy/manager.py
+++ b/src/pluggy/manager.py
@@ -71,16 +71,12 @@ class PluginManager:
self._plugin_distinfo = []
self.trace = _tracing.TagTracer().get("pluginmanage")
self.hook = _HookRelay()
- self._inner_hookexec = lambda hook, methods, kwargs: _multicall(
- methods,
- kwargs,
- firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
- )
+ self._inner_hookexec = _multicall
- def _hookexec(self, hook, methods, kwargs):
+ def _hookexec(self, hook_name, methods, kwargs, firstresult):
# called from all hookcaller instances.
# enable_tracing will set its own wrapping function at self._inner_hookexec
- return self._inner_hookexec(hook, methods, kwargs)
+ return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
def register(self, plugin, name=None):
""" Register a plugin and return its canonical name or ``None`` if the name
@@ -311,10 +307,12 @@ class PluginManager:
"""
oldcall = self._inner_hookexec
- def traced_hookexec(hook, hook_impls, kwargs):
- before(hook.name, hook_impls, kwargs)
- outcome = _Result.from_call(lambda: oldcall(hook, hook_impls, kwargs))
- after(outcome, hook.name, hook_impls, kwargs)
+ def traced_hookexec(hook_name, hook_impls, kwargs, firstresult):
+ before(hook_name, hook_impls, kwargs)
+ outcome = _Result.from_call(
+ lambda: oldcall(hook_name, hook_impls, kwargs, firstresult)
+ )
+ after(outcome, hook_name, hook_impls, kwargs)
return outcome.get_result()
self._inner_hookexec = traced_hookexec
diff --git a/testing/benchmark.py b/testing/benchmark.py
index cca4a75..7eec411 100644
--- a/testing/benchmark.py
+++ b/testing/benchmark.py
@@ -6,18 +6,11 @@ from pluggy import HookspecMarker, HookimplMarker
from pluggy.hooks import HookImpl
from pluggy.callers import _multicall
+
hookspec = HookspecMarker("example")
hookimpl = HookimplMarker("example")
-def MC(methods, kwargs, firstresult=False):
- hookfuncs = []
- for method in methods:
- f = HookImpl(None, "<temp>", method, method.example_impl)
- hookfuncs.append(f)
- return _multicall(hookfuncs, kwargs, firstresult=firstresult)
-
-
@hookimpl
def hook(arg1, arg2, arg3):
return arg1, arg2, arg3
@@ -38,9 +31,15 @@ def wrappers(request):
return [wrapper for i in range(request.param)]
-def inner_exec(methods):
- return MC(methods, {"arg1": 1, "arg2": 2, "arg3": 3})
-
-
def test_hook_and_wrappers_speed(benchmark, hooks, wrappers):
- benchmark(inner_exec, hooks + wrappers)
+ def setup():
+ hook_name = "foo"
+ hook_impls = []
+ for method in hooks + wrappers:
+ f = HookImpl(None, "<temp>", method, method.example_impl)
+ hook_impls.append(f)
+ caller_kwargs = {"arg1": 1, "arg2": 2, "arg3": 3}
+ firstresult = False
+ return (hook_name, hook_impls, caller_kwargs, firstresult), {}
+
+ benchmark.pedantic(_multicall, setup=setup)
diff --git a/testing/test_multicall.py b/testing/test_multicall.py
index 79f179f..554ed19 100644
--- a/testing/test_multicall.py
+++ b/testing/test_multicall.py
@@ -14,7 +14,7 @@ def MC(methods, kwargs, firstresult=False):
for method in methods:
f = HookImpl(None, "<temp>", method, method.example_impl)
hookfuncs.append(f)
- return caller(hookfuncs, kwargs, firstresult=firstresult)
+ return caller("foo", hookfuncs, kwargs, firstresult)
def test_keyword_args():