diff --git a/src/superqt/utils/_qthreading.py b/src/superqt/utils/_qthreading.py index 8b1cf1e..5816490 100644 --- a/src/superqt/utils/_qthreading.py +++ b/src/superqt/utils/_qthreading.py @@ -247,8 +247,13 @@ class WorkerBase(QRunnable, Generic[_R]): self._worker_set.add(self) self._finished.connect(self._set_discard) - start_ = partial(QThreadPool.globalInstance().start, self) - QTimer.singleShot(10, start_) + if QThread.currentThread().loopLevel(): + # if we're in a thread with an eventloop, queue the worker to start + start_ = partial(QThreadPool.globalInstance().start, self) + QTimer.singleShot(1, start_) + else: + # otherwise start it immediately + QThreadPool.globalInstance().start(self) @classmethod def _set_discard(cls, obj: WorkerBase) -> None: diff --git a/tests/test_threadworker.py b/tests/test_threadworker.py index 9ee8c40..2c9b52d 100644 --- a/tests/test_threadworker.py +++ b/tests/test_threadworker.py @@ -3,6 +3,7 @@ import time import warnings from functools import partial from operator import eq +from unittest.mock import Mock import pytest @@ -274,3 +275,20 @@ def test_abort_does_not_return(qtbot): assert loop_counter < 4 assert abort_counter == 1 assert return_counter == 0 + + +def test_nested_threads_start(qtbot): + mock1 = Mock() + mock2 = Mock() + + def call_mock(): + mock1() + worker2 = qthreading.create_worker(mock2) + worker2.start() + + worker = qthreading.create_worker(call_mock) + worker.start() + + qtbot.wait(20) + mock1.assert_called_once() + mock2.assert_called_once()