fix(ci): run GUI test under pyqt5 instead of skipping#595
Conversation
test_HighContentScreeningGui.py has been --ignore'd in CI since #391 due to a PySide6 QObject double-init failure. The known-good local recipe (force qtpy/pytest-qt onto PyQt5) works headless, and setup_22.04.sh already installs PyQt5 via apt (python3-pyqt5), so pin QT_API/PYTEST_QT_API=pyqt5 at the job level and drop the --ignore. Verified locally headless under the pin: 5 passed in 17.9s. The PySide6 double-init itself remains unfixed (tracked separately). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First CI run showed the pyqt5 pin works (the GUI test passed), but running it in the shared pytest process deterministically segfaults a later Qt test (test_channel_sequence.py:116 qtbot.waitUntil) — reproduced locally on macOS with the same two-file ordering (exit 139). The GUI test leaves Qt/thread state behind (faulthandler dump shows the simulated-camera stream thread and slack-notifier worker still alive). Keep the main run ignoring it and add a second pytest invocation for the GUI test alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
CI finding + fix (second commit): the first run proved the pyqt5 pin works — Fix: keep the main pytest run ignoring the GUI test and run it as its own pytest invocation in a second step — it is now enforced in CI, just process-isolated. This also resolves the original mystery: with no env pin, pytest-qt picked PySide6 for |
With the job-level pin, the main pytest run passed all 1413 tests and then segfaulted at interpreter shutdown — the pin flips pytest-qt/qtpy binding selection for the whole suite, hitting PyQt5's destructor-order-vs-GC conflict at exit (the reason main_hcs.py uses os._exit()). Master runs the main suite unpinned and green, so keep it identical and pin only the isolated GUI-test step, which is the invocation that needs it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Second CI finding: the job-level pin had a wider blast radius than intended — the main run (still Pushed |
Third CI iteration: the isolated GUI-test step passed (5/5) but the process segfaulted during interpreter shutdown — under PyQt5, a process that constructed the full HCS GUI crashes in Qt C++ destructors at exit even when every test passed. This is the same crash main_hcs.py avoids with os._exit(). Add an env-gated (SQUID_PYTEST_HARD_EXIT=1) pytest_unconfigure hook that flushes output and os._exit()s with pytest's real exit status, and set the variable only on the isolated CI step. Verified locally: summary still prints, pass exits 0, failure exits 1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Third CI finding + fix ( Fix mirrors the product's own solution: an env-gated ( |
Review finding (Opus): if pytest_sessionfinish never runs (a pytest_sessionstart failure leaves initstate==1, where unconfigure still fires), the previous default of 0 would turn a broken session into a green CI step. Default to 1 so an unrecorded status fails the gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… suite has the same flaky exit segfault The round-4 CI failure on this PR was the main run (byte-identical invocation to master's) segfaulting at interpreter shutdown after 1413 tests passed. Master itself fails the same way — 3 of its last 15 runs: 'N passed' followed by 'Segmentation fault (core dumped)' exit 139 (runs 28883871972, 28762269294, 28559414408). This also retroactively explains this PR's round-2 failure, which was misattributed to the job-level Qt pin. Set SQUID_PYTEST_HARD_EXIT=1 on the main step as well: after the session completes and all reporting is written, the conftest hook os._exit()s with pytest's real status — genuine failures still fail the step, and the ~20%-flaky Qt-teardown crash stops failing green runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Round-4 CI failure root-caused — it's a pre-existing master flake, and this PR now fixes it ( The failing run was the main pytest step — byte-identical invocation to master's ( Fix: set |
Summary
tests/control/test_HighContentScreeningGui.pyhas been--ignore'd in CI since #391 with the note "PySide6 QObject double-init bug". This PR stops skipping it:QT_API: pyqt5andPYTEST_QT_API: pyqt5as job-level env inmain.yml, forcing qtpy/pytest-qt onto PyQt5 (the known-good local recipe).--ignorefrom the pytest invocation.setup_22.04.shalready installs PyQt5 via apt (python3-pyqt5), so no dependency changes are needed.Verification
configurations/configuration_Squid+.ini, same file CI copies): 5 passed in 17.9s.Open question (documented, not fixed here)
The PySide6 QObject double-init failure itself is unchanged: under PySide6, GUI construction in the test fails (qtpy picks PySide6 when it's importable). Pinning CI to PyQt5 matches the production launch path (
main_hcs.pyandrun_acquisition.pyboth setQT_API=pyqt5), so this is an acceptable steady state; root-causing the PySide6 path (likely theQtMultiPointController(MultiPointController, QObject)multiple-inheritance init pattern) remains a separate issue if PySide6 support is ever wanted.🤖 Generated with Claude Code