Skip to content

Conversation

hosaka
Copy link
Collaborator

@hosaka hosaka commented Jul 22, 2025

No description provided.

@johnzhou721
Copy link
Contributor

@hosaka Try using macos-13 to get a x86_64 runner, it works.

@johnzhou721
Copy link
Contributor

johnzhou721 commented Jul 22, 2025

@hosaka Also, Python 3.12--3.13 is stable, so might add those as well.

EDIT Problem here: exclude these versions from PySide2, but only for Windows [edited again].

@johnzhou721
Copy link
Contributor

@hosaka Seems like some caching is occuring... pyqt5 and pyqt6 seemed preinstalled on the runner with wrong architechture. Try adding a step with

rm -rf $(poetry env info --path)

To remove the existing venv to see if things improve.

@johnzhou721
Copy link
Contributor

@hosaka Sorry, it's occuring at the install Qt not the deps step... I apologize for this wrong suggestion. I will addd another comment.

hosaka added 2 commits July 23, 2025 11:52
Exclude python versions incompatible with qt backend libs

Always get a qt backend in local venv, ignoring runner site-packages
@johnzhou721
Copy link
Contributor

@hosaka CI passed! Could you please explain the test modification?

@hosaka
Copy link
Collaborator Author

hosaka commented Jul 23, 2025

A line was added to the test_regression_bug13 test case: d9b9efa#diff-121d712b1368fbfcf0184d7347fd376dcc31e1dfd513118a32d7b3ec2918d83fR590. This test has been added as a result of discussion in harvimt/quamash#13 way back in 2014.

The author talks about a use case where an async reader is removed from a file descriptor during the callback, and a async writer is added instead, or vice-versa (which appears to be a valid scenario). The test that resulted from that discussion replicates this condition but breaks in python 3.11 due to cb3() notifier callback being called multiple times since the reader callback has never been removed. In the __notifier_cb_wrapper there's a comment:

        try:
            callback(*args)
        finally:
            # The notifier might have been overriden by the
            # callback. We must not re-enable it in that case.
            if notifiers.get(fd, None) is notifier:
                notifier.setEnabled(True)

Since cb3 never "overridden the notifier" (aka called loop.remove_reader(c_sock.fileno()) the notifier gets re-enabled and fires again. It is expected from the user to remove the reader/writer in this case, hence this line was added to the test. While native event loop handles this differently (perhaps using a select()), we are bound by what QSocketNotifier and QApplication.processEvents() can provide us.

Test run in python 3.10 (cb callbacks act as one-shot events)

DEBUG    test_qeventloop.py:573 cb1
DEBUG    __init__.py:735 Removing reader callback for file descriptor 22
DEBUG    __init__.py:735 Adding writer callback for file descriptor 22
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({22: <P ySide6.QtCore.QSocketNotifier(0x558489e40210) at 0x7c2edffce5c0>}, <PySide6.QtCore.QSocketNotifier(0x558489e40210) at 0x7c2edffce5c0>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb2 at 0x7c2 edffb4820>, ()) after 0 second(s)
DEBUG    test_qeventloop.py:581 cb2
DEBUG    __init__.py:735 Removing writer callback for file descriptor 22
DEBUG    __init__.py:735 Adding reader callback for file descriptor 22
DEBUG    __init__.py:735 Socket notifier for fd 25 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <P ySide6.QtCore.QSocketNotifier(0x558489e465b0) at 0x7c2edffbbe40>, 25: <PySide6.QtCore.QSocketNotifier(0x558489e328c0) at 0x7c2edffcce00>, 22: <PySide6.QtCore.QSocketNotifier(0x558489e47290) at 0x7c2edffcebc0>}, <P ySide6.QtCore.QSocketNotifier(0x558489e328c0) at 0x7c2edffcce00>, 25, <bound method _SelectorSocketTransport._read_ready of <_SelectorSocketTransport fd=25 read=idle write=<idle, bufsize=0>>>, ()) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <built-in method task_wakeup of _asyncio.Task object at 0x7c2ef39392f0> to be invoked with arguments (<Future finished result=None cb=[Task.task_wak eup()]>,) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <function gather.<locals>._done_callback at 0x7c2edffb4f70> to be invoked with arguments (<Future finished result=True cb=[gather.<locals>._done_cal lback() at /home/alex/.local/share/mise/installs/python/3.10.18/lib/python3.10/asyncio/tasks.py:720]>,) after 0 second(s)
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <P ySide6.QtCore.QSocketNotifier(0x558489e465b0) at 0x7c2edffbbe40>, 25: <PySide6.QtCore.QSocketNotifier(0x558489e328c0) at 0x7c2edffcce00>, 22: <PySide6.QtCore.QSocketNotifier(0x558489e47290) at 0x7c2edffcebc0>}, <P ySide6.QtCore.QSocketNotifier(0x558489e47290) at 0x7c2edffcebc0>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7c2edffb5090>, ()) after 0 second(s)
DEBUG    test_qeventloop.py:589 cb3
DEBUG    __init__.py:735 Registering callback <function gather.<locals>._done_callback at 0x7c2edffb4f70> to be invoked with arguments (<Future finished result=True cb=[gather.<locals>._done_cal lback() at /home/alex/.local/share/mise/installs/python/3.10.18/lib/python3.10/asyncio/tasks.py:720]>,) after 0 second(s)
DEBUG    __init__.py:735 Registering callback functools.partial(<function _release_waiter at 0x7c2ef3b59990>, <Future pending cb=[Task.task_wakeup()]>) to be invoked with arguments (<_GatheringF uture finished result=[True, True] cb=[_release_waiter(<Future pendi...ask_wakeup()]>)() at /home/alex/.local/share/mise/installs/python/3.10.18/lib/python3.10/asyncio/tasks.py:387]>,) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <built-in method task_wakeup of _asyncio.Task object at 0x7c2ef3939150> to be invoked with arguments (<Future finished result=None cb=[Task.task_wak eup()]>,) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <function _QEventLoop.run_until_complete.<locals>.stop at 0x7c2edffb4ca0> to be invoked with arguments (<Task finished name='Task-36' coro=<wait_for () done, defined at /home/alex/.local/share/mise/installs/python/3.10.18/lib/python3.10/asyncio/tasks.py:392> result=[True, True] cb=[_QEventLoop.run_until_complete.<locals>.stop() at /home/alex/wa/qasync/qasync/_ _init__.py:398]>,) after 0 second(s)
DEBUG    __init__.py:735 Stopping event loop...
DEBUG    __init__.py:735 Stopped event loop
DEBUG    __init__.py:735 Qt event loop ended with result 0
DEBUG    __init__.py:735 Future <Task finished name='Task-36' coro=<wait_for() done, defined at /home/alex/.local/share/mise/installs/python/3.10.18/lib/python3.10/asyncio/tasks.py:392> result=[ True, True]> finished running
DEBUG    __init__.py:735 Closing event loop...
DEBUG    __init__.py:735 Removing reader callback for file descriptor 20
DEBUG    _unix.py:144 Closing

Same run in python 3.11 (followed by assert result3 is None failing because cb3() was invoked multiple times):

DEBUG    test_qeventloop.py:573 cb1
DEBUG    __init__.py:735 Removing reader callback for file descriptor 22
DEBUG    __init__.py:735 Adding writer callback for file descriptor 22
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({22: <PySide6.QtCore.QSocketNotifier(0x579b4a54be10) at 0x7646784e8900>}, <PySide6.QtCore.QSocketNotifier(0x579b4a54be10) at 0x7646784e8900>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb2 at 0x7646784cea20>, ()) after 0 second(s)
DEBUG    test_qeventloop.py:581 cb2
DEBUG    __init__.py:735 Removing writer callback for file descriptor 22
DEBUG    __init__.py:735 Adding reader callback for file descriptor 22
DEBUG    __init__.py:735 Socket notifier for fd 25 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 25: <PySide6.QtCore.QSocketNotifier(0x579b4a5471f0) at 0x7646784e1400>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80 >}, <PySide6.QtCore.QSocketNotifier(0x579b4a5471f0) at 0x7646784e1400>, 25, <bound method _SelectorSocketTransport._read_ready of <_SelectorSocketTransport fd=2 5 read=idle write=<idle, bufsize=0>>>, ()) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <built-in method task_wakeup of _as yncio.Task object at 0x7646784c0a00> to be invoked with arguments (<Future finished result=None cb=[Task.task_wakeup()]>,) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <function gather.<locals>._done_callback at 0x7646784ce7a0> to be invoked with arguments (<Future finished result=True cb=[gather.<locals>._done_callback() at /home/alex/.local/share/mise/installs/python/3.11.13/lib/python3.11/asyncio/tasks.py:764]>,) after 0 second(s)
DEBUG    __init__.py:735 Removing reader callback for file descriptor 25
DEBUG    __init__.py:735 Removing writer callback for file descriptor 25
DEBUG    __init__.py:735 Registering callback <bound method _SelectorSocketTransport._call_connection_lost of <_SelectorSocketTransport closing fd=25 read=idle write=<idle, bufsize=0>>> to be invoked with arguments (None,) after 0 second(s)
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>}, <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7646784cd300>, ()) after 0 second(s)
DEBUG    test_qeventloop.py:589 cb3
DEBUG    __init__.py:735 Registering callback <function gather.<locals>._done_callback at 0x7646784ce7a0> to be invoked with arguments (<Future finished result=True cb=[gather.<locals>._done_callback() at /home/alex/.local/share/mise/installs/python/3.11.13/lib/python3.11/asyncio/tasks.py:764]>,) after 0 second(s)
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>}, <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7646784cd300>, ()) after 0 second(s)
DEBUG    __init__.py:735 Registering callback functools.partial(<function _release_waiter at 0x7646815a20c0>, <Future pending cb=[Task.task_wakeup()]>) to be invoked with arguments (<_GatheringFuture finished result=[True, True] cb=[_release_waiter(<Future pendi...ask_wakeup()]>)() at /home/alex/.local/share/mise/installs/python/3.11.13/lib/python3.11/asyncio/tasks.py:431]>,) after 0 second(s)
DEBUG    test_qeventloop.py:589 cb3
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>}, <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7646784cd300>, ()) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <built-in method task_wakeup of _asyncio.Task object at 0x7646784c0940> to be invoked with arguments (<Future finished result=None cb=[Task.task_wakeup()]>,) after 0 second(s)
DEBUG    test_qeventloop.py:589 cb3
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>}, <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7646784cd300>, ()) after 0 second(s)
DEBUG    __init__.py:735 Registering callback <function _QEventLoop.run_until_complete.<locals>.stop at 0x7646784ce840> to be invoked with arguments (<Task finished name='Task-36' coro=<wait_for() done, defined at /home/alex/.local/share/mise/installs/python/3.11.13/lib/python3.11/asyncio/tasks.py:436> result=[True, True] cb=[_QEventLoop.run_until_complete.<locals>.stop() at /home/alex/wa/qasync/qa sync/__init__.py:398]>,) after 0 second(s)
DEBUG    test_qeventloop.py:589 cb3
DEBUG    __init__.py:735 Socket notifier for fd 22 is ready
DEBUG    __init__.py:735 Registering callback <bound method _QEventLoop.__notifier_cb_wrapper of <QSelectorEventLoop running=True closed=False debug=False>> to be invoked with arguments ({20: <PySide6.QtCore.QSocketNotifier(0x579b4a55bf80) at 0x7646784e2780>, 22: <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>}, <PySide6.QtCore.QSocketNotifier(0x579b4a55ede0) at 0x7646784e8f80>, 22, <function test_regression_bug13.<locals>.client_coro.<locals>.cb3 at 0x7646784cd300>, ()) after 0 second(s)
DEBUG    __init__.py:735 Stopping event loop...
DEBUG    __init__.py:735 Stopped event loop

@hosaka hosaka merged commit bbacb25 into master Jul 23, 2025
49 checks passed
@hosaka hosaka deleted the ci-python-3.11 branch July 23, 2025 04:19
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

Successfully merging this pull request may close these issues.

2 participants