diff --git a/src/xdist/dsession.py b/src/xdist/dsession.py index d517a8a..12539a0 100644 --- a/src/xdist/dsession.py +++ b/src/xdist/dsession.py @@ -67,7 +67,7 @@ class DSession: if self.terminal and self.config.option.verbose >= 0: self.terminal.write_line(line) - @pytest.mark.trylast + @pytest.hookimpl(trylast=True) def pytest_sessionstart(self, session): """Creates and starts the nodes. @@ -79,6 +79,7 @@ class DSession: self._active_nodes.update(nodes) self._session = session + @pytest.hookimpl def pytest_sessionfinish(self, session): """Shutdown all nodes.""" nm = getattr(self, "nodemanager", None) # if not fully initialized @@ -86,11 +87,12 @@ class DSession: nm.teardown_nodes() self._session = None + @pytest.hookimpl def pytest_collection(self): # prohibit collection of test items in controller process return True - @pytest.mark.trylast + @pytest.hookimpl(trylast=True) def pytest_xdist_make_scheduler(self, config, log): dist = config.getvalue("dist") schedulers = { @@ -101,6 +103,7 @@ class DSession: } return schedulers[dist](config, log) + @pytest.hookimpl def pytest_runtestloop(self): self.sched = self.config.hook.pytest_xdist_make_scheduler( config=self.config, log=self.log @@ -223,6 +226,7 @@ class DSession: self._clone_node(node) self._active_nodes.remove(node) + @pytest.hookimpl def pytest_terminal_summary(self, terminalreporter): if self.config.option.verbose >= 0 and self._summary_report: terminalreporter.write_sep("=", "xdist: {}".format(self._summary_report)) @@ -390,6 +394,7 @@ class TerminalDistReporter: self._lastlen = len(line) self.tr.rewrite(pline, bold=True) + @pytest.hookimpl def pytest_xdist_setupnodes(self, specs): self._specs = specs for spec in specs: @@ -397,6 +402,7 @@ class TerminalDistReporter: self.setstatus(spec, "I", show=True) self.ensure_show_status() + @pytest.hookimpl def pytest_xdist_newgateway(self, gateway): if self.config.option.verbose > 0: rinfo = gateway._rinfo() @@ -408,6 +414,7 @@ class TerminalDistReporter: ) self.setstatus(gateway.spec, "C") + @pytest.hookimpl def pytest_testnodeready(self, node): if self.config.option.verbose > 0: d = node.workerinfo @@ -417,6 +424,7 @@ class TerminalDistReporter: self.rewrite(infoline, newline=True) self.setstatus(node.gateway.spec, "ok") + @pytest.hookimpl def pytest_testnodedown(self, node, error): if not error: return diff --git a/src/xdist/looponfail.py b/src/xdist/looponfail.py index b721527..ef4c34f 100644 --- a/src/xdist/looponfail.py +++ b/src/xdist/looponfail.py @@ -13,6 +13,7 @@ import time import execnet +@pytest.hookimpl def pytest_addoption(parser): group = parser.getgroup("xdist", "distributed and subprocess testing") group._addoption( @@ -26,6 +27,7 @@ def pytest_addoption(parser): ) +@pytest.hookimpl def pytest_cmdline_main(config): if config.getoption("looponfail"): @@ -178,6 +180,7 @@ class WorkerFailSession: if self.config.option.debug: print(" ".join(map(str, args))) + @pytest.hookimpl def pytest_collection(self, session): self.session = session self.trails = self.current_command @@ -192,10 +195,12 @@ class WorkerFailSession: hook.pytest_collection_finish(session=session) return True + @pytest.hookimpl def pytest_runtest_logreport(self, report): if report.failed: self.recorded_failures.append(report) + @pytest.hookimpl def pytest_collectreport(self, report): if report.failed: self.recorded_failures.append(report) diff --git a/src/xdist/newhooks.py b/src/xdist/newhooks.py index f9ac6b4..7776624 100644 --- a/src/xdist/newhooks.py +++ b/src/xdist/newhooks.py @@ -14,18 +14,22 @@ must be taken in plugins in case ``xdist`` is not installed. Please see: import pytest +@pytest.hookspec() def pytest_xdist_setupnodes(config, specs): """called before any remote node is set up.""" +@pytest.hookspec() def pytest_xdist_newgateway(gateway): """called on new raw gateway creation.""" +@pytest.hookspec() def pytest_xdist_rsyncstart(source, gateways): """called before rsyncing a directory to remote gateways takes place.""" +@pytest.hookspec() def pytest_xdist_rsyncfinish(source, gateways): """called after rsyncing a directory to remote gateways takes place.""" @@ -35,18 +39,22 @@ def pytest_xdist_getremotemodule(): """called when creating remote node""" +@pytest.hookspec() def pytest_configure_node(node): """configure node information before it gets instantiated.""" +@pytest.hookspec() def pytest_testnodeready(node): """Test Node is ready to operate.""" +@pytest.hookspec() def pytest_testnodedown(node, error): """Test Node is down.""" +@pytest.hookspec() def pytest_xdist_node_collection_finished(node, ids): """called by the controller node when a worker node finishes collecting.""" diff --git a/src/xdist/plugin.py b/src/xdist/plugin.py index 5f1ed09..17be6d0 100644 --- a/src/xdist/plugin.py +++ b/src/xdist/plugin.py @@ -12,6 +12,7 @@ PYTEST_GTE_7 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (7, _sys_path = list(sys.path) # freeze a copy of sys.path at interpreter startup +@pytest.hookimpl def pytest_xdist_auto_num_workers(config): try: import psutil @@ -50,6 +51,7 @@ def parse_numprocesses(s): return int(s) +@pytest.hookimpl def pytest_addoption(parser): group = parser.getgroup("xdist", "distributed and subprocess testing") group._addoption( @@ -171,6 +173,7 @@ def pytest_addoption(parser): # ------------------------------------------------------------------------- +@pytest.hookimpl def pytest_addhooks(pluginmanager): from xdist import newhooks @@ -182,7 +185,7 @@ def pytest_addhooks(pluginmanager): # ------------------------------------------------------------------------- -@pytest.mark.trylast +@pytest.hookimpl(trylast=True) def pytest_configure(config): if config.getoption("dist") != "no" and not config.getvalue("collectonly"): from xdist.dsession import DSession @@ -202,7 +205,7 @@ def pytest_configure(config): config.option.forked = True -@pytest.mark.tryfirst +@pytest.hookimpl(tryfirst=True) def pytest_cmdline_main(config): usepdb = config.getoption("usepdb", False) # a core option if config.option.numprocesses in ("auto", "logical"): diff --git a/src/xdist/remote.py b/src/xdist/remote.py index 05951f3..914040d 100644 --- a/src/xdist/remote.py +++ b/src/xdist/remote.py @@ -47,12 +47,14 @@ class WorkerInteractor: self.log("sending", name, kwargs) self.channel.send((name, kwargs)) + @pytest.hookimpl def pytest_internalerror(self, excrepr): formatted_error = str(excrepr) for line in formatted_error.split("\n"): self.log("IERROR>", line) interactor.sendevent("internal_error", formatted_error=formatted_error) + @pytest.hookimpl def pytest_sessionstart(self, session): self.session = session workerinfo = getinfodict() @@ -65,9 +67,11 @@ class WorkerInteractor: yield self.sendevent("workerfinished", workeroutput=self.config.workeroutput) + @pytest.hookimpl def pytest_collection(self, session): self.sendevent("collectionstart") + @pytest.hookimpl def pytest_runtestloop(self, session): self.log("entering main loop") torun = [] @@ -112,6 +116,7 @@ class WorkerInteractor: "runtest_protocol_complete", item_index=self.item_index, duration=duration ) + @pytest.hookimpl def pytest_collection_finish(self, session): try: topdir = str(self.config.rootpath) @@ -124,12 +129,15 @@ class WorkerInteractor: ids=[item.nodeid for item in session.items], ) + @pytest.hookimpl def pytest_runtest_logstart(self, nodeid, location): self.sendevent("logstart", nodeid=nodeid, location=location) + @pytest.hookimpl def pytest_runtest_logfinish(self, nodeid, location): self.sendevent("logfinish", nodeid=nodeid, location=location) + @pytest.hookimpl def pytest_runtest_logreport(self, report): data = self.config.hook.pytest_report_to_serializable( config=self.config, report=report @@ -140,6 +148,7 @@ class WorkerInteractor: assert self.session.items[self.item_index].nodeid == report.nodeid self.sendevent("testreport", data=data) + @pytest.hookimpl def pytest_collectreport(self, report): # send only reports that have not passed to controller as optimization (#330) if not report.passed: @@ -148,6 +157,7 @@ class WorkerInteractor: ) self.sendevent("collectreport", data=data) + @pytest.hookimpl def pytest_warning_recorded(self, warning_message, when, nodeid, location): self.sendevent( "warning_recorded", diff --git a/src/xdist/workermanage.py b/src/xdist/workermanage.py index 411ea82..8d291d4 100644 --- a/src/xdist/workermanage.py +++ b/src/xdist/workermanage.py @@ -212,7 +212,7 @@ class WorkerController: ENDMARK = -1 class RemoteHook: - @pytest.mark.trylast + @pytest.hookimpl(trylast=True) def pytest_xdist_getremotemodule(self): return xdist.remote diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index b7dadf8..82513a4 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -205,7 +205,7 @@ class TestDistribution: def pytest_addoption(parser): parser.addoption("--foobar", action="store", dest="foobar_opt") - @pytest.mark.tryfirst + @pytest.hookimpl(tryfirst=True) def pytest_load_initial_conftests(early_config): opt = early_config.known_args_namespace.foobar_opt print("--foobar=%s active! [%s]" % (opt, os.getpid()), file=sys.stderr)