Repository navigation
GUI: Resume button resumes a paused plan (run RE.resume() on the main thread) - #94
Merged
Jakub Wlodek (jwlodek) merged 3 commits intoOct 8, 2026
Merged
Conversation
In local mode the Resume button ran RE.resume() in a FunctionWorker thread. resume() enters bluesky's SigintHandler, and Python lets only the main thread install signal handlers, so it raised ValueError('signal only works in main thread of the main interpreter'). The button listened only for 'finished', never 'errored', so the click did nothing visible and the plan stayed paused. Resume now goes through run_in_ipython like RE(plan(...)) does.
Verified with mock tests: test_resume_button_resumes_a_paused_plan pauses a running scan with Pause: Immediate and presses Resume; it failed (RE stayed paused) before this change.
Assisted-by: copilot:claude-opus-4-8
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Custom RunEngine resolution is broken, and the regression test is skipped by all CI test jobs.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Routes local RunEngine resume actions through IPython’s main thread and adds a regression test.
Changes:
- Replaces worker-thread resume execution with deferred IPython execution.
- Adds an offscreen Qt pause/resume integration test.
| File | Description |
|---|---|
src/hextools/gui/re_execution_controls.py |
Moves resume execution to the main thread. |
tests/test_re_execution_controls.py |
Tests resuming a paused simulated scan. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review on PR 94: resuming by the name in the IPython shell could resume a different engine (or raise) when the controls were given re= or their own namespace. Resume now targets the resolved engine, still on the main thread: through IPython when that engine is the shell's RE (so the terminal echoes it), directly after the click otherwise. Pinned by test_resume_button_resumes_a_paused_plan[re|namespace], observed failing before this change. GUI tests move to tests/gui/ and a new CI job runs them in the gui-dev environment (offscreen Qt); the py3.11-3.13 jobs lack Qt and skip them. Assisted-by: copilot:claude-opus-4-8
Jakub Wlodek (jwlodek)
requested changes
Oct 6, 2026
…t uses RE Review on PR 94 (Jakub, agreeing with Copilot): scheduling resume() for after the click left the button enabled until the 0.5 s poll, so a double-click queued two resume() calls; the second ran while the plan was already running. Resume now disables itself on click and a pending flag keeps it disabled (the poller included) until resume() returns, at completion or at the next pause. The old worker-thread version had this guard; moving to the main thread dropped it. Verified with mock tests: test_double_click_on_resume_resumes_once observed failing (resume() called twice: paused, running), passes now; all 4 GUI tests pass. Tests name the engine RE (Jakub). Assisted-by: copilot:claude-opus-4-8
Jakub Wlodek (jwlodek)
approved these changes
Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Problem
At HEX, in the GUI's in-process mode (
pixi run hex-gui), an EDXD scan paused with Pause: Immediate could not be resumed: pressing Resume did nothing and the RunEngine stayedpaused.Cause
The local-mode Resume button ran
RE.resume()in aFunctionWorkerthread.resume()enters bluesky'sSigintHandler, and Python only lets the main thread install signal handlers, so it raisedValueError: signal only works in main thread of the main interpreter. The button connected only the worker'sfinishedsignal, noterrored, so the failure was invisible. Plans themselves are started on the main thread (RE(plan(...))through IPython), so only Resume was affected; Stop/Abort/Halt run on the Qt main thread already. The scan type is not involved: any paused plan fails the same way.Fix
Resume goes through
run_in_ipython("RE.resume()")after the click returns, the same routeRE(plan(...))takes. The[GUI] RE.resume()line is echoed in the terminal like a plan call.How this was verified
tests/test_re_execution_controls.pydrives the realQtReExecutionControls(local=True)offscreen with an IPython shell and a simulated RunEngine (ophyd.sim): it starts a scan, presses Pause: Immediate, then Resume, and asserts the scan completes. It was observed failing onmain(RE stayedpaused) and passes with this change. It needs Qt, so it runs in thegui-devenvironment and is skipped whereqtpy/bluesky_widgetsare absent.