Skip to content

Commit

Permalink
Merge branch 'edge' into skunk_grouped-steps-timeline-scrubber-pd-window
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader committed Jun 24, 2024
2 parents 0604088 + 68d4f77 commit 6eb6e96
Show file tree
Hide file tree
Showing 39 changed files with 1,159 additions and 703 deletions.
2 changes: 0 additions & 2 deletions api-client/src/runs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export * from './commands/types'

export const RUN_STATUS_IDLE = 'idle' as const
export const RUN_STATUS_RUNNING = 'running' as const
export const RUN_STATUS_PAUSE_REQUESTED = 'pause-requested' as const
export const RUN_STATUS_PAUSED = 'paused'
export const RUN_STATUS_STOP_REQUESTED = 'stop-requested' as const
export const RUN_STATUS_STOPPED = 'stopped' as const
Expand All @@ -26,7 +25,6 @@ export const RUN_STATUS_AWAITING_RECOVERY = 'awaiting-recovery' as const
export type RunStatus =
| typeof RUN_STATUS_IDLE
| typeof RUN_STATUS_RUNNING
| typeof RUN_STATUS_PAUSE_REQUESTED
| typeof RUN_STATUS_PAUSED
| typeof RUN_STATUS_STOP_REQUESTED
| typeof RUN_STATUS_STOPPED
Expand Down
2 changes: 1 addition & 1 deletion api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ push-no-restart-ot3: sdist

.PHONY: push-ot3
push-ot3: push-no-restart-ot3
$(call restart-server,$(host),$(host),$(ssh_opts),"opentrons-robot-server")
$(call restart-service,$(host),$(ssh_key),$(ssh_opts),"opentrons-robot-server")

.PHONY: simulate
simulate:
Expand Down
5 changes: 0 additions & 5 deletions api/src/opentrons/protocol_engine/state/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ def handle_action(self, action: Action) -> None: # noqa: C901
# TODO(mc, 2021-06-22): mypy has trouble with this automatic
# request > command mapping, figure out how to type precisely
# (or wait for a future mypy version that can figure it out).
# For now, unit tests cover mapping every request type
queued_command = action.request._CommandCls.construct(
id=action.command_id,
key=(
Expand Down Expand Up @@ -679,10 +678,6 @@ def get_is_door_blocking(self) -> bool:
"""Get whether the robot door is open when 'pause on door open' ff is True."""
return self._state.is_door_blocking

def get_is_implicitly_active(self) -> bool:
"""Get whether the queue is implicitly active, i.e., never 'played'."""
return self._state.queue_status == QueueStatus.SETUP

def get_is_running(self) -> bool:
"""Get whether the protocol is running & queued commands should be executed."""
return self._state.queue_status == QueueStatus.RUNNING
Expand Down
64 changes: 64 additions & 0 deletions api/tests/opentrons/protocol_engine/state/test_command_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,70 @@ def _make_config() -> Config:
)


def test_queue_command_action() -> None:
"""It should translate a command request into a queued command and add it."""
subject = CommandStore(is_door_open=False, config=_make_config())
subject_view = CommandView(subject.state)

id = "command-id"
key = "command-key"
params = commands.CommentParams(message="yay")
created_at = datetime(year=2021, month=1, day=1)
request = commands.CommentCreate(params=params, key=key)
action = actions.QueueCommandAction(
request=request,
request_hash=None,
created_at=created_at,
command_id=id,
)
expected_command = commands.Comment(
id=id,
key=key,
createdAt=created_at,
status=commands.CommandStatus.QUEUED,
params=params,
)

subject.handle_action(action)
assert subject_view.get("command-id") == expected_command
assert subject_view.get_all() == [expected_command]


def test_latest_protocol_command_hash() -> None:
"""It should return the latest protocol command's hash."""
subject = CommandStore(is_door_open=False, config=_make_config())
subject_view = CommandView(subject.state)

# The initial hash should be None.
assert subject_view.get_latest_protocol_command_hash() is None

# It should pick up the hash from an enqueued protocol command.
subject.handle_action(
actions.QueueCommandAction(
request=commands.CommentCreate(
params=commands.CommentParams(message="hello world"),
),
request_hash="hash-1",
command_id="command-id-1",
created_at=datetime.now(),
)
)
assert subject_view.get_latest_protocol_command_hash() == "hash-1"

# It should pick up newer hashes as they come in.
subject.handle_action(
actions.QueueCommandAction(
request=commands.CommentCreate(
params=commands.CommentParams(message="hello world"),
),
request_hash="hash-2",
command_id="command-id-2",
created_at=datetime.now(),
)
)
assert subject_view.get_latest_protocol_command_hash() == "hash-2"


@pytest.mark.parametrize("error_recovery_type", ErrorRecoveryType)
def test_command_failure(error_recovery_type: ErrorRecoveryType) -> None:
"""It should store an error and mark the command if it fails."""
Expand Down
218 changes: 1 addition & 217 deletions api/tests/opentrons/protocol_engine/state/test_command_store_old.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@

import pytest
from datetime import datetime
from typing import NamedTuple, Type

from opentrons_shared_data.errors import ErrorCodes
from opentrons_shared_data.pipette.dev_types import PipetteNameType

from opentrons.ordered_set import OrderedSet
from opentrons.protocol_engine.actions.actions import RunCommandAction
from opentrons.types import MountType, DeckSlotName
from opentrons.hardware_control.types import DoorState

from opentrons.protocol_engine import commands, errors
from opentrons.protocol_engine.types import DeckSlotLocation, DeckType, WellLocation
from opentrons.protocol_engine.types import DeckType
from opentrons.protocol_engine.state import Config
from opentrons.protocol_engine.state.commands import (
CommandState,
Expand Down Expand Up @@ -55,219 +52,6 @@ def _make_config(block_on_door_open: bool = False) -> Config:
)


@pytest.mark.parametrize(
("is_door_open", "config", "expected_is_door_blocking"),
[
(False, _make_config(), False),
(True, _make_config(), False),
(False, _make_config(block_on_door_open=True), False),
(True, _make_config(block_on_door_open=True), True),
],
)
def test_initial_state(
is_door_open: bool,
config: Config,
expected_is_door_blocking: bool,
) -> None:
"""It should set the initial state."""
subject = CommandStore(is_door_open=is_door_open, config=config)

assert subject.state == CommandState(
command_history=CommandHistory(),
queue_status=QueueStatus.SETUP,
run_completed_at=None,
run_started_at=None,
is_door_blocking=expected_is_door_blocking,
run_result=None,
run_error=None,
finish_error=None,
failed_command=None,
command_error_recovery_types={},
recovery_target_command_id=None,
latest_protocol_command_hash=None,
stopped_by_estop=False,
)


class QueueCommandSpec(NamedTuple):
"""Test data for the QueueCommandAction."""

command_request: commands.CommandCreate
expected_cls: Type[commands.Command]
created_at: datetime = datetime(year=2021, month=1, day=1)
command_id: str = "command-id"
command_key: str = "command-key"


@pytest.mark.parametrize(
QueueCommandSpec._fields,
[
QueueCommandSpec(
command_request=commands.AspirateCreate(
params=commands.AspirateParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
volume=42,
flowRate=1.23,
wellLocation=WellLocation(),
),
key="command-key",
),
expected_cls=commands.Aspirate,
),
QueueCommandSpec(
command_request=commands.DispenseCreate(
params=commands.DispenseParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
volume=42,
flowRate=1.23,
wellLocation=WellLocation(),
),
),
expected_cls=commands.Dispense,
# test when key prop is missing
command_key="command-id",
),
QueueCommandSpec(
command_request=commands.DropTipCreate(
params=commands.DropTipParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.DropTip,
),
QueueCommandSpec(
command_request=commands.LoadLabwareCreate(
params=commands.LoadLabwareParams(
location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1),
loadName="load-name",
namespace="namespace",
version=42,
),
key="command-key",
),
expected_cls=commands.LoadLabware,
),
QueueCommandSpec(
command_request=commands.LoadPipetteCreate(
params=commands.LoadPipetteParams(
mount=MountType.LEFT,
pipetteName=PipetteNameType.P300_SINGLE,
),
key="command-key",
),
expected_cls=commands.LoadPipette,
),
QueueCommandSpec(
command_request=commands.PickUpTipCreate(
params=commands.PickUpTipParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.PickUpTip,
),
QueueCommandSpec(
command_request=commands.MoveToWellCreate(
params=commands.MoveToWellParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.MoveToWell,
),
QueueCommandSpec(
command_request=commands.WaitForResumeCreate(
params=commands.WaitForResumeParams(message="hello world"),
key="command-key",
),
expected_cls=commands.WaitForResume,
),
QueueCommandSpec(
# a WaitForResumeCreate with `pause` should be mapped to
# a WaitForResume with `commandType="waitForResume"`
command_request=commands.WaitForResumeCreate(
commandType="pause",
params=commands.WaitForResumeParams(message="hello world"),
key="command-key",
),
expected_cls=commands.WaitForResume,
),
],
)
def test_command_store_queues_commands(
command_request: commands.CommandCreate,
expected_cls: Type[commands.Command],
created_at: datetime,
command_id: str,
command_key: str,
) -> None:
"""It should add a command to the store."""
action = QueueCommandAction(
request=command_request,
request_hash=None,
created_at=created_at,
command_id=command_id,
)
expected_command = expected_cls(
id=command_id,
key=command_key,
createdAt=created_at,
status=commands.CommandStatus.QUEUED,
params=command_request.params, # type: ignore[arg-type]
)

subject = CommandStore(is_door_open=False, config=_make_config())
subject.handle_action(action)

assert subject.state.command_history.get("command-id") == CommandEntry(
index=0, command=expected_command
)
assert subject.state.command_history.get_all_ids() == ["command-id"]
assert subject.state.command_history.get_queue_ids() == OrderedSet(["command-id"])


def test_command_queue_with_hash() -> None:
"""It should queue a command with a command hash and no explicit key."""
create = commands.WaitForResumeCreate(
params=commands.WaitForResumeParams(message="hello world"),
)

subject = CommandStore(is_door_open=False, config=_make_config())
subject.handle_action(
QueueCommandAction(
request=create,
request_hash="abc123",
created_at=datetime(year=2021, month=1, day=1),
command_id="command-id-1",
)
)

assert subject.state.command_history.get("command-id-1").command.key == "abc123"
assert subject.state.latest_protocol_command_hash == "abc123"

subject.handle_action(
QueueCommandAction(
request=create,
request_hash="def456",
created_at=datetime(year=2021, month=1, day=1),
command_id="command-id-2",
)
)

assert subject.state.latest_protocol_command_hash == "def456"


def test_command_queue_and_unqueue() -> None:
"""It should queue on QueueCommandAction and dequeue on RunCommandAction."""
queue_1 = QueueCommandAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ def test_get_next_to_execute_returns_no_commands_if_paused() -> None:
assert result is None


def test_get_next_to_execute_returns_no_commands_if_awaiting_recovery_no_fixit() -> None:
def test_get_next_to_execute_returns_no_commands_if_awaiting_recovery_no_fixit() -> (
None
):
"""It should not return any type of command if the engine is awaiting-recovery."""
subject = get_command_view(
queue_status=QueueStatus.AWAITING_RECOVERY,
Expand Down Expand Up @@ -1020,9 +1022,3 @@ def test_get_slice_default_cursor_queued() -> None:
cursor=2,
total_length=5,
)


def test_get_latest_command_hash() -> None:
"""It should get the latest command hash from state, if set."""
subject = get_command_view(latest_command_hash="abc123")
assert subject.get_latest_protocol_command_hash() == "abc123"
6 changes: 3 additions & 3 deletions app-shell-odd/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ export function getOverrides(path?: string): unknown {

export function getConfig<P extends keyof Config>(path: P): Config[P]
export function getConfig(): Config
export function getConfig(path?: string): any {
const result = path == null ? null : store().get(path)
const over = getOverrides(path)
export function getConfig(path?: any): any {
const result = store().get(path)
const over = getOverrides(path as string | undefined)

if (over != null) {
if (typeof result === 'object' && result != null) {
Expand Down
1 change: 1 addition & 0 deletions app/src/assets/localization/en/device_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"estop_disengaged": "E-stop disengaged, but robot operation still halted.",
"estop_pressed": "E-stop pressed. Robot movement is halted.",
"failed": "failed",
"files": "Files",
"firmware_update_needed": "Instrument firmware update needed. Start the update on the robot's touchscreen.",
"firmware_update_available": "Firmware update available.",
"firmware_update_failed": "Failed to update module firmware",
Expand Down
Loading

0 comments on commit 6eb6e96

Please sign in to comment.