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