Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asyncio.CancelledError not caught in asyncSlot error handler #126

Open
QQ80 opened this issue Sep 9, 2024 · 1 comment
Open

asyncio.CancelledError not caught in asyncSlot error handler #126

QQ80 opened this issue Sep 9, 2024 · 1 comment

Comments

@QQ80
Copy link

QQ80 commented Sep 9, 2024

For coroutines decorated with asyncSlot, if the enclosing task is cancelled, the asyncio.CancelledError is left uncaught. This is a problem if another signal triggers the cancelling of that enclosing task, while it is awaiting for something.

I believe the error handler at line 778 of qasync/__init__.py should handle asyncio.CancelledError with something like this:

    def _error_handler(task):
        try:
            task.result()
        except Exception:
            sys.excepthook(*sys.exc_info())
        except asyncio.CancelledError:
            pass

Note that since Python 3.8, asyncio.CancelledError is a derived class of BaseException but not Exception.

@QQ80
Copy link
Author

QQ80 commented Sep 9, 2024

Here's a minimal example:

import asyncio
import qasync
from PyQt6.QtWidgets import QApplication, QPushButton


app: QApplication


@qasync.asyncSlot(bool)
async def button_clicked(_checked):
    match app.button.text():
        case "Wait":
            app.button.setText("Cancel wait")

            app.waiting_task = asyncio.current_task()
            await asyncio.sleep(5)

            app.button.setText("Wait")

        case "Cancel wait":
            app.waiting_task.cancel()

            app.button.setText("Wait")


async def main():
    global app
    app = QApplication.instance()
    app_quit_event = asyncio.Event()
    app.aboutToQuit.connect(app_quit_event.set)

    app.button = QPushButton("Wait")
    app.button.clicked.connect(button_clicked)
    app.button.show()

    await app_quit_event.wait()


qasync.run(main())

The exception is uncaught if "Wait" is pressed, and, while "Cancel wait" is shown, the button is pressed again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant