Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,15 @@ class MainWindow(QWidget):
if __name__ == "__main__":
app = QApplication(sys.argv)

event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)

app_close_event = asyncio.Event()
app.aboutToQuit.connect(app_close_event.set)

main_window = MainWindow()
main_window.show()

with event_loop:
event_loop.run_until_complete(app_close_event.wait())
# for 3.11 or older use qasync.run instead of asyncio.run
# qasync.run(app_close_event.wait())
asyncio.run(app_close_event.wait(), loop_factory=QEventLoop)
```

More detailed examples can be found [here](https://github.com/CabbageDevelopment/qasync/tree/master/examples).
Expand Down
16 changes: 9 additions & 7 deletions examples/aiohttp_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
QVBoxLayout,
QWidget,
)

from qasync import QEventLoop, asyncClose, asyncSlot


Expand Down Expand Up @@ -68,15 +69,16 @@ async def on_btn_fetch_clicked(self):
if __name__ == "__main__":
app = QApplication(sys.argv)

event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)

app_close_event = asyncio.Event()
app.aboutToQuit.connect(app_close_event.set)

main_window = MainWindow()
main_window.show()

event_loop.create_task(main_window.boot())
event_loop.run_until_complete(app_close_event.wait())
event_loop.close()
async def async_main():
asyncio.create_task(main_window.boot())
await app_close_event.wait()

# for 3.11 or older use qasync.run instead of asyncio.run
# qasync.run(async_main())
asyncio.run(async_main(), loop_factory=QEventLoop)
13 changes: 6 additions & 7 deletions examples/executor_example.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import functools
import asyncio
import time
import functools
import sys
import time

# from PyQt6.QtWidgets import
from PySide6.QtWidgets import QApplication, QProgressBar

from qasync import QEventLoop, QThreadExecutor


Expand Down Expand Up @@ -34,8 +35,6 @@ def last_50(progress, loop):
if __name__ == "__main__":
app = QApplication(sys.argv)

event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)

event_loop.run_until_complete(master())
event_loop.close()
# for 3.11 or older use qasync.run instead of asyncio.run
# qasync.run(master())
asyncio.run(master(), loop_factory=QEventLoop)
7 changes: 2 additions & 5 deletions qasync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,8 @@ class _QEventLoop:
... assert x + y == 4
... await asyncio.sleep(.1)
>>>
>>> loop = QEventLoop(app)
>>> asyncio.set_event_loop(loop)
>>> with loop:
... loop.run_until_complete(xplusy(2, 2))

>>> asyncio.run(xplusy(2, 2), loop_factory=lambda:QEventLoop(app))

If the event loop shall be used with an existing and already running QApplication
it must be specified in the constructor via already_running=True
In this case the user is responsible for loop cleanup with stop() and close()
Expand Down
66 changes: 66 additions & 0 deletions tests/test_qeventloop.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@

def test_can_handle_exception_in_executor(self, loop, executor):
with pytest.raises(ExceptionTester) as excinfo:
loop.run_until_complete(

Check failure on line 104 in tests/test_qeventloop.py

View workflow job for this annotation

GitHub Actions / macos-x86_64 / 3.12 / pyqt6

TestCanRunTasksInExecutor.test_can_handle_exception_in_executor[ProcessPoolExecutor] TimeoutError
asyncio.wait_for(
loop.run_in_executor(executor, self.blocking_failure),
timeout=3.0,
Expand Down Expand Up @@ -159,7 +159,7 @@
assert process.returncode == 0
assert received_stdout.strip() == b"Hello async world!"

loop.run_until_complete(asyncio.wait_for(mycoro(), timeout=3))

Check failure on line 162 in tests/test_qeventloop.py

View workflow job for this annotation

GitHub Actions / macos-x86_64 / 3.12 / pyqt6

test_can_read_subprocess TimeoutError


def test_can_communicate_subprocess(loop):
Expand Down Expand Up @@ -808,6 +808,72 @@
assert "seconds" in msg


@pytest.mark.skipif(sys.version_info < (3, 12), reason="Requires Python 3.12+")
def test_asyncio_run(application):
"""Test that QEventLoop is compatible with asyncio.run()"""
done = False
loop = None

async def main():
nonlocal done, loop
assert loop.is_running()
assert asyncio.get_running_loop() is loop
await asyncio.sleep(0.01)
done = True

def factory():
nonlocal loop
loop = qasync.QEventLoop(application)
return loop

asyncio.run(main(), loop_factory=factory)
assert done
assert loop.is_closed()
assert not loop.is_running()


@pytest.mark.skipif(sys.version_info < (3, 12), reason="Requires Python 3.12+")
def test_asyncio_run_cleanup(application):
"""Test that running tasks are cleaned up"""
task = None
cancelled = False

async def main():
nonlocal task, cancelled

async def long_task():
nonlocal cancelled
try:
await asyncio.sleep(10)
except asyncio.CancelledError:
cancelled = True

task = asyncio.create_task(long_task())
await asyncio.sleep(0.01)

asyncio.run(main(), loop_factory=lambda: qasync.QEventLoop(application))
assert cancelled


def test_qasync_run(application):
"""Test running with qasync.run()"""
done = False
loop = None

async def main():
nonlocal done, loop
loop = asyncio.get_running_loop()
assert loop.is_running()
await asyncio.sleep(0.01)
done = True

# qasync.run uses an EventLoopPolicy to create the loop
qasync.run(main())
assert done
assert loop.is_closed()
assert not loop.is_running()


def teardown_module(module):
"""
Remove handlers from all loggers
Expand Down
Loading