From 2c5ea7e6bff841f2362fafbca04cc5ea06570e5b Mon Sep 17 00:00:00 2001 From: x01dc Date: Thu, 29 Oct 2026 15:21:51 +0100 Subject: [PATCH] fix(csaxs): aerotech plot stops following once its window is closed A closed plot made every redraw fail with a warning for each line of each scan. The first failure now stops following the scans (unsubscribes) with one message to reopen the plot with csaxs.aerotech.plot(). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv --- .../plugins/cSAXS/aerotech.py | 12 +++++++++-- .../test_cSAXS_aerotech.py | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/cSAXS/aerotech.py b/csaxs_bec/bec_ipython_client/plugins/cSAXS/aerotech.py index 738469e7..22882e59 100644 --- a/csaxs_bec/bec_ipython_client/plugins/cSAXS/aerotech.py +++ b/csaxs_bec/bec_ipython_client/plugins/cSAXS/aerotech.py @@ -231,6 +231,14 @@ class _LivePositions: lines = list(self._lines) try: _draw(self.curves, lines) - except Exception as exc: # window closed, GUI restarted - logger.warning(f"csaxs.aerotech.plot: redraw failed: {exc}") + except Exception as exc: # window or plot closed, GUI restarted + # stop following instead of failing on every line of every scan + logger.warning( + f"csaxs.aerotech.plot: the plot is gone ({exc}); stopped following" + " the scans. Call csaxs.aerotech.plot() to open it again." + ) + self.stop() + if self.parent._live is self: + self.parent._live = None + return self._stop.wait(self.parent.REDRAW_INTERVAL) diff --git a/tests/tests_bec_ipython_client/test_cSAXS_aerotech.py b/tests/tests_bec_ipython_client/test_cSAXS_aerotech.py index b53ed302..49e8a053 100644 --- a/tests/tests_bec_ipython_client/test_cSAXS_aerotech.py +++ b/tests/tests_bec_ipython_client/test_cSAXS_aerotech.py @@ -145,3 +145,24 @@ def test_live_ignores_other_scans(): tool._live._on_scan_status(SimpleNamespace(value=status)) assert client.connector.register.call_count == registered tool.stop_plot() + + +def test_live_stops_once_when_the_plot_is_closed(): + client = _client() + waveform = _waveform(client) + forward, backward = mock.MagicMock(), mock.MagicMock() + forward.set_data.side_effect = RuntimeError("widget has been deleted") + waveform.plot.side_effect = [forward, backward] + client.history.__getitem__.side_effect = IndexError + tool = cSAXSAerotech(client) + with mock.patch( + "csaxs_bec.bec_ipython_client.plugins.cSAXS.aerotech.logger" + ) as logger: + tool.plot() + live = tool._live + live._set_lines(_snake(n_lines=2)) + live._worker.join(timeout=3) + assert not live._worker.is_alive() + assert tool._live is None + assert logger.warning.call_count == 1 + client.connector.unregister.assert_called()