CabbageDevelopment / qasync

Python library for using asyncio in Qt-based applications.
BSD 2-Clause "Simplified" License
334 stars 45 forks source link

Fix qasync.run in Python 3.11 #83

Closed veractor closed 1 year ago

veractor commented 1 year ago

QEventLoops previously set themselves as the running loop by default on construction, regardless of if they are actually running or not. For already_running loops, this is fine, but for non-already_running loops, this setting of the running loop is premature.

This is because asyncio may check for an existing running loop after it constructs a new QEventLoop, but before running it. If it does, it will falsely detect the newly constructed, never ran loop as the "running" loop.

This didn't happen until Python 3.11, where asyncio.run checks for a running loop both before and after getting a new QEventLoop with the use of the new asyncio.Runner.run, hence raising a RuntimeError.

Set QEventLoops as the running loop on construction exclusively when they are already running. This means the set_running_loop constructor parameter is now unused, but for backwards compatibility I've left it intact (as existing code already referred to this parameter by keyword).

The original commit that put it there was, from what I can tell, in response to a RuntimeError raised when calling asyncio.sleep because of Python 3.8 switching to using get_running_loop in asyncio.sleep in place of get_event_loop. For non-already_running loops, since the fix in #75, this is redundant, as QEventLoop.run_forever sets the running loop.

Fixes #68.

hosaka commented 1 year ago

Looks good, thank you for submitting! Sorry it took a while.