Skip to content

tests: Destroy Qt objects left behind by GUI tests - #1548

Open
apyrgio wants to merge 1 commit into
mainfrom
1547-qt-teardown
Open

tests: Destroy Qt objects left behind by GUI tests#1548
apyrgio wants to merge 1 commit into
mainfrom
1547-qt-teardown

Conversation

@apyrgio

@apyrgio apyrgio commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

By the time a GUI test is over, pytest-qt has called close() and deleteLater() on every widget registered with qtbot.addWidget(), and has run processEvents() a few times. That is not enough to actually destroy them:

  • deleteLater() merely posts a DeferredDelete event, and Qt delivers those only from within a running event loop. There is none at teardown time, so the deletions pile up unprocessed.
  • The widgets that the application creates without a parent, such as MainWindow.file_dialog or the various Alert dialogs, are not registered with pytest-qt in the first place.

The result is that a Qt test leaves roughly a dozen live widgets behind, and since pytest holds on to the fixtures that reference them for the whole session, they are only ever destroyed by the interpreter's final garbage collection pass -- in an order that PySide does not control, and possibly after the QApplication itself is gone. On Windows this occasionally faults after pytest has already reported the test as passed, which fails the CI run with no indication of which test process died.

So we destroy them here instead, while the QApplication is still alive and we are still in control of the ordering.

Refs #493
Closes #1547

By the time a GUI test is over, pytest-qt has called `close()` and
`deleteLater()` on every widget registered with `qtbot.addWidget()`, and
has run `processEvents()` a few times. That is not enough to actually
destroy them:

* `deleteLater()` merely posts a DeferredDelete event, and Qt delivers
  those only from within a running event loop. There is none at teardown
  time, so the deletions pile up unprocessed.
* The widgets that the application creates without a parent, such as
  `MainWindow.file_dialog` or the various `Alert` dialogs, are not
  registered with pytest-qt in the first place.

The result is that a Qt test leaves roughly a dozen live widgets behind,
and since pytest holds on to the fixtures that reference them for the
whole session, they are only ever destroyed by the interpreter's final
garbage collection pass -- in an order that PySide does not control, and
possibly after the QApplication itself is gone. On Windows this
occasionally faults *after* pytest has already reported the test as
passed, which fails the CI run with no indication of which test process
died.

So we destroy them here instead, while the QApplication is still alive
and we are still in control of the ordering.

Refs #493
Closes #1547
@apyrgio apyrgio added the no changelog For pull requests that do not require changelog updates (typos, clarifications, etc.) label Aug 11, 2026
@apyrgio
apyrgio requested a review from almet August 13, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog For pull requests that do not require changelog updates (typos, clarifications, etc.)

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Flakiness in GUI tests during teardown

1 participant