From 640ee7a16a6f501060dba6454f763b8e81976df8 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Thu, 15 Feb 2024 21:08:56 -0800 Subject: [PATCH] Use execnet main_thread_only execmodel Use the execnet main_thread_only execmodel so that code which expects to run in the main thread will just work. This execmodel has been proposed in https://github.com/pytest-dev/execnet/pull/243, so this patch should not be merged until there is a release version of execnet supporting the main_thread_only execmodel. Closes: https://github.com/pytest-dev/pytest-xdist/issues/620 --- src/xdist/looponfail.py | 2 +- src/xdist/workermanage.py | 8 +++++++- testing/test_remote.py | 2 +- testing/test_workermanage.py | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/xdist/looponfail.py b/src/xdist/looponfail.py index ab9ff32e..70c8e71d 100644 --- a/src/xdist/looponfail.py +++ b/src/xdist/looponfail.py @@ -76,7 +76,7 @@ def trace(self, *args): print("RemoteControl:", msg) def initgateway(self): - return execnet.makegateway("popen") + return execnet.makegateway("execmodel=main_thread_only//popen") def setup(self, out=None): if out is None: diff --git a/src/xdist/workermanage.py b/src/xdist/workermanage.py index fdd4109a..fc2a3a16 100644 --- a/src/xdist/workermanage.py +++ b/src/xdist/workermanage.py @@ -41,13 +41,15 @@ def __init__(self, config, specs=None, defaultchdir="pyexecnetcache") -> None: self.testrunuid = self.config.getoption("testrunuid") if self.testrunuid is None: self.testrunuid = uuid.uuid4().hex - self.group = execnet.Group() + self.group = execnet.Group(execmodel="main_thread_only") if specs is None: specs = self._getxspecs() self.specs = [] for spec in specs: if not isinstance(spec, execnet.XSpec): spec = execnet.XSpec(spec) + if getattr(spec, "execmodel", None) != "main_thread_only": + spec = execnet.XSpec(f"execmodel=main_thread_only//{spec}") if not spec.chdir and not spec.popen: spec.chdir = defaultchdir self.group.allocate_id(spec) @@ -68,6 +70,10 @@ def setup_nodes(self, putevent): return [self.setup_node(spec, putevent) for spec in self.specs] def setup_node(self, spec, putevent): + if not isinstance(spec, execnet.XSpec): + spec = execnet.XSpec(spec) + if getattr(spec, "execmodel", None) != "main_thread_only": + spec = execnet.XSpec(f"execmodel=main_thread_only//{spec}") gw = self.group.makegateway(spec) self.config.hook.pytest_xdist_newgateway(gateway=gw) self.rsync_roots(gw) diff --git a/testing/test_remote.py b/testing/test_remote.py index 2d250c5b..20715fc9 100644 --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -38,7 +38,7 @@ def __init__(self, request, pytester: pytest.Pytester) -> None: def setup(self) -> None: self.pytester.chdir() # import os ; os.environ['EXECNET_DEBUG'] = "2" - self.gateway = execnet.makegateway() + self.gateway = execnet.makegateway("execmodel=main_thread_only") self.config = config = self.pytester.parseconfigure() putevent = self.events.put if self.use_callback else None diff --git a/testing/test_workermanage.py b/testing/test_workermanage.py index 6f5a3a46..49060aa0 100644 --- a/testing/test_workermanage.py +++ b/testing/test_workermanage.py @@ -162,7 +162,7 @@ def test_hrsync_filter(self, source: Path, dest: Path) -> None: assert names == {"dir", "file.txt", "somedir"} def test_hrsync_one_host(self, source: Path, dest: Path) -> None: - gw = execnet.makegateway("popen//chdir=%s" % dest) + gw = execnet.makegateway("execmodel=main_thread_only//popen//chdir=%s" % dest) finished = [] rsync = HostRSync(source) rsync.add_target_host(gw, finished=lambda: finished.append(1))