simplify method to record calls
This commit is contained in:
parent
d8f4663f49
commit
3d84f35850
|
@ -416,7 +416,6 @@ 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):
|
||||||
hookspecs = [hookspecs]
|
hookspecs = [hookspecs]
|
||||||
self._hookspecs = []
|
|
||||||
self._pm = pm
|
self._pm = pm
|
||||||
self.trace = pm.trace.root.get("hook")
|
self.trace = pm.trace.root.get("hook")
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
|
@ -424,7 +423,6 @@ class HookRelay:
|
||||||
self._addhooks(hookspec, prefix)
|
self._addhooks(hookspec, prefix)
|
||||||
|
|
||||||
def _addhooks(self, hookspec, prefix):
|
def _addhooks(self, hookspec, prefix):
|
||||||
self._hookspecs.append(hookspec)
|
|
||||||
added = False
|
added = False
|
||||||
isclass = int(inspect.isclass(hookspec))
|
isclass = int(inspect.isclass(hookspec))
|
||||||
for name, method in vars(hookspec).items():
|
for name, method in vars(hookspec).items():
|
||||||
|
|
|
@ -12,7 +12,7 @@ import subprocess
|
||||||
import py
|
import py
|
||||||
import pytest
|
import pytest
|
||||||
from py.builtin import print_
|
from py.builtin import print_
|
||||||
from _pytest.core import HookRelay
|
from _pytest.core import HookRelay, HookCaller, Wrapping
|
||||||
|
|
||||||
from _pytest.main import Session, EXIT_OK
|
from _pytest.main import Session, EXIT_OK
|
||||||
|
|
||||||
|
@ -51,10 +51,8 @@ class PytestArg:
|
||||||
return hookrecorder
|
return hookrecorder
|
||||||
|
|
||||||
class ParsedCall:
|
class ParsedCall:
|
||||||
def __init__(self, name, locals):
|
def __init__(self, name, kwargs):
|
||||||
assert '_name' not in locals
|
self.__dict__.update(kwargs)
|
||||||
self.__dict__.update(locals)
|
|
||||||
self.__dict__.pop('self')
|
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -62,64 +60,24 @@ class ParsedCall:
|
||||||
del d['_name']
|
del d['_name']
|
||||||
return "<ParsedCall %r(**%r)>" %(self._name, d)
|
return "<ParsedCall %r(**%r)>" %(self._name, d)
|
||||||
|
|
||||||
|
|
||||||
class HookRecorder:
|
class HookRecorder:
|
||||||
def __init__(self, pluginmanager):
|
def __init__(self, pluginmanager):
|
||||||
self._pluginmanager = pluginmanager
|
self._pluginmanager = pluginmanager
|
||||||
self.calls = []
|
self.calls = []
|
||||||
self._recorders = {}
|
self.wrapping = Wrapping()
|
||||||
|
@self.wrapping.method(HookCaller)
|
||||||
hookspecs = self._pluginmanager.hook._hookspecs
|
def _docall(hookcaller, methods, kwargs):
|
||||||
for hookspec in hookspecs:
|
self.calls.append(ParsedCall(hookcaller.name, kwargs))
|
||||||
assert hookspec not in self._recorders
|
yield
|
||||||
class RecordCalls:
|
|
||||||
_recorder = self
|
|
||||||
for name, method in vars(hookspec).items():
|
|
||||||
if name[0] != "_":
|
|
||||||
setattr(RecordCalls, name, self._makecallparser(method))
|
|
||||||
recorder = RecordCalls()
|
|
||||||
self._recorders[hookspec] = recorder
|
|
||||||
self._pluginmanager.register(recorder)
|
|
||||||
self.hook = HookRelay(hookspecs, pm=self._pluginmanager,
|
|
||||||
prefix="pytest_")
|
|
||||||
|
|
||||||
def finish_recording(self):
|
def finish_recording(self):
|
||||||
for recorder in self._recorders.values():
|
self.wrapping.undo()
|
||||||
if self._pluginmanager.isregistered(recorder):
|
|
||||||
self._pluginmanager.unregister(recorder)
|
|
||||||
self._recorders.clear()
|
|
||||||
|
|
||||||
def _makecallparser(self, method):
|
|
||||||
name = method.__name__
|
|
||||||
args, varargs, varkw, default = inspect.getargspec(method)
|
|
||||||
if not args or args[0] != "self":
|
|
||||||
args.insert(0, 'self')
|
|
||||||
fspec = inspect.formatargspec(args, varargs, varkw, default)
|
|
||||||
# we use exec because we want to have early type
|
|
||||||
# errors on wrong input arguments, using
|
|
||||||
# *args/**kwargs delays this and gives errors
|
|
||||||
# elsewhere
|
|
||||||
exec (py.code.compile("""
|
|
||||||
def %(name)s%(fspec)s:
|
|
||||||
self._recorder.calls.append(
|
|
||||||
ParsedCall(%(name)r, locals()))
|
|
||||||
""" % locals()))
|
|
||||||
return locals()[name]
|
|
||||||
|
|
||||||
def getcalls(self, names):
|
def getcalls(self, names):
|
||||||
if isinstance(names, str):
|
if isinstance(names, str):
|
||||||
names = names.split()
|
names = names.split()
|
||||||
for name in names:
|
return [call for call in self.calls if call._name in names]
|
||||||
for cls in self._recorders:
|
|
||||||
if name in vars(cls):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise ValueError("callname %r not found in %r" %(
|
|
||||||
name, self._recorders.keys()))
|
|
||||||
l = []
|
|
||||||
for call in self.calls:
|
|
||||||
if call._name in names:
|
|
||||||
l.append(call)
|
|
||||||
return l
|
|
||||||
|
|
||||||
def contains(self, entries):
|
def contains(self, entries):
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
|
@ -228,10 +186,9 @@ class TmpTestdir:
|
||||||
obj = obj.config
|
obj = obj.config
|
||||||
if hasattr(obj, 'hook'):
|
if hasattr(obj, 'hook'):
|
||||||
obj = obj.hook
|
obj = obj.hook
|
||||||
assert hasattr(obj, '_hookspecs'), obj
|
assert isinstance(obj, HookRelay)
|
||||||
reprec = ReportRecorder(obj)
|
reprec = ReportRecorder(obj)
|
||||||
reprec.hookrecorder = self._pytest.gethookrecorder(obj)
|
reprec.hookrecorder = self._pytest.gethookrecorder(obj)
|
||||||
reprec.hook = reprec.hookrecorder.hook
|
|
||||||
return reprec
|
return reprec
|
||||||
|
|
||||||
def chdir(self):
|
def chdir(self):
|
||||||
|
|
|
@ -94,12 +94,12 @@ def test_hookrecorder_basic(holder):
|
||||||
pm = PluginManager()
|
pm = PluginManager()
|
||||||
pm.hook._addhooks(holder, "pytest_")
|
pm.hook._addhooks(holder, "pytest_")
|
||||||
rec = HookRecorder(pm)
|
rec = HookRecorder(pm)
|
||||||
rec.hook.pytest_xyz(arg=123)
|
pm.hook.pytest_xyz(arg=123)
|
||||||
call = rec.popcall("pytest_xyz")
|
call = rec.popcall("pytest_xyz")
|
||||||
assert call.arg == 123
|
assert call.arg == 123
|
||||||
assert call._name == "pytest_xyz"
|
assert call._name == "pytest_xyz"
|
||||||
pytest.raises(pytest.fail.Exception, "rec.popcall('abc')")
|
pytest.raises(pytest.fail.Exception, "rec.popcall('abc')")
|
||||||
rec.hook.pytest_xyz_noarg()
|
pm.hook.pytest_xyz_noarg()
|
||||||
call = rec.popcall("pytest_xyz_noarg")
|
call = rec.popcall("pytest_xyz_noarg")
|
||||||
assert call._name == "pytest_xyz_noarg"
|
assert call._name == "pytest_xyz_noarg"
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ def test_functional(testdir, linecomp):
|
||||||
def pytest_xyz(self, arg):
|
def pytest_xyz(self, arg):
|
||||||
return arg + 1
|
return arg + 1
|
||||||
rec._pluginmanager.register(Plugin())
|
rec._pluginmanager.register(Plugin())
|
||||||
res = rec.hook.pytest_xyz(arg=41)
|
res = pm.hook.pytest_xyz(arg=41)
|
||||||
assert res == [42]
|
assert res == [42]
|
||||||
""")
|
""")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
Loading…
Reference in New Issue