optimize argument slicing when calling plugin hooks
This commit is contained in:
parent
e635f9f9b2
commit
de83d35994
|
@ -292,6 +292,7 @@ class MultiCall:
|
||||||
def __init__(self, methods, kwargs, firstresult=False):
|
def __init__(self, methods, kwargs, firstresult=False):
|
||||||
self.methods = list(methods)
|
self.methods = list(methods)
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
self.kwargs["__multicall__"] = self
|
||||||
self.results = []
|
self.results = []
|
||||||
self.firstresult = firstresult
|
self.firstresult = firstresult
|
||||||
|
|
||||||
|
@ -302,11 +303,12 @@ class MultiCall:
|
||||||
def execute(self):
|
def execute(self):
|
||||||
next_finalizers = []
|
next_finalizers = []
|
||||||
try:
|
try:
|
||||||
|
all_kwargs = self.kwargs
|
||||||
while self.methods:
|
while self.methods:
|
||||||
method = self.methods.pop()
|
method = self.methods.pop()
|
||||||
kwargs = self.getkwargs(method)
|
args = [all_kwargs[argname] for argname in varnames(method)]
|
||||||
if hasattr(method, "hookwrapper"):
|
if hasattr(method, "hookwrapper"):
|
||||||
it = method(**kwargs)
|
it = method(*args)
|
||||||
next = getattr(it, "next", None)
|
next = getattr(it, "next", None)
|
||||||
if next is None:
|
if next is None:
|
||||||
next = getattr(it, "__next__", None)
|
next = getattr(it, "__next__", None)
|
||||||
|
@ -316,7 +318,7 @@ class MultiCall:
|
||||||
res = next()
|
res = next()
|
||||||
next_finalizers.append((method, next))
|
next_finalizers.append((method, next))
|
||||||
else:
|
else:
|
||||||
res = method(**kwargs)
|
res = method(*args)
|
||||||
if res is not None:
|
if res is not None:
|
||||||
self.results.append(res)
|
self.results.append(res)
|
||||||
if self.firstresult:
|
if self.firstresult:
|
||||||
|
@ -334,16 +336,6 @@ class MultiCall:
|
||||||
"wrapper contain more than one yield")
|
"wrapper contain more than one yield")
|
||||||
|
|
||||||
|
|
||||||
def getkwargs(self, method):
|
|
||||||
kwargs = {}
|
|
||||||
for argname in varnames(method):
|
|
||||||
try:
|
|
||||||
kwargs[argname] = self.kwargs[argname]
|
|
||||||
except KeyError:
|
|
||||||
if argname == "__multicall__":
|
|
||||||
kwargs[argname] = self
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
def varnames(func):
|
def varnames(func):
|
||||||
""" return argument name tuple for a function, method, class or callable.
|
""" return argument name tuple for a function, method, class or callable.
|
||||||
|
|
||||||
|
@ -371,12 +363,17 @@ def varnames(func):
|
||||||
x = rawcode.co_varnames[ismethod:rawcode.co_argcount]
|
x = rawcode.co_varnames[ismethod:rawcode.co_argcount]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
x = ()
|
x = ()
|
||||||
|
else:
|
||||||
|
defaults = func.__defaults__
|
||||||
|
if defaults:
|
||||||
|
x = x[:-len(defaults)]
|
||||||
try:
|
try:
|
||||||
cache["_varnames"] = x
|
cache["_varnames"] = x
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
class HookRelay:
|
class HookRelay:
|
||||||
def __init__(self, hookspecs, pm, prefix="pytest_"):
|
def __init__(self, hookspecs, pm, prefix="pytest_"):
|
||||||
if not isinstance(hookspecs, list):
|
if not isinstance(hookspecs, list):
|
||||||
|
|
|
@ -142,7 +142,7 @@ def pytest_generate_tests(metafunc):
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# generic runtest related hooks
|
# generic runtest related hooks
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
def pytest_itemstart(item, node=None):
|
def pytest_itemstart(item, node):
|
||||||
""" (deprecated, use pytest_runtest_logstart). """
|
""" (deprecated, use pytest_runtest_logstart). """
|
||||||
|
|
||||||
def pytest_runtest_protocol(item, nextitem):
|
def pytest_runtest_protocol(item, nextitem):
|
||||||
|
|
|
@ -436,6 +436,11 @@ def test_varnames():
|
||||||
assert varnames(A().f) == ('y',)
|
assert varnames(A().f) == ('y',)
|
||||||
assert varnames(B()) == ('z',)
|
assert varnames(B()) == ('z',)
|
||||||
|
|
||||||
|
def test_varnames_default():
|
||||||
|
def f(x, y=3):
|
||||||
|
pass
|
||||||
|
assert varnames(f) == ("x",)
|
||||||
|
|
||||||
def test_varnames_class():
|
def test_varnames_class():
|
||||||
class C:
|
class C:
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
|
@ -494,12 +499,10 @@ class TestMultiCall:
|
||||||
return x + z
|
return x + z
|
||||||
reslist = MultiCall([f], dict(x=23, y=24)).execute()
|
reslist = MultiCall([f], dict(x=23, y=24)).execute()
|
||||||
assert reslist == [24]
|
assert reslist == [24]
|
||||||
reslist = MultiCall([f], dict(x=23, z=2)).execute()
|
|
||||||
assert reslist == [25]
|
|
||||||
|
|
||||||
def test_tags_call_error(self):
|
def test_tags_call_error(self):
|
||||||
multicall = MultiCall([lambda x: x], {})
|
multicall = MultiCall([lambda x: x], {})
|
||||||
pytest.raises(TypeError, multicall.execute)
|
pytest.raises(KeyError, multicall.execute)
|
||||||
|
|
||||||
def test_call_subexecute(self):
|
def test_call_subexecute(self):
|
||||||
def m(__multicall__):
|
def m(__multicall__):
|
||||||
|
|
Loading…
Reference in New Issue