Skip to content

Commit

Permalink
refactor(robot-server): consolidate runs into a single Run model (#8685)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous authored Nov 9, 2021
1 parent 4dfbc6f commit dcb5a37
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 440 deletions.
24 changes: 12 additions & 12 deletions robot-server/robot_server/runs/router/base_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
get_protocol_store,
)

from ..run_store import RunStore, RunNotFoundError
from ..run_store import RunStore, RunResource, RunNotFoundError
from ..run_view import RunView
from ..run_models import Run, RunCreateData, ProtocolRunCreateData, RunUpdate
from ..run_models import Run, RunCreate, RunUpdate
from ..engine_store import EngineStore, EngineConflictError
from ..dependencies import get_run_store, get_engine_store

Expand Down Expand Up @@ -88,7 +88,7 @@ class AllRunsLinks(BaseModel):
},
)
async def create_run(
request_body: Optional[RequestModel[RunCreateData]] = None,
request_body: Optional[RequestModel[RunCreate]] = None,
run_view: RunView = Depends(RunView),
run_store: RunStore = Depends(get_run_store),
engine_store: EngineStore = Depends(get_engine_store),
Expand All @@ -109,12 +109,10 @@ async def create_run(
created_at: Timestamp to attach to created run.
task_runner: Background task runner.
"""
create_data = request_body.data if request_body is not None else None
protocol_id = request_body.data.protocolId if request_body is not None else None
protocol_resource = None

if isinstance(create_data, ProtocolRunCreateData):
protocol_id = create_data.createParams.protocolId

if protocol_id is not None:
try:
protocol_resource = protocol_store.get(protocol_id=protocol_id)
except ProtocolNotFoundError as e:
Expand All @@ -132,10 +130,12 @@ async def create_run(
# them in the run resource
task_runner.run(engine_store.runner.join)

run = run_view.as_resource(
run = RunResource(
run_id=run_id,
protocol_id=protocol_id,
created_at=created_at,
create_data=create_data,
is_current=True,
actions=[],
)

run_store.upsert(run=run)
Expand Down Expand Up @@ -166,7 +166,7 @@ async def get_runs(
"""Get all runs.
Args:
run_view: Run model construction interface.
run_view: Run model manipulation interface.
run_store: Run storage interface.
engine_store: ProtocolEngine storage and control.
"""
Expand Down Expand Up @@ -210,7 +210,7 @@ async def get_run(
Args:
runId: Run ID pulled from URL.
run_view: Run model construction interface.
run_view: Run model manipulation interface.
run_store: Run storage interface.
engine_store: ProtocolEngine storage and control.
"""
Expand Down Expand Up @@ -290,7 +290,7 @@ async def update_run(
Args:
runId: Run ID pulled from URL.
request_body: Update data from request body.
run_view: Run model manipulation.
run_view: Run model manipulation interface.
run_store: Run storage interface.
engine_store: ProtocolEngine storage and control.
"""
Expand Down
152 changes: 56 additions & 96 deletions robot-server/robot_server/runs/run_models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
"""Request and response models for run resources."""
from enum import Enum
from datetime import datetime
from pydantic import BaseModel, Field
from typing import List, Optional, Union
from typing_extensions import Literal
from typing import List, Optional

from opentrons.protocol_engine import (
CommandStatus,
Expand All @@ -17,13 +15,6 @@
from .action_models import RunAction


class RunType(str, Enum):
"""All available run types."""

BASIC = "basic"
PROTOCOL = "protocol"


class RunCommandSummary(ResourceModel):
"""A stripped down model of a full Command for usage in a Run response."""

Expand All @@ -32,11 +23,38 @@ class RunCommandSummary(ResourceModel):
status: CommandStatus = Field(..., description="Execution status of the command.")


class _AbstractRun(ResourceModel):
"""Base run resource model."""
class LabwareOffsetVector(BaseModel):
"""An offset to apply to labware, in deck coordinates."""

x: float
y: float
z: float


class LabwareOffset(BaseModel):
"""An offset that the robot adds to a pipette's position when it moves to a labware.
During the run, if a labware is loaded whose definition URI and location
both match what's found here, the given offset will be added to all
pipette movements that use that labware as a reference point.
"""

id: str = Field(..., description="Unique labware offset record identifier.")
definitionUri: str = Field(..., description="The URI for the labware's definition.")
location: LabwareLocation = Field(
...,
description="Where the labware is located on the robot.",
)
offset: LabwareOffsetVector = Field(
...,
description="The offset applied to matching labware.",
)


class Run(ResourceModel):
"""Run resource model."""

id: str = Field(..., description="Unique run identifier.")
runType: RunType = Field(..., description="Specific run type.")
createdAt: datetime = Field(..., description="When the run was created")
status: RunStatus = Field(..., description="Execution status of the run")
current: bool = Field(
Expand All @@ -62,95 +80,48 @@ class _AbstractRun(ResourceModel):
...,
description="Labware that has been loaded into the run.",
)
labwareOffsets: List[LabwareOffset] = Field(
default_factory=list,
description="Labware offsets to apply as labware are loaded.",
)
protocolId: Optional[str] = Field(
None,
description=(
"Protocol resource being run, if any. If not present, the run may"
" still be used to execute protocol commands over HTTP."
),
)


class LabwareOffsetVector(BaseModel):
"""An offset to apply to labware, in deck coordinates."""

x: float
y: float
z: float


class LabwareOffset(BaseModel):
"""An offset that the robot adds to a pipette's position when it moves to a labware.
During the run, if a labware is loaded whose definition URI and location
both match what's found here, the given offset will be added to all
pipette movements that use that labware as a reference point.
"""
class LabwareOffsetCreate(BaseModel):
"""Create request data for a labware offset."""

definitionUri: str = Field(..., description="The URI for the labware's definition.")
location: LabwareLocation = Field(
..., description="Where the labware is located on the robot."
...,
description="Where the labware is located on the robot.",
)
offset: LabwareOffsetVector = Field(
..., description="The offset applied to matching labware."
)


class BasicRunCreateParams(BaseModel):
"""Creation parameters for a basic run."""

labwareOffsets: List[LabwareOffset] = Field(default_factory=list)


class BasicRunCreateData(BaseModel):
"""Creation request data for a basic run."""

runType: Literal[RunType.BASIC] = Field(
RunType.BASIC,
description="The run type to create.",
)
# TODO(mc, 2021-05-25): how hard would it be to rename this field to `config`?
createParams: BasicRunCreateParams = Field(
default_factory=BasicRunCreateParams,
description="Parameters to set run behaviors at creation time.",
)


class BasicRun(_AbstractRun):
"""A run to execute commands without a previously loaded protocol file."""

runType: Literal[RunType.BASIC] = RunType.BASIC

createParams: BasicRunCreateParams


class ProtocolRunCreateParams(BaseModel):
"""Creation parameters for a protocol run."""

protocolId: str = Field(
...,
description="Unique identifier of the protocol this run will execute.",
description="The offset applied to matching labware.",
)

labwareOffsets: List[LabwareOffset] = Field(default_factory=list)

class RunCreate(BaseModel):
"""Create request data for a new run."""

class ProtocolRunCreateData(BaseModel):
"""Creation request data for a protocol run."""

runType: Literal[RunType.PROTOCOL] = Field(
RunType.PROTOCOL,
description="The run type to create.",
protocolId: Optional[str] = Field(
None,
description="Protocol resource ID that this run will be using, if applicable.",
)
# TODO(mc, 2021-05-25): how hard would it be to rename this field to `config`?
createParams: ProtocolRunCreateParams = Field(
...,
description="Parameters to set run behaviors at creation time.",
labwareOffsets: List[LabwareOffsetCreate] = Field(
default_factory=list,
description="Labware offsets to apply as labware are loaded.",
)


class ProtocolRun(_AbstractRun):
"""A run to execute commands with a previously loaded protocol file."""

runType: Literal[RunType.PROTOCOL] = RunType.PROTOCOL
createParams: ProtocolRunCreateParams


class RunUpdate(BaseModel):
"""Update request data for a run."""
"""Update request data for an existing run."""

current: Optional[bool] = Field(
None,
Expand All @@ -159,14 +130,3 @@ class RunUpdate(BaseModel):
" Setting `current` to `false` will deactivate the run."
),
)


RunCreateData = Union[
BasicRunCreateData,
ProtocolRunCreateData,
]

Run = Union[
BasicRun,
ProtocolRun,
]
5 changes: 2 additions & 3 deletions robot-server/robot_server/runs/run_store.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"""Runs' in-memory store."""
from dataclasses import dataclass, replace
from datetime import datetime
from typing import Dict, List
from typing import Dict, List, Optional

from .run_models import RunCreateData
from .action_models import RunAction


Expand All @@ -16,7 +15,7 @@ class RunResource:
"""

run_id: str
create_data: RunCreateData
protocol_id: Optional[str]
created_at: datetime
actions: List[RunAction]
is_current: bool
Expand Down
Loading

0 comments on commit dcb5a37

Please sign in to comment.