From 97de8a397281c1f80855eac129a43e98946c1cd6 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Fri, 17 May 2024 16:58:18 -0400 Subject: [PATCH 1/3] this definitely should only happen with no result --- api/src/opentrons/protocol_engine/state/commands.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/src/opentrons/protocol_engine/state/commands.py b/api/src/opentrons/protocol_engine/state/commands.py index 7500b16d631..bd171d88cfd 100644 --- a/api/src/opentrons/protocol_engine/state/commands.py +++ b/api/src/opentrons/protocol_engine/state/commands.py @@ -384,12 +384,12 @@ def handle_action(self, action: Action) -> None: # noqa: C901 else: self._state.run_result = RunResult.STOPPED - if not self._state.run_error and action.error_details: - self._state.run_error = self._map_run_exception_to_error_occurrence( - action.error_details.error_id, - action.error_details.created_at, - action.error_details.error, - ) + if not self._state.run_error and action.error_details: + self._state.run_error = self._map_run_exception_to_error_occurrence( + action.error_details.error_id, + action.error_details.created_at, + action.error_details.error, + ) elif isinstance(action, HardwareStoppedAction): self._state.queue_status = QueueStatus.PAUSED From 4c30bf5d0fb833762cffb0bace7add9b01236004 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Fri, 17 May 2024 17:26:41 -0400 Subject: [PATCH 2/3] fix estop handling --- api/src/opentrons/protocol_engine/state/commands.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/src/opentrons/protocol_engine/state/commands.py b/api/src/opentrons/protocol_engine/state/commands.py index bd171d88cfd..0c055fdee39 100644 --- a/api/src/opentrons/protocol_engine/state/commands.py +++ b/api/src/opentrons/protocol_engine/state/commands.py @@ -390,6 +390,15 @@ def handle_action(self, action: Action) -> None: # noqa: C901 action.error_details.created_at, action.error_details.error, ) + else: + # HACK(sf): There needs to be a better way to set + # an estop error than this else clause + if self._state.stopped_by_estop and action.error_details: + self._state.run_error = self._map_run_exception_to_error_occurrence( + action.error_details.error_id, + action.error_details.created_at, + action.error_details.error, + ) elif isinstance(action, HardwareStoppedAction): self._state.queue_status = QueueStatus.PAUSED From 26f9ada2e9af906cc14e2ad0940407914146e39c Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Fri, 17 May 2024 18:32:50 -0400 Subject: [PATCH 3/3] test(api): Add a unit test for RQA-2737 (#15216) --- .../state/test_command_state.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/api/tests/opentrons/protocol_engine/state/test_command_state.py b/api/tests/opentrons/protocol_engine/state/test_command_state.py index 742abf3e6e9..01b9186ac9b 100644 --- a/api/tests/opentrons/protocol_engine/state/test_command_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_command_state.py @@ -469,3 +469,33 @@ def test_final_state_after_estop() -> None: assert subject_view.get_status() == EngineStatus.FAILED assert subject_view.get_error() == expected_error_occurrence + + +def test_final_state_after_stop() -> None: + """Test the final state of the run after it's stopped.""" + subject = CommandStore(config=_make_config(), is_door_open=False) + subject_view = CommandView(subject.state) + + subject.handle_action(actions.StopAction()) + subject.handle_action( + actions.FinishAction( + error_details=actions.FinishErrorDetails( + error=RuntimeError( + "uh oh I was a command and then I got cancelled because someone" + " stopped the run, and now I'm raising this exception because" + " of that. Woe is me" + ), + error_id="error-id", + created_at=datetime.now(), + ) + ) + ) + subject.handle_action( + actions.HardwareStoppedAction( + completed_at=sentinel.hardware_stopped_action_completed_at, + finish_error_details=None, + ) + ) + + assert subject_view.get_status() == EngineStatus.STOPPED + assert subject_view.get_error() is None