pytest-dev / pytest-dev/pytest-qt

QApplication.processEvents() blocks qtbot on MacOS

Open
#284 12 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug :bug: macos :apple:
Dominant language
Python
Stars
455
Forks
72
Avg merge
12h 26m
Merged PRs (30d)
1

Description

If qtbot tries to stop waiting while QApplication.processEvents() is being called, the test will hang indefinitely.
What happens is that:

  • qtbot creates a QEventLoop
  • an event calling QApplication.processEvents() is processed by QEventLoop
  • The qtbot timer event that calls _quit_loop_by_timeout is processed by QApplication.processEvents()
  • Somehow self._loop.quit() doesn't quit the loop if it is called from QApplication.processEvents()

Code to reproduce (save as test_qtbot.py):

import pytest
import time
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QEventLoop, QTimer


class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._timer = QTimer(self)
        self._timer.setSingleShot(True)
        self._timer.setInterval(10)
        self._timer.timeout.connect(self._wait_process_events)
        self._timer.start()

    def _wait_process_events(self):
        time.sleep(1)
        QApplication.processEvents()


def test_qtbot(qtbot):
    """
    qtbot does the following:
    1. start QEventLoop
    2. process an event that calls QApplication.processEvents()
    3. this processes an event that calls loop.quit()
        which doesn't quit the wait loop
    """
    widget = MyWidget()
    qtbot.addWidget(widget)
    widget.show()
    qtbot.wait(500)

if __name__ == "__main__":
    pytest.main()

Versions I am using:

PyQt5                                   5.12.3
pytest                                  5.3.1         
pytest-qt                               3.2.2  

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the test_qtbot.py reproducer and trace qtbot's QEventLoop, the _quit_loop_by_timeout timer callback, and self._loop.quit(). Compare how QApplication.processEvents() dispatches the timeout event on macOS. Done means the reproduced qtbot.wait(500) test exits instead of hanging.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, python
Domain
desktop, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.