Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(api): add a defined over pressure error to prepare to aspirate #16518

Merged
merged 28 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
487e9b3
prepare to aspirate over pressue
TamarZanzouri Oct 17, 2024
6a9115f
current position outside the try
TamarZanzouri Oct 18, 2024
a354759
change path to relative path
TamarZanzouri Oct 18, 2024
ee6d534
fix(labware-library): make labware creator accessible via external li…
shlokamin Oct 17, 2024
0df110c
fix(api): ER support for in place commands and blow out (#16510)
TamarZanzouri Oct 17, 2024
2ecbdcd
feat(protocol-designer): mix tools advanced settings and mix batch ed…
jerader Oct 17, 2024
addddb9
refactor(app): Update ignore error route in Error Recovery (#16511)
mjhuff Oct 17, 2024
65cedec
fix(api): add details to confusing error message (#16517)
TamarZanzouri Oct 17, 2024
c62be01
feat(api): add liquid class in PAPI (#16506)
sanni-t Oct 17, 2024
55cfc3e
feat(app): Add Error Recovery support for in-place commands (#16515)
mjhuff Oct 17, 2024
de72890
feat(app): implement system language modal (#16507)
brenthagen Oct 17, 2024
0b977af
fix(protocol-designer): add Eppendorf to removeOpentronsPhrases (#16470)
koji Oct 17, 2024
27a8768
fix(labware-library): fix labware-library css issue (#16502)
koji Oct 17, 2024
9b46870
test(abt): fix Makefile variable (#16525)
y3rsh Oct 17, 2024
a1df2db
feat(api): add WellVolumeOffset to WellLocation (#16302)
pmoegenburg Oct 17, 2024
2a3baaa
refactor(app-shell,app-shell-odd): update winston and improve logging…
sfoster1 Oct 18, 2024
17da47f
fix(analyses-snapshot-testing): heal edge snapshots (#16527)
github-actions[bot] Oct 18, 2024
2cdf0e0
fix(analyses-snapshot-testing): heal edge snapshots (#16526)
y3rsh Oct 18, 2024
9d92fad
fix(api): Fix path planning after failed tip drop (#16513)
SyntaxColoring Oct 18, 2024
286407b
refactor(app): update various error recovery copy/css (#16519)
mjhuff Oct 18, 2024
67dbb1e
fix(protocol-designer): enable color picker's alpha value (#16505)
koji Oct 18, 2024
b9d235c
fix(protocol-designer): fix remove settings icon button (#16524)
koji Oct 18, 2024
3903604
fix(protocol-designer): fix create button clickable area issue (#16522)
koji Oct 18, 2024
bad2d1b
refactor(api): Allow adding/removing tips on HW API without `await` (…
SyntaxColoring Oct 18, 2024
ccbff54
change path to relative path
TamarZanzouri Oct 18, 2024
8a9c6d9
Merge branch 'edge' into EXEC-557-overpressure-detected-during-prepar…
TamarZanzouri Oct 18, 2024
51beb8c
revert FE changes
TamarZanzouri Oct 18, 2024
bec7b33
revert test.json changes
TamarZanzouri Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 60 additions & 15 deletions api/src/opentrons/protocol_engine/commands/prepare_to_aspirate.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
"""Prepare to aspirate command request, result, and implementation models."""

from __future__ import annotations
from opentrons_shared_data.errors.exceptions import PipetteOverpressureError
from pydantic import BaseModel
from typing import TYPE_CHECKING, Optional, Type
from typing import TYPE_CHECKING, Optional, Type, Union
from typing_extensions import Literal

from .pipetting_common import (
OverpressureError,
PipetteIdMixin,
)
from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
from .command import (
AbstractCommandImpl,
BaseCommand,
BaseCommandCreate,
DefinedErrorData,
SuccessData,
)
from ..errors.error_occurrence import ErrorOccurrence

if TYPE_CHECKING:
from ..execution.pipetting import PipettingHandler
from ..execution import PipettingHandler, GantryMover
from ..resources import ModelUtils


PrepareToAspirateCommandType = Literal["prepareToAspirate"]

Expand All @@ -29,25 +39,60 @@ class PrepareToAspirateResult(BaseModel):
pass


_ExecuteReturn = Union[
SuccessData[PrepareToAspirateResult, None],
DefinedErrorData[OverpressureError],
]


class PrepareToAspirateImplementation(
AbstractCommandImpl[
PrepareToAspirateParams, SuccessData[PrepareToAspirateResult, None]
]
AbstractCommandImpl[PrepareToAspirateParams, _ExecuteReturn]
):
"""Prepare for aspirate command implementation."""

def __init__(self, pipetting: PipettingHandler, **kwargs: object) -> None:
def __init__(
self,
pipetting: PipettingHandler,
model_utils: ModelUtils,
gantry_mover: GantryMover,
**kwargs: object,
) -> None:
self._pipetting_handler = pipetting
self._model_utils = model_utils
self._gantry_mover = gantry_mover

async def execute(
self, params: PrepareToAspirateParams
) -> SuccessData[PrepareToAspirateResult, None]:
async def execute(self, params: PrepareToAspirateParams) -> _ExecuteReturn:
"""Prepare the pipette to aspirate."""
await self._pipetting_handler.prepare_for_aspirate(
pipette_id=params.pipetteId,
)

return SuccessData(public=PrepareToAspirateResult(), private=None)
try:
current_position = await self._gantry_mover.get_position(params.pipetteId)
TamarZanzouri marked this conversation as resolved.
Show resolved Hide resolved
await self._pipetting_handler.prepare_for_aspirate(
pipette_id=params.pipetteId,
)
except PipetteOverpressureError as e:
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
createdAt=self._model_utils.get_timestamp(),
wrappedErrors=[
ErrorOccurrence.from_failed(
id=self._model_utils.generate_id(),
createdAt=self._model_utils.get_timestamp(),
error=e,
)
],
errorInfo=(
{
"retryLocation": (
current_position.x,
current_position.y,
current_position.z,
)
}
),
),
)
else:
return SuccessData(public=PrepareToAspirateResult(), private=None)


class PrepareToAspirate(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
"""Test prepare to aspirate commands."""

from decoy import Decoy
from datetime import datetime
from opentrons.types import Point
import pytest
from decoy import Decoy, matchers

from opentrons.protocol_engine.execution import (
PipettingHandler,
)

from opentrons.protocol_engine.commands.command import SuccessData
from opentrons.protocol_engine.commands.command import DefinedErrorData, SuccessData
from opentrons.protocol_engine.commands.prepare_to_aspirate import (
PrepareToAspirateParams,
PrepareToAspirateImplementation,
PrepareToAspirateResult,
)
from opentrons.protocol_engine.execution.gantry_mover import GantryMover
from opentrons.protocol_engine.resources.model_utils import ModelUtils
from opentrons.protocol_engine.commands.pipetting_common import OverpressureError
from opentrons_shared_data.errors.exceptions import PipetteOverpressureError


@pytest.fixture
def subject(
pipetting: PipettingHandler,
model_utils: ModelUtils,
gantry_mover: GantryMover,
) -> PrepareToAspirateImplementation:
"""Get the implementation subject."""
return PrepareToAspirateImplementation(
pipetting=pipetting, model_utils=model_utils, gantry_mover=gantry_mover
)


async def test_prepare_to_aspirate_implmenetation(
decoy: Decoy, pipetting: PipettingHandler
decoy: Decoy, subject: PrepareToAspirateImplementation, pipetting: PipettingHandler
) -> None:
"""A PrepareToAspirate command should have an executing implementation."""
subject = PrepareToAspirateImplementation(pipetting=pipetting)

data = PrepareToAspirateParams(pipetteId="some id")

decoy.when(await pipetting.prepare_for_aspirate(pipette_id="some id")).then_return(
Expand All @@ -28,3 +44,44 @@ async def test_prepare_to_aspirate_implmenetation(

result = await subject.execute(data)
assert result == SuccessData(public=PrepareToAspirateResult(), private=None)


async def test_overpressure_error(
decoy: Decoy,
gantry_mover: GantryMover,
pipetting: PipettingHandler,
subject: PrepareToAspirateImplementation,
model_utils: ModelUtils,
) -> None:
"""It should return an overpressure error if the hardware API indicates that."""
pipette_id = "pipette-id"

position = Point(x=1, y=2, z=3)

error_id = "error-id"
error_timestamp = datetime(year=2020, month=1, day=2)

data = PrepareToAspirateParams(
pipetteId=pipette_id,
)

decoy.when(
await pipetting.prepare_for_aspirate(
pipette_id=pipette_id,
),
).then_raise(PipetteOverpressureError())

decoy.when(model_utils.generate_id()).then_return(error_id)
decoy.when(model_utils.get_timestamp()).then_return(error_timestamp)
decoy.when(await gantry_mover.get_position(pipette_id)).then_return(position)

result = await subject.execute(data)

assert result == DefinedErrorData(
public=OverpressureError.construct(
id=error_id,
createdAt=error_timestamp,
wrappedErrors=[matchers.Anything()],
errorInfo={"retryLocation": (position.x, position.y, position.z)},
),
)
Loading