Skip to content

Commit 68be1ee

Browse files
authored
Merge pull request #141 from kormax/qeventloop-with-qthread
Add support for using QEventLoop inside of QThread
2 parents a8e4873 + 969663c commit 68be1ee

2 files changed

Lines changed: 46 additions & 4 deletions

File tree

qasync/__init__.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,24 +78,28 @@
7878
from PyQt5.QtCore import pyqtSlot as Slot
7979

8080
QApplication = QtWidgets.QApplication
81+
AllEvents = QtCore.QEventLoop.ProcessEventsFlags(0x00)
8182

8283
elif QtModuleName == "PyQt6":
8384
from PyQt6 import QtWidgets
8485
from PyQt6.QtCore import pyqtSlot as Slot
8586

8687
QApplication = QtWidgets.QApplication
88+
AllEvents = QtCore.QEventLoop.ProcessEventsFlag(0x00)
8789

8890
elif QtModuleName == "PySide2":
8991
from PySide2 import QtWidgets
9092
from PySide2.QtCore import Slot
9193

9294
QApplication = QtWidgets.QApplication
95+
AllEvents = QtCore.QEventLoop.ProcessEventsFlags(0x00)
9396

9497
elif QtModuleName == "PySide6":
9598
from PySide6 import QtWidgets
9699
from PySide6.QtCore import Slot
97100

98101
QApplication = QtWidgets.QApplication
102+
AllEvents = QtCore.QEventLoop.ProcessEventsFlags(0x00)
99103

100104
from ._common import with_logger # noqa
101105

@@ -234,7 +238,7 @@ def __exit__(self, *args):
234238

235239
def _format_handle(handle: asyncio.Handle):
236240
cb = getattr(handle, "_callback", None)
237-
if isinstance(getattr(cb, '__self__', None), asyncio.tasks.Task):
241+
if isinstance(getattr(cb, "__self__", None), asyncio.tasks.Task):
238242
return repr(cb.__self__)
239243
return str(handle)
240244

@@ -292,7 +296,11 @@ def timerEvent(self, event): # noqa: N802
292296
handle._run()
293297
dt = time.time() - t0
294298
if dt >= loop.slow_callback_duration:
295-
self._logger.warning('Executing %s took %.3f seconds', _format_handle(handle), dt)
299+
self._logger.warning(
300+
"Executing %s took %.3f seconds",
301+
_format_handle(handle),
302+
dt,
303+
)
296304
finally:
297305
loop._current_handle = None
298306
else:
@@ -338,7 +346,7 @@ class _QEventLoop:
338346
... await asyncio.sleep(.1)
339347
>>>
340348
>>> asyncio.run(xplusy(2, 2), loop_factory=lambda:QEventLoop(app))
341-
349+
342350
If the event loop shall be used with an existing and already running QApplication
343351
it must be specified in the constructor via already_running=True
344352
In this case the user is responsible for loop cleanup with stop() and close()
@@ -420,7 +428,9 @@ def stop(*args):
420428
self.run_forever()
421429
finally:
422430
future.remove_done_callback(stop)
423-
self.__app.processEvents() # run loop one last time to process all the events
431+
self.__app.eventDispatcher().processEvents(
432+
AllEvents
433+
) # run loop one last time to process all the events
424434
if not future.done():
425435
raise RuntimeError("Event loop stopped before Future completed.")
426436

tests/test_qeventloop.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import asyncio
77
import ctypes
8+
import threading
89
import logging
910
import multiprocessing
1011
import os
@@ -874,6 +875,37 @@ async def main():
874875
assert not loop.is_running()
875876

876877

878+
def test_qeventloop_in_qthread():
879+
class CoroutineExecutorThread(qasync.QtCore.QThread):
880+
def __init__(self, coro):
881+
super().__init__()
882+
self.coro = coro
883+
self.loop = None
884+
885+
def run(self):
886+
self.loop = qasync.QEventLoop(self)
887+
asyncio.set_event_loop(self.loop)
888+
asyncio.run(self.coro)
889+
890+
def join(self):
891+
self.loop.stop()
892+
self.loop.close()
893+
self.wait()
894+
895+
event = threading.Event()
896+
897+
async def coro():
898+
await asyncio.sleep(0.1)
899+
event.set()
900+
901+
thread = CoroutineExecutorThread(coro())
902+
thread.start()
903+
904+
assert event.wait(timeout=1), "Coroutine did not execute successfully"
905+
906+
thread.join() # Ensure thread cleanup
907+
908+
877909
def teardown_module(module):
878910
"""
879911
Remove handlers from all loggers

0 commit comments

Comments
 (0)