optimize argument slicing when calling plugin hooks

This commit is contained in:
holger krekel 2014-10-01 14:55:54 +02:00
parent f250e912eb
commit c7c4f62f77
3 changed files with 17 additions and 17 deletions

View File

@ -292,6 +292,7 @@ class MultiCall:
def __init__(self, methods, kwargs, firstresult=False):
self.methods = list(methods)
self.kwargs = kwargs
self.kwargs["__multicall__"] = self
self.results = []
self.firstresult = firstresult
@ -302,11 +303,12 @@ class MultiCall:
def execute(self):
next_finalizers = []
try:
all_kwargs = self.kwargs
while self.methods:
method = self.methods.pop()
kwargs = self.getkwargs(method)
args = [all_kwargs[argname] for argname in varnames(method)]
if hasattr(method, "hookwrapper"):
it = method(**kwargs)
it = method(*args)
next = getattr(it, "next", None)
if next is None:
next = getattr(it, "__next__", None)
@ -316,7 +318,7 @@ class MultiCall:
res = next()
next_finalizers.append((method, next))
else:
res = method(**kwargs)
res = method(*args)
if res is not None:
self.results.append(res)
if self.firstresult:
@ -334,16 +336,6 @@ class MultiCall:
"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):
""" 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]
except AttributeError:
x = ()
else:
defaults = func.__defaults__
if defaults:
x = x[:-len(defaults)]
try:
cache["_varnames"] = x
except TypeError:
pass
return x
class HookRelay:
def __init__(self, hookspecs, pm, prefix="pytest_"):
if not isinstance(hookspecs, list):

View File

@ -142,7 +142,7 @@ def pytest_generate_tests(metafunc):
# -------------------------------------------------------------------------
# generic runtest related hooks
# -------------------------------------------------------------------------
def pytest_itemstart(item, node=None):
def pytest_itemstart(item, node):
""" (deprecated, use pytest_runtest_logstart). """
def pytest_runtest_protocol(item, nextitem):

View File

@ -436,6 +436,11 @@ def test_varnames():
assert varnames(A().f) == ('y',)
assert varnames(B()) == ('z',)
def test_varnames_default():
def f(x, y=3):
pass
assert varnames(f) == ("x",)
def test_varnames_class():
class C:
def __init__(self, x):
@ -494,12 +499,10 @@ class TestMultiCall:
return x + z
reslist = MultiCall([f], dict(x=23, y=24)).execute()
assert reslist == [24]
reslist = MultiCall([f], dict(x=23, z=2)).execute()
assert reslist == [25]
def test_tags_call_error(self):
multicall = MultiCall([lambda x: x], {})
pytest.raises(TypeError, multicall.execute)
pytest.raises(KeyError, multicall.execute)
def test_call_subexecute(self):
def m(__multicall__):