From 933086e00b7101bc3334cb294aef752a3f78834e Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sun, 25 Feb 2024 12:39:31 -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 merged to the execnet master branch via pytest-dev/execnet#243, so this patch should not be merged until there is a released version of execnet supporting the main_thread_only execmodel. Closes: pytest-dev/pytest-xdist#620 --- changelog/620.bugfix | 1 + src/xdist/looponfail.py | 2 +- src/xdist/workermanage.py | 8 +++++++- testing/test_remote.py | 2 +- testing/test_workermanage.py | 4 ++-- 5 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 changelog/620.bugfix diff --git a/changelog/620.bugfix b/changelog/620.bugfix new file mode 100644 index 00000000..81b3378d --- /dev/null +++ b/changelog/620.bugfix @@ -0,0 +1 @@ +Use the ``execnet`` new ``main_thread_only`` "execmodel" so that code which expects to only run in the main thread will now work as expected. diff --git a/src/xdist/looponfail.py b/src/xdist/looponfail.py index 8c2a60ab..04ea1036 100644 --- a/src/xdist/looponfail.py +++ b/src/xdist/looponfail.py @@ -78,7 +78,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): if hasattr(self, "gateway"): diff --git a/src/xdist/workermanage.py b/src/xdist/workermanage.py index c3793efb..fcc0a501 100644 --- a/src/xdist/workermanage.py +++ b/src/xdist/workermanage.py @@ -46,13 +46,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) @@ -73,6 +75,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 245f27d0..8314668e 100644 --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -39,7 +39,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//popen") 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 1246911f..6f84324b 100644 --- a/testing/test_workermanage.py +++ b/testing/test_workermanage.py @@ -77,7 +77,7 @@ def test_popen_makegateway_events( assert len(call.specs) == 2 call = hookrecorder.popcall("pytest_xdist_newgateway") - assert call.gateway.spec == execnet.XSpec("popen") + assert call.gateway.spec == execnet.XSpec("execmodel=main_thread_only//popen") assert call.gateway.id == "gw0" call = hookrecorder.popcall("pytest_xdist_newgateway") assert call.gateway.id == "gw1" @@ -167,7 +167,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))