remove overhead for tracing of hook calls and remove some old unused code
This commit is contained in:
parent
c7c4f62f77
commit
69ff29bf44
|
@ -98,7 +98,7 @@ class PytestPluginManager(PluginManager):
|
|||
err = py.io.dupfile(err, encoding=encoding)
|
||||
except Exception:
|
||||
pass
|
||||
self.trace.root.setwriter(err.write)
|
||||
self.set_tracing(err.write)
|
||||
|
||||
def pytest_configure(self, config):
|
||||
config.addinivalue_line("markers",
|
||||
|
|
|
@ -70,7 +70,6 @@ class TagTracerSub:
|
|||
class PluginManager(object):
|
||||
def __init__(self, hookspecs=None, prefix="pytest_"):
|
||||
self._name2plugin = {}
|
||||
self._listattrcache = {}
|
||||
self._plugins = []
|
||||
self._conftestplugins = []
|
||||
self._warnings = []
|
||||
|
@ -79,6 +78,26 @@ class PluginManager(object):
|
|||
self._shutdown = []
|
||||
self.hook = HookRelay(hookspecs or [], pm=self, prefix=prefix)
|
||||
|
||||
def set_tracing(self, writer):
|
||||
self.trace.root.setwriter(writer)
|
||||
# we reconfigure HookCalling to perform tracing
|
||||
# and we avoid doing the "do we need to trace" check dynamically
|
||||
# for speed reasons
|
||||
assert HookCaller._docall.__name__ == "_docall"
|
||||
real_docall = HookCaller._docall
|
||||
def docall_tracing(self, methods, kwargs):
|
||||
trace = self.hookrelay.trace
|
||||
trace.root.indent += 1
|
||||
trace(self.name, kwargs)
|
||||
try:
|
||||
res = real_docall(self, methods, kwargs)
|
||||
if res:
|
||||
trace("finish", self.name, "-->", res)
|
||||
finally:
|
||||
trace.root.indent -= 1
|
||||
return res
|
||||
HookCaller._docall = docall_tracing
|
||||
|
||||
def do_configure(self, config):
|
||||
# backward compatibility
|
||||
config.do_configure()
|
||||
|
@ -129,7 +148,6 @@ class PluginManager(object):
|
|||
func()
|
||||
self._plugins = self._conftestplugins = []
|
||||
self._name2plugin.clear()
|
||||
self._listattrcache.clear()
|
||||
|
||||
def isregistered(self, plugin, name=None):
|
||||
if self.getplugin(name) is not None:
|
||||
|
@ -261,7 +279,6 @@ class PluginManager(object):
|
|||
l.append(meth)
|
||||
l.extend(last)
|
||||
l.extend(wrappers)
|
||||
#self._listattrcache[key] = list(l)
|
||||
return l
|
||||
|
||||
def call_plugin(self, plugin, methname, kwargs):
|
||||
|
@ -336,7 +353,7 @@ class MultiCall:
|
|||
"wrapper contain more than one yield")
|
||||
|
||||
|
||||
def varnames(func):
|
||||
def varnames(func, startindex=None):
|
||||
""" return argument name tuple for a function, method, class or callable.
|
||||
|
||||
In case of a class, its "__init__" method is considered.
|
||||
|
@ -353,14 +370,16 @@ def varnames(func):
|
|||
func = func.__init__
|
||||
except AttributeError:
|
||||
return ()
|
||||
ismethod = True
|
||||
startindex = 1
|
||||
else:
|
||||
if not inspect.isfunction(func) and not inspect.ismethod(func):
|
||||
func = getattr(func, '__call__', func)
|
||||
ismethod = inspect.ismethod(func)
|
||||
if startindex is None:
|
||||
startindex = int(inspect.ismethod(func))
|
||||
|
||||
rawcode = py.code.getrawcode(func)
|
||||
try:
|
||||
x = rawcode.co_varnames[ismethod:rawcode.co_argcount]
|
||||
x = rawcode.co_varnames[startindex:rawcode.co_argcount]
|
||||
except AttributeError:
|
||||
x = ()
|
||||
else:
|
||||
|
@ -388,12 +407,12 @@ class HookRelay:
|
|||
def _addhooks(self, hookspec, prefix):
|
||||
self._hookspecs.append(hookspec)
|
||||
added = False
|
||||
for name in dir(hookspec):
|
||||
isclass = int(inspect.isclass(hookspec))
|
||||
for name, method in vars(hookspec).items():
|
||||
if name.startswith(prefix):
|
||||
method = getattr(hookspec, name)
|
||||
firstresult = getattr(method, 'firstresult', False)
|
||||
hc = HookCaller(self, name, firstresult=firstresult,
|
||||
argnames=varnames(method))
|
||||
argnames=varnames(method, startindex=isclass))
|
||||
setattr(self, name, hc)
|
||||
added = True
|
||||
#print ("setting new hook", name)
|
||||
|
@ -438,11 +457,10 @@ class HookCaller:
|
|||
self.hookrelay = hookrelay
|
||||
self.name = name
|
||||
self.firstresult = firstresult
|
||||
self.trace = self.hookrelay.trace
|
||||
self.methods = methods
|
||||
self.argnames = ["__multicall__"]
|
||||
self.argnames.extend(argnames)
|
||||
assert "self" not in argnames
|
||||
assert "self" not in argnames # prevent oversights
|
||||
|
||||
def new_cached_caller(self, methods):
|
||||
return HookCaller(self.hookrelay, self.name, self.firstresult,
|
||||
|
@ -461,22 +479,11 @@ class HookCaller:
|
|||
return self._docall(methods, kwargs)
|
||||
|
||||
def callextra(self, methods, **kwargs):
|
||||
#if self.methods is None:
|
||||
# self.reload_methods()
|
||||
return self._docall(self.methods + methods, kwargs)
|
||||
|
||||
def _docall(self, methods, kwargs):
|
||||
self.trace(self.name, kwargs)
|
||||
self.trace.root.indent += 1
|
||||
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
|
||||
try:
|
||||
res = mc.execute()
|
||||
if res:
|
||||
self.trace("finish", self.name, "-->", res)
|
||||
finally:
|
||||
self.trace.root.indent -= 1
|
||||
return res
|
||||
|
||||
return MultiCall(methods, kwargs,
|
||||
firstresult=self.firstresult).execute()
|
||||
|
||||
|
||||
class PluginValidationError(Exception):
|
||||
|
@ -486,13 +493,6 @@ def isgenerichook(name):
|
|||
return name == "pytest_plugins" or \
|
||||
name.startswith("pytest_funcarg__")
|
||||
|
||||
def collectattr(obj):
|
||||
methods = {}
|
||||
for apiname in dir(obj):
|
||||
if apiname.startswith("pytest_"):
|
||||
methods[apiname] = getattr(obj, apiname)
|
||||
return methods
|
||||
|
||||
def formatdef(func):
|
||||
return "%s%s" % (
|
||||
func.__name__,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
""" version info, help messages, tracing configuration. """
|
||||
import py
|
||||
import pytest
|
||||
import os, inspect, sys
|
||||
from _pytest.core import varnames
|
||||
import os, sys
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup('debugconfig')
|
||||
|
@ -32,7 +31,7 @@ def pytest_cmdline_parse(__multicall__):
|
|||
f.write("versions pytest-%s, py-%s, python-%s\ncwd=%s\nargs=%s\n\n" %(
|
||||
pytest.__version__, py.__version__, ".".join(map(str, sys.version_info)),
|
||||
os.getcwd(), config._origargs))
|
||||
config.trace.root.setwriter(f.write)
|
||||
config.pluginmanager.set_tracing(f.write)
|
||||
sys.stderr.write("writing pytestdebug information to %s\n" % path)
|
||||
return config
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ class TestBootstrapping:
|
|||
saveindent.append(pm.trace.root.indent)
|
||||
raise ValueError(42)
|
||||
l = []
|
||||
pm.trace.root.setwriter(l.append)
|
||||
pm.set_tracing(l.append)
|
||||
indent = pm.trace.root.indent
|
||||
p = api1()
|
||||
pm.register(p)
|
||||
|
@ -405,11 +405,7 @@ class TestPytestPluginInteractions:
|
|||
pluginmanager.register(p3)
|
||||
methods = pluginmanager.listattr('m')
|
||||
assert methods == [p2.m, p3.m, p1.m]
|
||||
# listattr keeps a cache and deleting
|
||||
# a function attribute requires clearing it
|
||||
pluginmanager._listattrcache.clear()
|
||||
del P1.m.__dict__['tryfirst']
|
||||
|
||||
pytest.mark.trylast(getattr(P2.m, 'im_func', P2.m))
|
||||
methods = pluginmanager.listattr('m')
|
||||
assert methods == [p2.m, p1.m, p3.m]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import py, pytest
|
||||
from _pytest.core import collectattr
|
||||
import pytest
|
||||
|
||||
def test_version(testdir, pytestconfig):
|
||||
result = testdir.runpytest("--version")
|
||||
|
@ -25,18 +24,6 @@ def test_help(testdir):
|
|||
*to see*fixtures*py.test --fixtures*
|
||||
""")
|
||||
|
||||
def test_collectattr():
|
||||
class A:
|
||||
def pytest_hello(self):
|
||||
pass
|
||||
class B(A):
|
||||
def pytest_world(self):
|
||||
pass
|
||||
methods = py.builtin.sorted(collectattr(B))
|
||||
assert list(methods) == ['pytest_hello', 'pytest_world']
|
||||
methods = py.builtin.sorted(collectattr(B()))
|
||||
assert list(methods) == ['pytest_hello', 'pytest_world']
|
||||
|
||||
def test_hookvalidation_unknown(testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_hello(xyz):
|
||||
|
|
Loading…
Reference in New Issue