aboutsummaryrefslogtreecommitdiffstats
path: root/examples/async/minimal/minimal_asyncio.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/async/minimal/minimal_asyncio.py')
-rw-r--r--examples/async/minimal/minimal_asyncio.py59
1 files changed, 32 insertions, 27 deletions
diff --git a/examples/async/minimal/minimal_asyncio.py b/examples/async/minimal/minimal_asyncio.py
index 337a2558d..497e388a1 100644
--- a/examples/async/minimal/minimal_asyncio.py
+++ b/examples/async/minimal/minimal_asyncio.py
@@ -5,18 +5,17 @@ from PySide6.QtCore import (Qt, QEvent, QObject, Signal, Slot)
from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget)
import asyncio
-import outcome
import signal
import sys
-import traceback
class MainWindow(QMainWindow):
- def __init__(self, async_signal):
- super().__init__()
+ start_signal = Signal()
+ done_signal = Signal()
- self.async_signal = async_signal
+ def __init__(self):
+ super().__init__()
widget = QWidget()
self.setCentralWidget(widget)
@@ -32,21 +31,20 @@ class MainWindow(QMainWindow):
@Slot()
def async_start(self):
- self.async_signal.emit()
+ self.start_signal.emit()
async def set_text(self):
await asyncio.sleep(1)
self.text.setText("What do you get if you multiply six by nine?")
+ self.done_signal.emit()
class AsyncHelper(QObject):
- trigger_signal = Signal()
-
class ReenterQtObject(QObject):
""" This is a QObject to which an event will be posted, allowing
- Trio to resume when the event is handled. event.fn() is the
- next entry point of the Trio event loop. """
+ asyncio to resume when the event is handled. event.fn() is
+ the next entry point of the asyncio event loop. """
def event(self, event):
if event.type() == QEvent.User + 1:
event.fn()
@@ -55,22 +53,26 @@ class AsyncHelper(QObject):
class ReenterQtEvent(QEvent):
""" This is the QEvent that will be handled by the ReenterQtObject.
- self.fn is the next entry point of the Trio event loop. """
+ self.fn is the next entry point of the asyncio event loop. """
def __init__(self, fn):
super().__init__(QEvent.Type(QEvent.User + 1))
self.fn = fn
- def __init__(self, entry=None):
+ def __init__(self, worker, entry):
super().__init__()
self.reenter_qt = self.ReenterQtObject()
self.entry = entry
self.loop = asyncio.new_event_loop()
+ self.done = False
- def set_entry(self, entry):
- self.entry = entry
+ self.worker = worker
+ if hasattr(self.worker, "start_signal") and isinstance(self.worker.start_signal, Signal):
+ self.worker.start_signal.connect(self.on_worker_started)
+ if hasattr(self.worker, "done_signal") and isinstance(self.worker.done_signal, Signal):
+ self.worker.done_signal.connect(self.on_worker_done)
@Slot()
- def launch_guest_run(self):
+ def on_worker_started(self):
""" To use asyncio and Qt together, one must run the asyncio
event loop as a "guest" inside the Qt "host" event loop. """
if not self.entry:
@@ -78,13 +80,23 @@ class AsyncHelper(QObject):
asyncio.set_event_loop(self.loop)
self.loop.create_task(self.entry())
self.loop.call_soon(self.next_guest_run_schedule)
+ self.done = False # Set this explicitly as we might want to restart the guest run.
self.loop.run_forever()
+ @Slot()
+ def on_worker_done(self):
+ """ When all our current asyncio tasks are finished, we must end
+ the "guest run" lest we enter a quasi idle loop of switching
+ back and forth between the asyncio and Qt loops. We can
+ launch a new guest run by calling launch_guest_run() again. """
+ self.done = True
+
def continue_loop(self):
""" This function is called by an event posted to the Qt event
- loop to restart the asyncio event loop. """
- self.loop.call_soon(self.next_guest_run_schedule)
- self.loop.run_forever()
+ loop to continue the asyncio event loop. """
+ if not self.done:
+ self.loop.call_soon(self.next_guest_run_schedule)
+ self.loop.run_forever()
def next_guest_run_schedule(self):
""" This function serves to pause and re-schedule the guest
@@ -102,15 +114,8 @@ class AsyncHelper(QObject):
if __name__ == "__main__":
app = QApplication(sys.argv)
- async_helper = AsyncHelper()
- main_window = MainWindow(async_helper.trigger_signal)
- async_helper.set_entry(main_window.set_text)
-
- # This establishes the entry point for the Trio guest run. It varies
- # depending on how and when its event loop is to be triggered, e.g.,
- # at a specific moment like a button press (as here) or rather from
- # the beginning.
- async_helper.trigger_signal.connect(async_helper.launch_guest_run)
+ main_window = MainWindow()
+ async_helper = AsyncHelper(main_window, main_window.set_text)
main_window.show()