simplify internal plugin dispatching code, rename parts of the py._com plugin helpers
--HG-- branch : 1.0.x
This commit is contained in:
		
							parent
							
								
									5c8df1d4ca
								
							
						
					
					
						commit
						a01e4769cc
					
				
							
								
								
									
										11
									
								
								CHANGELOG
								
								
								
								
							
							
						
						
									
										11
									
								
								CHANGELOG
								
								
								
								
							|  | @ -1,18 +1,21 @@ | |||
| Changes between 1.0.0 and 1.0.1 | ||||
| ===================================== | ||||
| 
 | ||||
| * various unicode fixes: capturing and prints of unicode strings now  | ||||
|   work within tests, they are encoded as "utf8" by default, terminalwriting  | ||||
| * unicode fixes: capturing and unicode writes to sys.stdout  | ||||
|   (through e.g a print statement) now work within tests,  | ||||
|   they are encoded as "utf8" by default, also terminalwriting  | ||||
|   was adapted and somewhat unified between windows and linux  | ||||
| 
 | ||||
| * fix issue #27: better reporting on non-collectable items given on commandline  | ||||
|   (e.g. pyc files)  | ||||
| 
 | ||||
| * "Test" prefixed classes with an __init__ method are *not* collected by default anymore | ||||
| * "Test" prefixed classes are *not* collected by default anymore if they  | ||||
|   have an __init__ method  | ||||
| 
 | ||||
| * terser reporting of collection error tracebacks | ||||
| 
 | ||||
| * renaming of arguments to some special rather internal hooks | ||||
| * streamlined internal plugin arch code, renamed of internal methods  | ||||
|   and argnames (related to py/_com.py multicall/plugin) | ||||
| 
 | ||||
| Changes between 1.0.0b9 and 1.0.0 | ||||
| ===================================== | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ initpkg(__name__, | |||
|     '_com.Registry'          : ('./_com.py', 'Registry'),  | ||||
|     '_com.MultiCall'         : ('./_com.py', 'MultiCall'),  | ||||
|     '_com.comregistry'       : ('./_com.py', 'comregistry'),  | ||||
|     '_com.Hooks'             : ('./_com.py', 'Hooks'),  | ||||
|     '_com.HookRelay'             : ('./_com.py', 'HookRelay'),  | ||||
| 
 | ||||
|     # py lib cmdline tools  | ||||
|     'cmdline.pytest'         : ('./cmdline/pytest.py', 'main',), | ||||
|  |  | |||
							
								
								
									
										143
									
								
								py/_com.py
								
								
								
								
							
							
						
						
									
										143
									
								
								py/_com.py
								
								
								
								
							|  | @ -5,77 +5,50 @@ py lib plugins and plugin call management | |||
| import py | ||||
|   | ||||
| class MultiCall: | ||||
|     """ Manage a specific call into many python functions/methods.  | ||||
|     """ execute a call into multiple python functions/methods.  """ | ||||
| 
 | ||||
|         Simple example:  | ||||
|         MultiCall([list1.append, list2.append], 42).execute() | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, methods, *args, **kwargs): | ||||
|     def __init__(self, methods, kwargs, firstresult=False): | ||||
|         self.methods = methods[:] | ||||
|         self.args = args  | ||||
|         self.kwargs = kwargs  | ||||
|         self.results = [] | ||||
|         self.firstresult = firstresult | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         args = [] | ||||
|         if self.args: | ||||
|             args.append("posargs=%r" %(self.args,)) | ||||
|         kw = self.kwargs | ||||
|         args.append(", ".join(["%s=%r" % x for x in self.kwargs.items()])) | ||||
|         args = " ".join(args) | ||||
|         status = "results: %r, rmethods: %r" % (self.results, self.methods) | ||||
|         return "<MultiCall %s %s>" %(args, status) | ||||
|         status = "%d results, %d meths" % (len(self.results), len(self.methods)) | ||||
|         return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs) | ||||
| 
 | ||||
|     def execute(self, firstresult=False): | ||||
|     def execute(self): | ||||
|         while self.methods: | ||||
|             currentmethod = self.methods.pop() | ||||
|             res = self.execute_method(currentmethod) | ||||
|             if hasattr(self, '_ex1'): | ||||
|                 self.results = [res] | ||||
|                 break | ||||
|             method = self.methods.pop() | ||||
|             res = self._call1(method) | ||||
|             if res is not None: | ||||
|                 self.results.append(res)  | ||||
|                 if firstresult: | ||||
|                     break  | ||||
|         if not firstresult: | ||||
|                 if self.firstresult: | ||||
|                     break | ||||
|         if not self.firstresult: | ||||
|             return self.results  | ||||
|         if self.results: | ||||
|             return self.results[-1]  | ||||
|             return self.results[-1] | ||||
| 
 | ||||
|     def execute_method(self, currentmethod): | ||||
|         self.currentmethod = currentmethod | ||||
|         # provide call introspection if "__call__" is the first positional argument  | ||||
|         if hasattr(currentmethod, 'im_self'): | ||||
|             varnames = currentmethod.im_func.func_code.co_varnames | ||||
|             needscall = varnames[1:2] == ('__call__',) | ||||
|         else: | ||||
|             try: | ||||
|                 varnames = currentmethod.func_code.co_varnames | ||||
|             except AttributeError: | ||||
|                 # builtin function | ||||
|                 varnames = () | ||||
|             needscall = varnames[:1] == ('__call__',) | ||||
|         if needscall: | ||||
|             return currentmethod(self, *self.args, **self.kwargs) | ||||
|         else: | ||||
|             #try: | ||||
|                 return currentmethod(*self.args, **self.kwargs) | ||||
|             #except TypeError: | ||||
|             #    print currentmethod.__module__, currentmethod.__name__, self.args, self.kwargs | ||||
|             #    raise | ||||
| 
 | ||||
|     def exclude_other_results(self): | ||||
|         self._ex1 = True | ||||
|     def _call1(self, method): | ||||
|         kwargs = self.kwargs | ||||
|         if '__call__' in varnames(method): | ||||
|             kwargs = kwargs.copy() | ||||
|             kwargs['__call__'] = self | ||||
|         return method(**kwargs) | ||||
| 
 | ||||
| def varnames(rawcode): | ||||
|     rawcode = getattr(rawcode, 'im_func', rawcode) | ||||
|     rawcode = getattr(rawcode, 'func_code', rawcode) | ||||
|     try: | ||||
|         return rawcode.co_varnames  | ||||
|     except AttributeError: | ||||
|         return () | ||||
| 
 | ||||
| class Registry: | ||||
|     """ | ||||
|         Manage Plugins: Load plugins and manage calls to plugins.  | ||||
|         Manage Plugins: register/unregister call calls to plugins.  | ||||
|     """ | ||||
|     logfile = None | ||||
|     MultiCall = MultiCall | ||||
| 
 | ||||
|     def __init__(self, plugins=None): | ||||
|         if plugins is None: | ||||
|             plugins = [] | ||||
|  | @ -83,6 +56,7 @@ class Registry: | |||
| 
 | ||||
|     def register(self, plugin): | ||||
|         assert not isinstance(plugin, str) | ||||
|         assert not plugin in self._plugins | ||||
|         self._plugins.append(plugin) | ||||
| 
 | ||||
|     def unregister(self, plugin): | ||||
|  | @ -107,45 +81,44 @@ class Registry: | |||
|             l.reverse() | ||||
|         return l | ||||
| 
 | ||||
| class Hooks:  | ||||
|     def __init__(self, hookspecs, registry=None): | ||||
| class HookRelay:  | ||||
|     def __init__(self, hookspecs, registry): | ||||
|         self._hookspecs = hookspecs | ||||
|         if registry is None: | ||||
|             registry = py._com.comregistry | ||||
|         self.registry = registry | ||||
|         self._registry = registry | ||||
|         for name, method in vars(hookspecs).items(): | ||||
|             if name[:1] != "_": | ||||
|                 firstresult = getattr(method, 'firstresult', False) | ||||
|                 mm = HookCall(registry, name, firstresult=firstresult) | ||||
|                 setattr(self, name, mm) | ||||
|     def __repr__(self): | ||||
|         return "<Hooks %r %r>" %(self._hookspecs, self.registry) | ||||
|                 setattr(self, name, self._makecall(name)) | ||||
| 
 | ||||
| class HookCall: | ||||
|     def __init__(self, registry, name, firstresult, extralookup=None): | ||||
|         self.registry = registry | ||||
|     def _makecall(self, name, extralookup=None): | ||||
|         hookspecmethod = getattr(self._hookspecs, name) | ||||
|         firstresult = getattr(hookspecmethod, 'firstresult', False) | ||||
|         return HookCaller(self, name, firstresult=firstresult, | ||||
|             extralookup=extralookup) | ||||
| 
 | ||||
|     def _getmethods(self, name, extralookup=()): | ||||
|         return self._registry.listattr(name, extra=extralookup) | ||||
| 
 | ||||
|     def _performcall(self, name, multicall): | ||||
|         return multicall.execute() | ||||
|          | ||||
|     def __repr__(self): | ||||
|         return "<HookRelay %r %r>" %(self._hookspecs, self._registry) | ||||
| 
 | ||||
| class HookCaller: | ||||
|     def __init__(self, hookrelay, name, firstresult, extralookup=()): | ||||
|         self.hookrelay = hookrelay  | ||||
|         self.name = name  | ||||
|         self.firstresult = firstresult  | ||||
|         self.extralookup = extralookup and [extralookup] or () | ||||
| 
 | ||||
|     def clone(self, extralookup): | ||||
|         return HookCall(self.registry, self.name, self.firstresult, extralookup) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         mode = self.firstresult and "firstresult" or "each" | ||||
|         return "<HookCall %r mode=%s %s>" %(self.name, mode, self.registry) | ||||
|         return "<HookCaller %r firstresult=%s %s>" %( | ||||
|             self.name, self.firstresult, self.hookrelay) | ||||
| 
 | ||||
|     def __call__(self, *args, **kwargs): | ||||
|         if args: | ||||
|             raise TypeError("only keyword arguments allowed " | ||||
|                             "for api call to %r" % self.name) | ||||
|         attr = self.registry.listattr(self.name, extra=self.extralookup) | ||||
|         mc = MultiCall(attr, **kwargs) | ||||
|         # XXX this should be doable from a hook impl: | ||||
|         if self.registry.logfile: | ||||
|             self.registry.logfile.write("%s(**%s) # firstresult=%s\n" % | ||||
|                 (self.name, kwargs, self.firstresult)) | ||||
|             self.registry.logfile.flush() | ||||
|         return mc.execute(firstresult=self.firstresult) | ||||
| 
 | ||||
| comregistry = Registry() | ||||
|     def __call__(self, **kwargs): | ||||
|         methods = self.hookrelay._getmethods(self.name,  | ||||
|             extralookup=self.extralookup) | ||||
|         mc = MultiCall(methods, kwargs, firstresult=self.firstresult) | ||||
|         return self.hookrelay._performcall(self.name, mc) | ||||
|     | ||||
| comregistry = Registry([]) | ||||
|  |  | |||
|  | @ -88,8 +88,8 @@ class Gateway(object): | |||
|         self._channelfactory = ChannelFactory(self, _startcount) | ||||
|         self._cleanup.register(self)  | ||||
|         if _startcount == 1: # only import 'py' on the "client" side  | ||||
|             from py._com import Hooks  | ||||
|             self.hook = Hooks(ExecnetAPI) | ||||
|             import py | ||||
|             self.hook = py._com.HookRelay(ExecnetAPI, py._com.comregistry) | ||||
|         else: | ||||
|             self.hook = ExecnetAPI() | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,7 +21,8 @@ class GatewayManager: | |||
|             if not spec.chdir and not spec.popen: | ||||
|                 spec.chdir = defaultchdir | ||||
|             self.specs.append(spec) | ||||
|         self.hook = py._com.Hooks(py.execnet._HookSpecs) | ||||
|         self.hook = py._com.HookRelay( | ||||
|             py.execnet._HookSpecs, py._com.comregistry) | ||||
| 
 | ||||
|     def makegateways(self): | ||||
|         assert not self.gateways | ||||
|  |  | |||
|  | @ -1,15 +1,12 @@ | |||
| 
 | ||||
| import py | ||||
| import os | ||||
| from py._com import Registry, MultiCall | ||||
| from py._com import Hooks | ||||
| 
 | ||||
| pytest_plugins = "xfail" | ||||
| from py._com import Registry, MultiCall, HookRelay | ||||
| 
 | ||||
| class TestMultiCall: | ||||
|     def test_uses_copy_of_methods(self): | ||||
|         l = [lambda: 42] | ||||
|         mc = MultiCall(l) | ||||
|         mc = MultiCall(l, {}) | ||||
|         repr(mc) | ||||
|         l[:] = [] | ||||
|         res = mc.execute() | ||||
|  | @ -18,22 +15,19 @@ class TestMultiCall: | |||
|     def test_call_passing(self): | ||||
|         class P1: | ||||
|             def m(self, __call__, x): | ||||
|                 assert __call__.currentmethod == self.m  | ||||
|                 assert len(__call__.results) == 1 | ||||
|                 assert not __call__.methods | ||||
|                 return 17 | ||||
| 
 | ||||
|         class P2: | ||||
|             def m(self, __call__, x): | ||||
|                 assert __call__.currentmethod == self.m  | ||||
|                 assert __call__.args | ||||
|                 assert __call__.results == [] | ||||
|                 assert __call__.methods | ||||
|                 return 23  | ||||
|                 | ||||
|         p1 = P1()  | ||||
|         p2 = P2()  | ||||
|         multicall = MultiCall([p1.m, p2.m], 23) | ||||
|         multicall = MultiCall([p1.m, p2.m], {'x': 23}) | ||||
|         assert "23" in repr(multicall) | ||||
|         reslist = multicall.execute() | ||||
|         assert len(reslist) == 2 | ||||
|  | @ -43,62 +37,44 @@ class TestMultiCall: | |||
|     def test_keyword_args(self): | ||||
|         def f(x):  | ||||
|             return x + 1 | ||||
|         multicall = MultiCall([f], x=23) | ||||
|         assert "x=23" in repr(multicall) | ||||
|         multicall = MultiCall([f], dict(x=23)) | ||||
|         assert "'x': 23" in repr(multicall) | ||||
|         reslist = multicall.execute() | ||||
|         assert reslist == [24] | ||||
|         assert "24" in repr(multicall) | ||||
|         assert "1 results" in repr(multicall) | ||||
| 
 | ||||
|     def test_optionalcallarg(self): | ||||
|         class P1: | ||||
|             def m(self, x): | ||||
|                 return x | ||||
|         call = MultiCall([P1().m], 23) | ||||
|         call = MultiCall([P1().m], dict(x=23)) | ||||
|         assert "23" in repr(call) | ||||
|         assert call.execute() == [23] | ||||
|         assert call.execute(firstresult=True) == 23 | ||||
|         call = MultiCall([P1().m], dict(x=23), firstresult=True) | ||||
|   | ||||
|     def test_call_subexecute(self): | ||||
|         def m(__call__): | ||||
|             subresult = __call__.execute(firstresult=True) | ||||
|             subresult = __call__.execute() | ||||
|             return subresult + 1 | ||||
| 
 | ||||
|         def n(): | ||||
|             return 1 | ||||
| 
 | ||||
|         call = MultiCall([n, m]) | ||||
|         res = call.execute(firstresult=True) | ||||
|         assert res == 2 | ||||
| 
 | ||||
|     def test_call_exclude_other_results(self): | ||||
|         def m(__call__): | ||||
|             __call__.exclude_other_results() | ||||
|             return 10 | ||||
| 
 | ||||
|         def n(): | ||||
|             return 1 | ||||
| 
 | ||||
|         call = MultiCall([n, n, m, n]) | ||||
|         call = MultiCall([n, m], {}, firstresult=True) | ||||
|         res = call.execute() | ||||
|         assert res == [10] | ||||
|         # doesn't really make sense for firstresult-mode - because | ||||
|         # we might not have had a chance to run at all.  | ||||
|         #res = call.execute(firstresult=True) | ||||
|         #assert res == 10 | ||||
|         assert res == 2 | ||||
| 
 | ||||
|     def test_call_none_is_no_result(self): | ||||
|         def m1(): | ||||
|             return 1 | ||||
|         def m2(): | ||||
|             return None | ||||
|         mc = MultiCall([m1, m2]) | ||||
|         res = mc.execute(firstresult=True) | ||||
|         res = MultiCall([m1, m2], {}, firstresult=True).execute() | ||||
|         assert res == 1 | ||||
|         res = MultiCall([m1, m2], {}).execute() | ||||
|         assert res == [1] | ||||
| 
 | ||||
| class TestRegistry: | ||||
|     def test_MultiCall(self): | ||||
|         plugins = Registry() | ||||
|         assert hasattr(plugins, "MultiCall") | ||||
| 
 | ||||
|     def test_register(self): | ||||
|         registry = Registry() | ||||
|  | @ -142,14 +118,14 @@ class TestRegistry: | |||
| def test_api_and_defaults(): | ||||
|     assert isinstance(py._com.comregistry, Registry) | ||||
| 
 | ||||
| class TestHooks: | ||||
| class TestHookRelay: | ||||
|     def test_happypath(self): | ||||
|         registry = Registry() | ||||
|         class Api: | ||||
|             def hello(self, arg): | ||||
|                 pass | ||||
| 
 | ||||
|         mcm = Hooks(hookspecs=Api, registry=registry) | ||||
|         mcm = HookRelay(hookspecs=Api, registry=registry) | ||||
|         assert hasattr(mcm, 'hello') | ||||
|         assert repr(mcm.hello).find("hello") != -1 | ||||
|         class Plugin: | ||||
|  | @ -160,23 +136,21 @@ class TestHooks: | |||
|         assert l == [4] | ||||
|         assert not hasattr(mcm, 'world') | ||||
| 
 | ||||
|     def test_needskeywordargs(self): | ||||
|     def test_only_kwargs(self): | ||||
|         registry = Registry() | ||||
|         class Api: | ||||
|             def hello(self, arg): | ||||
|                 pass | ||||
|         mcm = Hooks(hookspecs=Api, registry=registry) | ||||
|         excinfo = py.test.raises(TypeError, "mcm.hello(3)") | ||||
|         assert str(excinfo.value).find("only keyword arguments") != -1 | ||||
|         assert str(excinfo.value).find("hello(self, arg)") | ||||
|         mcm = HookRelay(hookspecs=Api, registry=registry) | ||||
|         py.test.raises(TypeError, "mcm.hello(3)") | ||||
| 
 | ||||
|     def test_firstresult(self): | ||||
|     def test_firstresult_definition(self): | ||||
|         registry = Registry() | ||||
|         class Api: | ||||
|             def hello(self, arg): pass | ||||
|             hello.firstresult = True | ||||
| 
 | ||||
|         mcm = Hooks(hookspecs=Api, registry=registry) | ||||
|         mcm = HookRelay(hookspecs=Api, registry=registry) | ||||
|         class Plugin: | ||||
|             def hello(self, arg): | ||||
|                 return arg + 1 | ||||
|  | @ -186,15 +160,16 @@ class TestHooks: | |||
| 
 | ||||
|     def test_default_plugins(self): | ||||
|         class Api: pass  | ||||
|         mcm = Hooks(hookspecs=Api) | ||||
|         assert mcm.registry == py._com.comregistry | ||||
|         mcm = HookRelay(hookspecs=Api, registry=py._com.comregistry) | ||||
|         assert mcm._registry == py._com.comregistry | ||||
| 
 | ||||
|     def test_hooks_extra_plugins(self): | ||||
|         registry = Registry() | ||||
|         class Api: | ||||
|             def hello(self, arg): | ||||
|                 pass | ||||
|         hook_hello = Hooks(hookspecs=Api, registry=registry).hello  | ||||
|         hookrelay = HookRelay(hookspecs=Api, registry=registry) | ||||
|         hook_hello = hookrelay.hello | ||||
|         class Plugin: | ||||
|             def hello(self, arg): | ||||
|                 return arg + 1 | ||||
|  | @ -202,7 +177,7 @@ class TestHooks: | |||
|         class Plugin2: | ||||
|             def hello(self, arg): | ||||
|                 return arg + 2 | ||||
|         newhook = hook_hello.clone(extralookup=Plugin2()) | ||||
|         newhook = hookrelay._makecall("hello", extralookup=Plugin2()) | ||||
|         l = newhook(arg=3) | ||||
|         assert l == [5, 4] | ||||
|         l2 = hook_hello(arg=3) | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ class HookRecorder: | |||
|         recorder = RecordCalls() | ||||
|         self._recorders[hookspecs] = recorder | ||||
|         self._comregistry.register(recorder) | ||||
|         self.hook = py._com.Hooks(hookspecs, registry=self._comregistry) | ||||
|         self.hook = py._com.HookRelay(hookspecs, registry=self._comregistry) | ||||
| 
 | ||||
|     def finish_recording(self): | ||||
|         for recorder in self._recorders.values(): | ||||
|  |  | |||
|  | @ -185,7 +185,7 @@ class CaptureManager: | |||
|         method = self._getmethod(collector.config, collector.fspath) | ||||
|         self.resumecapture(method) | ||||
|         try: | ||||
|             rep = __call__.execute(firstresult=True) | ||||
|             rep = __call__.execute() | ||||
|         finally: | ||||
|             outerr = self.suspendcapture() | ||||
|         addouterr(rep, outerr) | ||||
|  | @ -208,7 +208,7 @@ class CaptureManager: | |||
|         method = self._getmethod(session.config, None) | ||||
|         self.resumecapture(method) | ||||
|         try: | ||||
|             rep = __call__.execute(firstresult=True) | ||||
|             rep = __call__.execute() | ||||
|         finally: | ||||
|             outerr = self.suspendcapture() | ||||
|         if rep: | ||||
|  | @ -221,7 +221,7 @@ class CaptureManager: | |||
| 
 | ||||
|     def pytest_runtest_makereport(self, __call__, item, call): | ||||
|         self.deactivate_funcargs() | ||||
|         rep = __call__.execute(firstresult=True) | ||||
|         rep = __call__.execute() | ||||
|         outerr = self.suspendcapture() | ||||
|         outerr = (item.outerr[0] + outerr[0], item.outerr[1] + outerr[1]) | ||||
|         if not rep.passed: | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| import py | ||||
| 
 | ||||
| def pytest_pyfunc_call(__call__, pyfuncitem): | ||||
|     if not __call__.execute(firstresult=True): | ||||
|     if not __call__.execute(): | ||||
|         testfunction = pyfuncitem.obj  | ||||
|         if pyfuncitem._isyieldedfunction(): | ||||
|             testfunction(*pyfuncitem._args) | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ class Execnetcleanup: | |||
|     def pytest_pyfunc_call(self, __call__, pyfuncitem): | ||||
|         if self._gateways is not None: | ||||
|             gateways = self._gateways[:] | ||||
|             res = __call__.execute(firstresult=True) | ||||
|             res = __call__.execute() | ||||
|             while len(self._gateways) > len(gateways): | ||||
|                 self._gateways[-1].exit() | ||||
|             return res | ||||
|  |  | |||
|  | @ -8,14 +8,27 @@ def pytest_addoption(parser): | |||
| def pytest_configure(config): | ||||
|     hooklog = config.getvalue("hooklog") | ||||
|     if hooklog: | ||||
|         assert not config.pluginmanager.comregistry.logfile | ||||
|         config.pluginmanager.comregistry.logfile = open(hooklog, 'w') | ||||
|         config._hooklogfile = open(hooklog, 'w', 0) | ||||
|         config._hooklog_oldperformcall = config.hook._performcall | ||||
|         config.hook._performcall = (lambda name, multicall:  | ||||
|             logged_call(name=name, multicall=multicall, config=config)) | ||||
| 
 | ||||
| def logged_call(name, multicall, config): | ||||
|     f = config._hooklogfile | ||||
|     f.write("%s(**%s)\n" % (name, multicall.kwargs)) | ||||
|     try: | ||||
|         res = config._hooklog_oldperformcall(name=name, multicall=multicall) | ||||
|     except: | ||||
|         f.write("-> exception") | ||||
|         raise | ||||
|     f.write("-> %r" % (res,)) | ||||
|     return res | ||||
| 
 | ||||
| def pytest_unconfigure(config): | ||||
|     f = config.pluginmanager.comregistry.logfile | ||||
|     if f: | ||||
|         f.close() | ||||
|         config.pluginmanager.comregistry.logfile = None | ||||
|     try: | ||||
|         del config.hook.__dict__['_performcall']  | ||||
|     except KeyError: | ||||
|         pass | ||||
| 
 | ||||
| # =============================================================================== | ||||
| # plugin tests  | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ def pytest_runtest_makereport(__call__, item, call): | |||
|         return | ||||
|     if hasattr(item, 'obj') and hasattr(item.obj, 'func_dict'): | ||||
|         if 'xfail' in item.obj.func_dict: | ||||
|             res = __call__.execute(firstresult=True) | ||||
|             res = __call__.execute() | ||||
|             if call.excinfo: | ||||
|                 res.skipped = True | ||||
|                 res.failed = res.passed = False | ||||
|  |  | |||
|  | @ -16,10 +16,9 @@ class PluginManager(object): | |||
|         if comregistry is None:  | ||||
|             comregistry = py._com.Registry() | ||||
|         self.comregistry = comregistry  | ||||
|         self.MultiCall = self.comregistry.MultiCall | ||||
|         self.impname2plugin = {} | ||||
| 
 | ||||
|         self.hook = py._com.Hooks( | ||||
|         self.hook = py._com.HookRelay( | ||||
|             hookspecs=hookspec,  | ||||
|             registry=self.comregistry)  | ||||
| 
 | ||||
|  | @ -166,20 +165,24 @@ class PluginManager(object): | |||
|         return self.hook.pytest_internalerror(excrepr=excrepr) | ||||
| 
 | ||||
|     def do_addoption(self, parser): | ||||
|         methods = self.comregistry.listattr("pytest_addoption", reverse=True) | ||||
|         mc = py._com.MultiCall(methods, parser=parser) | ||||
|         mname = "pytest_addoption" | ||||
|         methods = self.comregistry.listattr(mname, reverse=True) | ||||
|         mc = py._com.MultiCall(methods, {'parser': parser}) | ||||
|         mc.execute() | ||||
| 
 | ||||
|     def pytest_plugin_registered(self, plugin): | ||||
|         if hasattr(self, '_config'): | ||||
|             self.call_plugin(plugin, "pytest_addoption", parser=self._config._parser) | ||||
|             self.call_plugin(plugin, "pytest_configure", config=self._config) | ||||
|             self.call_plugin(plugin, "pytest_addoption",  | ||||
|                 {'parser': self._config._parser}) | ||||
|             self.call_plugin(plugin, "pytest_configure",  | ||||
|                 {'config': self._config}) | ||||
|             #dic = self.call_plugin(plugin, "pytest_namespace") | ||||
|             #self._updateext(dic) | ||||
| 
 | ||||
|     def call_plugin(self, plugin, methname, **kwargs): | ||||
|         return self.MultiCall(self.listattr(methname, plugins=[plugin]),  | ||||
|                 **kwargs).execute(firstresult=True) | ||||
|     def call_plugin(self, plugin, methname, kwargs): | ||||
|         return py._com.MultiCall( | ||||
|                 methods=self.listattr(methname, plugins=[plugin]),  | ||||
|                 kwargs=kwargs, firstresult=True).execute() | ||||
| 
 | ||||
|     def _updateext(self, dic): | ||||
|         if dic: | ||||
|  |  | |||
|  | @ -155,8 +155,8 @@ class PyCollectorMixin(PyobjMixin, py.test.collect.Collector): | |||
|         cls = clscol and clscol.obj or None | ||||
|         metafunc = funcargs.Metafunc(funcobj, config=self.config,  | ||||
|             cls=cls, module=module) | ||||
|         gentesthook = self.config.hook.pytest_generate_tests.clone( | ||||
|                 extralookup=module) | ||||
|         gentesthook = self.config.hook._makecall( | ||||
|             "pytest_generate_tests", extralookup=module) | ||||
|         gentesthook(metafunc=metafunc) | ||||
|         if not metafunc._calls: | ||||
|             return self.Function(name, parent=self) | ||||
|  |  | |||
|  | @ -145,7 +145,7 @@ class TestCollectFS: | |||
|         names = [x.name for x in col.collect()] | ||||
|         assert names == ["dir1", "dir2", "test_one.py", "test_two.py", "x"] | ||||
| 
 | ||||
| class TestCollectPluginHooks: | ||||
| class TestCollectPluginHookRelay: | ||||
|     def test_pytest_collect_file(self, testdir): | ||||
|         tmpdir = testdir.tmpdir | ||||
|         wascalled = [] | ||||
|  |  | |||
|  | @ -222,10 +222,6 @@ class TestPytestPluginInteractions: | |||
|         config.pluginmanager.register(A()) | ||||
|         assert len(l) == 2 | ||||
| 
 | ||||
|     def test_MultiCall(self): | ||||
|         pp = PluginManager() | ||||
|         assert hasattr(pp, 'MultiCall') | ||||
| 
 | ||||
|     # lower level API | ||||
| 
 | ||||
|     def test_listattr(self): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue