diff options
author | Adrian Herrmann <adrian.herrmann@qt.io> | 2024-01-25 02:05:15 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-01-30 14:11:54 +0000 |
commit | ce29b3372e75fccc24ca16651266569a674f1604 (patch) | |
tree | 548f30b9d597697809995c6ea44ded572d64228d | |
parent | d956fd5c17a77c369cb937a163b0d31b714015c8 (diff) |
QtAsyncio: Introduce quit_qapp argument
A new optional argument quit_qapp can be passed to QtAsyncio.run()
to configure whether the QCoreApplication at the core of QtAsyncio
should be shut down when asyncio finishes. A special case where one
would want to disable this is test suites that want to reuse a single
QCoreApplication instance across all unit tests, which would fail if
this instance is shut down every time.
Fixes: PYSIDE-2575
Task-number: PYSIDE-769
Change-Id: I49cd0a50311fb30cc50df9b7f6a6d73fe8c58613
Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
(cherry picked from commit 3bc157720e37198c99e2d9c8ce38185b894b2fdd)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/PySide6/QtAsyncio/__init__.py | 5 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtAsyncio/events.py | 17 | ||||
-rw-r--r-- | sources/pyside6/doc/PySide6/QtAsyncio/index.rst | 13 |
3 files changed, 28 insertions, 7 deletions
diff --git a/sources/pyside6/PySide6/QtAsyncio/__init__.py b/sources/pyside6/PySide6/QtAsyncio/__init__.py index f20dad96b..3830ad887 100644 --- a/sources/pyside6/PySide6/QtAsyncio/__init__.py +++ b/sources/pyside6/PySide6/QtAsyncio/__init__.py @@ -18,7 +18,8 @@ __all__ = [ def run(coro: typing.Optional[typing.Coroutine] = None, - keep_running: typing.Optional[bool] = True, *, + keep_running: bool = True, + quit_qapp: bool = True, *, debug: typing.Optional[bool] = None) -> None: """Run the QtAsyncio event loop.""" @@ -31,7 +32,7 @@ def run(coro: typing.Optional[typing.Coroutine] = None, # # More details: # https://discuss.python.org/t/removing-the-asyncio-policy-system-asyncio-set-event-loop-policy-in-python-3-15/37553 # noqa: E501 - asyncio.set_event_loop_policy(QAsyncioEventLoopPolicy()) + asyncio.set_event_loop_policy(QAsyncioEventLoopPolicy(quit_qapp=quit_qapp)) if keep_running: if coro: diff --git a/sources/pyside6/PySide6/QtAsyncio/events.py b/sources/pyside6/PySide6/QtAsyncio/events.py index 92ec1f5f9..aa89e984e 100644 --- a/sources/pyside6/PySide6/QtAsyncio/events.py +++ b/sources/pyside6/PySide6/QtAsyncio/events.py @@ -57,7 +57,9 @@ class QAsyncioExecutorWrapper(QObject): class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy): - def __init__(self, application: typing.Optional[QCoreApplication] = None) -> None: + def __init__(self, + application: typing.Optional[QCoreApplication] = None, + quit_qapp: bool = True) -> None: super().__init__() if application is None: if QCoreApplication.instance() is None: @@ -65,6 +67,7 @@ class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy): else: application = QCoreApplication.instance() self._application: QCoreApplication = application # type: ignore[assignment] + self._quit_qapp = quit_qapp self._event_loop: typing.Optional[asyncio.AbstractEventLoop] = None signal.signal(signal.SIGINT, signal.SIG_DFL) @@ -78,7 +81,7 @@ class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy): self._event_loop = loop def new_event_loop(self) -> asyncio.AbstractEventLoop: - return QAsyncioEventLoop(self._application) + return QAsyncioEventLoop(self._application, quit_qapp=self._quit_qapp) def get_child_watcher(self) -> asyncio.AbstractChildWatcher: raise DeprecationWarning("Child watchers are deprecated since Python 3.12") @@ -112,11 +115,13 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject): if not self._loop.is_closed(): self._loop.call_soon_threadsafe(self._future.set_exception, e) - def __init__(self, application: QCoreApplication) -> None: + def __init__(self, + application: QCoreApplication, quit_qapp: bool = True) -> None: asyncio.BaseEventLoop.__init__(self) QObject.__init__(self) self._application: QCoreApplication = application + self._quit_qapp = quit_qapp self._thread = QThread.currentThread() self._closed = False @@ -191,7 +196,8 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject): else: return self._quit_from_inside = True - self._application.quit() + if self._quit_qapp: + self._application.quit() def is_running(self) -> bool: return self._thread.loopLevel() > 0 @@ -206,7 +212,8 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject): return if self._default_executor is not None: self._default_executor.shutdown(wait=False) - self._application.shutdown() + if self._quit_qapp: + self._application.shutdown() self._closed = True async def shutdown_asyncgens(self) -> None: diff --git a/sources/pyside6/doc/PySide6/QtAsyncio/index.rst b/sources/pyside6/doc/PySide6/QtAsyncio/index.rst index e5c06de81..90c0ee670 100644 --- a/sources/pyside6/doc/PySide6/QtAsyncio/index.rst +++ b/sources/pyside6/doc/PySide6/QtAsyncio/index.rst @@ -118,6 +118,19 @@ or to run the coroutine and then stop the event loop upon its completion. This latter case behaves identically to ``asyncio.run(my_coroutine())``. +An additional optional argument ``quit_qapp`` can be passed to ``run()`` +to configure whether the QCoreApplication at the core of QtAsyncio +should be shut down when asyncio finishes. A special case where one +would want to disable this is test suites that want to reuse a single +QCoreApplication instance across all unit tests, which would fail if +this instance is shut down every time. The default is ``True``. + +Note that this argument is orthogonal to the ``keep_running`` argument. +``keep_running`` determines if **asyncio** should keep running after the +coroutine has finished, while ``quit_qapp`` determines if the +QCoreApplication should be shut down after asyncio has finished. It is +possible for asyncio to finish while the QCoreApplication is kept alive. + Coroutines explained ^^^^^^^^^^^^^^^^^^^^ |