aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Herrmann <adrian.herrmann@qt.io>2024-01-25 02:05:15 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-01-30 14:11:54 +0000
commitce29b3372e75fccc24ca16651266569a674f1604 (patch)
tree548f30b9d597697809995c6ea44ded572d64228d
parentd956fd5c17a77c369cb937a163b0d31b714015c8 (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__.py5
-rw-r--r--sources/pyside6/PySide6/QtAsyncio/events.py17
-rw-r--r--sources/pyside6/doc/PySide6/QtAsyncio/index.rst13
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
^^^^^^^^^^^^^^^^^^^^