Skip to content

Commit cd278e1

Browse files
committed
Merge branch 'chore_release-pd-8.5.0' into flex_liquid_class to update
2 parents 782ead8 + 30b2dc6 commit cd278e1

File tree

120 files changed

+4230
-2600
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+4230
-2600
lines changed

api/src/opentrons/protocol_api/_liquid_properties.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,28 @@ def position_reference(self) -> PositionReference:
115115
return self._position_reference
116116

117117
@position_reference.setter
118-
def position_reference(self, new_position: str) -> None:
119-
self._position_reference = PositionReference(new_position)
118+
def position_reference(self, new_position: Union[str, PositionReference]) -> None:
119+
self._position_reference = (
120+
new_position
121+
if isinstance(new_position, PositionReference)
122+
else PositionReference(new_position)
123+
)
120124

121125
@property
122126
def offset(self) -> Coordinate:
123127
return self._offset
124128

125129
@offset.setter
126-
def offset(self, new_offset: Sequence[float]) -> None:
127-
x, y, z = validation.validate_coordinates(new_offset)
130+
def offset(self, new_offset: Union[Sequence[float], Coordinate]) -> None:
131+
if isinstance(new_offset, Coordinate):
132+
new_coordinate: Sequence[Union[int, float]] = [
133+
new_offset.x,
134+
new_offset.y,
135+
new_offset.z,
136+
]
137+
else:
138+
new_coordinate = new_offset
139+
x, y, z = validation.validate_coordinates(new_coordinate)
128140
self._offset = Coordinate(x=x, y=y, z=z)
129141

130142
def as_shared_data_model(self) -> SharedDataTipPosition:

api/src/opentrons/protocol_api/module_contexts.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def load_labware(
181181

182182
labware_core = self._protocol_core.load_labware(
183183
load_name=name,
184-
label=label,
184+
label=label if label is None else str(label),
185185
namespace=namespace,
186186
version=version,
187187
location=load_location,
@@ -252,7 +252,10 @@ def load_labware_by_name(
252252
"""
253253
_log.warning("load_labware_by_name is deprecated. Use load_labware instead.")
254254
return self.load_labware(
255-
name=name, label=label, namespace=namespace, version=version
255+
name=name,
256+
label=label,
257+
namespace=namespace,
258+
version=version,
256259
)
257260

258261
@requires_version(2, 15)

api/src/opentrons/protocol_api/protocol_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ def load_labware(
499499
labware_core = self._core.load_labware(
500500
load_name=load_name,
501501
location=load_location,
502-
label=label,
502+
label=label if label is None else str(label),
503503
namespace=namespace,
504504
version=version,
505505
)

api/src/opentrons/protocol_runner/legacy_command_mapper.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,7 @@ def _map_labware_load(
651651
)
652652
command_id = f"commands.LOAD_LABWARE-{count}"
653653
labware_id = f"labware-{count}"
654-
655-
succeeded_command = pe_commands.LoadLabware.model_construct(
654+
succeeded_command = pe_commands.LoadLabware(
656655
id=command_id,
657656
key=command_id,
658657
status=pe_commands.CommandStatus.SUCCEEDED,

api/tests/opentrons/protocol_api/test_module_context.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Tests for Protocol API module contexts."""
2+
23
from typing import cast
34

45
import pytest
@@ -120,6 +121,49 @@ def test_load_labware(
120121
decoy.verify(mock_core_map.add(mock_labware_core, result), times=1)
121122

122123

124+
@pytest.mark.parametrize("api_version", [APIVersion(2, 1234)])
125+
@pytest.mark.parametrize(
126+
"label,sanitized_label", [(7, "7"), ("hi", "hi"), (None, None)]
127+
)
128+
def test_load_labware_sanitizes_label(
129+
decoy: Decoy,
130+
mock_protocol_core: ProtocolCore,
131+
mock_core_map: LoadedCoreMap,
132+
mock_core: ModuleCore,
133+
api_version: APIVersion,
134+
label: str | None,
135+
sanitized_label: str | None,
136+
subject: ModuleContext,
137+
) -> None:
138+
"""It should load labware by load parameters."""
139+
mock_labware_core = decoy.mock(cls=LabwareCore)
140+
141+
decoy.when(
142+
mock_protocol_core.load_labware(
143+
load_name="infinite tip rack",
144+
label=sanitized_label,
145+
namespace="ideal",
146+
version=101,
147+
location=mock_core,
148+
)
149+
).then_return(mock_labware_core)
150+
151+
decoy.when(mock_labware_core.get_name()).then_return("Full Name")
152+
decoy.when(mock_labware_core.get_well_columns()).then_return([])
153+
154+
result = subject.load_labware(
155+
name="Infinite Tip Rack",
156+
label=label,
157+
namespace="ideal",
158+
version=101,
159+
)
160+
161+
assert isinstance(result, Labware)
162+
assert result.name == "Full Name"
163+
assert result.api_version == api_version
164+
decoy.verify(mock_core_map.add(mock_labware_core, result), times=1)
165+
166+
123167
@pytest.mark.parametrize("api_version", [APIVersion(2, 1234)])
124168
def test_load_labware_from_definition(
125169
decoy: Decoy,

api/tests/opentrons/protocol_api/test_protocol_context.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Tests for the ProtocolContext public interface."""
2+
23
import inspect
34
from typing import cast, Dict
45

@@ -463,6 +464,57 @@ def test_load_labware(
463464
decoy.verify(mock_core_map.add(mock_labware_core, result), times=1)
464465

465466

467+
@pytest.mark.parametrize(
468+
"label,sanitized_label", [(7, "7"), (None, None), ("hi", "hi")]
469+
)
470+
def test_load_labware_sanitizes_label(
471+
decoy: Decoy,
472+
mock_core: ProtocolCore,
473+
mock_core_map: LoadedCoreMap,
474+
api_version: APIVersion,
475+
label: str | None, # think of this like a typecast
476+
sanitized_label: str | None,
477+
subject: ProtocolContext,
478+
) -> None:
479+
"""It should stringify labels unless they are None."""
480+
mock_labware_core = decoy.mock(cls=LabwareCore)
481+
482+
decoy.when(mock_validation.ensure_lowercase_name("UPPERCASE_LABWARE")).then_return(
483+
"lowercase_labware"
484+
)
485+
decoy.when(mock_core.robot_type).then_return("OT-3 Standard")
486+
decoy.when(
487+
mock_validation.ensure_and_convert_deck_slot(42, api_version, "OT-3 Standard")
488+
).then_return(DeckSlotName.SLOT_5)
489+
490+
decoy.when(
491+
mock_core.load_labware(
492+
load_name="lowercase_labware",
493+
location=DeckSlotName.SLOT_5,
494+
label=sanitized_label,
495+
namespace="some_namespace",
496+
version=1337,
497+
)
498+
).then_return(mock_labware_core)
499+
500+
decoy.when(mock_labware_core.get_name()).then_return("Full Name")
501+
decoy.when(mock_labware_core.get_display_name()).then_return("Display Name")
502+
decoy.when(mock_labware_core.get_well_columns()).then_return([])
503+
504+
result = subject.load_labware(
505+
load_name="UPPERCASE_LABWARE",
506+
location=42,
507+
label=label,
508+
namespace="some_namespace",
509+
version=1337,
510+
)
511+
512+
assert isinstance(result, Labware)
513+
assert result.name == "Full Name"
514+
515+
decoy.verify(mock_core_map.add(mock_labware_core, result), times=1)
516+
517+
466518
def test_load_labware_off_deck(
467519
decoy: Decoy,
468520
mock_core: ProtocolCore,
Loading
Loading
Loading
Loading
Loading

app/src/organisms/Desktop/Labware/LabwareDetails/labware-images.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import agilent_1_reservoir_290ml_side_view from '/app/assets/images/labware/agilent_1_reservoir_290ml_side_view.jpg'
44
import appliedbiosystemsmicroamp_384_wellplate_40ul from '/app/assets/images/labware/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg'
55
import axygen_1_reservoir_90ml_side_view from '/app/assets/images/labware/axygen_1_reservoir_90ml_side_view.jpg'
6+
import axygen_96_well_plate_500ul from '/app/assets/images/labware/axygen_96_well_plate_500uL.png'
67
import biorad_96_wellplate_200ul_pcr_photo_three_quarters from '/app/assets/images/labware/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg'
78
import biorad_384_wellplate_50ul from '/app/assets/images/labware/biorad_384_wellplate_50ul.jpg'
89
import corning_6_wellplate_16_8ml_flat_photo_three_quarters from '/app/assets/images/labware/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg'
@@ -16,6 +17,8 @@ import eppendorf_1_5ml_safelock_snapcap_tube from '/app/assets/images/labware/ep
1617
import eppendorf_2ml_safelock_snapcap_tube from '/app/assets/images/labware/eppendorf_2ml_safelock_snapcap_tube.jpg'
1718
import eppendorf_10ul_tips_eptips_side_view from '/app/assets/images/labware/eppendorf_10ul_tips_eptips_side_view.jpg'
1819
import eppendorf_1000ul_tip_eptips_side_view from '/app/assets/images/labware/eppendorf_1000ul_tip_eptips_side_view.jpg'
20+
import ev_resin_tips_flex_96_labware from '/app/assets/images/labware/ev_resin_tips_flex_96_labware.png'
21+
import ev_resin_tips_flex_96_tiprack_adapter from '/app/assets/images/labware/ev_resin_tips_flex_96_tiprack_adapter.png'
1922
import ev_resin_tips_flex_short_adapter_img from '/app/assets/images/labware/ev_resin_tips_flex_short_adapter.png'
2023
import ev_resin_tips_flex_tall_adapter_img from '/app/assets/images/labware/ev_resin_tips_flex_tall_adapter.png'
2124
import falcon_15ml_conical_tube from '/app/assets/images/labware/falcon_15ml_conical_tube.jpg'
@@ -29,6 +32,7 @@ import geb_96_tiprack_1000ul_side_view from '/app/assets/images/labware/geb_96_t
2932
import geb_1000ul_tip_side_view from '/app/assets/images/labware/geb_1000ul_tip_side_view.jpg'
3033
import generic_2ml_screwcap_tube from '/app/assets/images/labware/generic_2ml_screwcap_tube.jpg'
3134
import generic_pcr_strip_200ul_tubes from '/app/assets/images/labware/generic_pcr_strip_200ul_tubes.jpg'
35+
import ibidi_96_square_well_plate_300ul from '/app/assets/images/labware/ibidi_96_square_well_plate_300ul.png'
3236
import nest_0_5ml_screwcap_tube from '/app/assets/images/labware/nest_0.5ml_screwcap_tube.jpg'
3337
import nest_1_reservoir_195ml_three_quarters from '/app/assets/images/labware/nest_1_reservoir_195ml_three_quarters.jpg'
3438
import nest_1_reservoir_290ml from '/app/assets/images/labware/nest_1_reservoir_290ml.jpg'
@@ -55,6 +59,7 @@ import opentrons_96_tiprack_300ul_side_view from '/app/assets/images/labware/ope
5559
import opentrons_96_tiprack_1000ul_side_view from '/app/assets/images/labware/opentrons_96_tiprack_1000ul_side_view.jpg'
5660
import opentrons_flex_deck_riser_img from '/app/assets/images/labware/opentrons_flex_deck_riser.png'
5761
import pcr_plate_adapter from '/app/assets/images/labware/pcr_plate_adapter.jpg'
62+
import smc_384_read_plate from '/app/assets/images/labware/smc_384_read_plate.png'
5863
import thermoscientificnunc_96_wellplate_1300ul from '/app/assets/images/labware/thermoscientificnunc_96_wellplate_1300ul.jpg'
5964
import thermoscientificnunc_96_wellplate_2000ul from '/app/assets/images/labware/thermoscientificnunc_96_wellplate_2000ul.jpg'
6065
import tipone_96_tiprack_200ul_side_view from '/app/assets/images/labware/tipone_96_tiprack_200ul_side_view.jpg'
@@ -66,6 +71,7 @@ import usascientific_96_wellplate_2_4ml_deep_side_view from '/app/assets/images/
6671
export const labwareImages: Record<string, string[]> = {
6772
agilent_1_reservoir_290ml: [agilent_1_reservoir_290ml_side_view],
6873
axygen_1_reservoir_90ml: [axygen_1_reservoir_90ml_side_view],
74+
axygen_96_wellplate_500ul: [axygen_96_well_plate_500ul],
6975
biorad_96_wellplate_200ul_pcr: [
7076
biorad_96_wellplate_200ul_pcr_photo_three_quarters,
7177
],
@@ -94,6 +100,7 @@ export const labwareImages: Record<string, string[]> = {
94100
geb_1000ul_tip_side_view,
95101
],
96102
geb_96_tiprack_10ul: [geb_96_tiprack_10ul_side_view, geb_10ul_tip_side_view],
103+
ibidi_96_square_well_plate_300ul: [ibidi_96_square_well_plate_300ul],
97104
nest_1_reservoir_195ml: [nest_1_reservoir_195ml_three_quarters],
98105
nest_1_reservoir_290ml: [nest_1_reservoir_290ml],
99106
nest_12_reservoir_15ml: [nest_12_reservoir_15ml_three_quarters],
@@ -215,6 +222,7 @@ export const labwareImages: Record<string, string[]> = {
215222
opentrons_96_filtertiprack_10ul: [opentrons_96_tiprack_10ul_side_view],
216223
opentrons_96_filtertiprack_20ul: [opentrons_96_tiprack_10ul_side_view],
217224
opentrons_96_filtertiprack_200ul: [opentrons_96_tiprack_300ul_side_view],
225+
smc_384_read_plate: [smc_384_read_plate],
218226
tipone_96_tiprack_200ul: [
219227
tipone_96_tiprack_200ul_side_view,
220228
tipone_200ul_tip_side_view,
@@ -261,4 +269,8 @@ export const labwareImages: Record<string, string[]> = {
261269
opentrons_flex_deck_riser: [opentrons_flex_deck_riser_img],
262270
ev_resin_tips_flex_short_adapter: [ev_resin_tips_flex_short_adapter_img],
263271
ev_resin_tips_flex_tall_adapter: [ev_resin_tips_flex_tall_adapter_img],
272+
ev_resin_tips_flex_96_labware: [ev_resin_tips_flex_96_labware],
273+
ev_resin_tips_flex_96_tiprack_adapter: [
274+
ev_resin_tips_flex_96_tiprack_adapter,
275+
],
264276
}

app/src/organisms/ErrorRecoveryFlows/utils/__tests__/getErrorKind.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ describe('getErrorKind', () => {
3232
errorType: DEFINED_ERROR_TYPES.OVERPRESSURE,
3333
expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING,
3434
},
35+
{
36+
commandType: 'blowout',
37+
errorType: DEFINED_ERROR_TYPES.OVERPRESSURE,
38+
expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING,
39+
},
40+
{
41+
commandType: 'blowOutInPlace',
42+
errorType: DEFINED_ERROR_TYPES.OVERPRESSURE,
43+
expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING,
44+
},
3545
{
3646
commandType: 'dropTip',
3747
errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED,

app/src/organisms/ErrorRecoveryFlows/utils/getErrorKind.ts

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,53 @@ export function getErrorKind(
1919
const errorType = failedCommandByRunRecord?.error?.errorType
2020

2121
if (Boolean(errorIsDefined)) {
22-
if (
23-
commandType === 'prepareToAspirate' &&
24-
errorType === DEFINED_ERROR_TYPES.OVERPRESSURE
25-
) {
26-
return ERROR_KINDS.OVERPRESSURE_PREPARE_TO_ASPIRATE
27-
} else if (
28-
(commandType === 'aspirate' || commandType === 'aspirateInPlace') &&
29-
errorType === DEFINED_ERROR_TYPES.OVERPRESSURE
30-
) {
31-
return ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING
32-
} else if (
33-
(commandType === 'dispense' || commandType === 'dispenseInPlace') &&
34-
errorType === DEFINED_ERROR_TYPES.OVERPRESSURE
35-
) {
36-
return ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING
37-
} else if (
38-
commandType === 'liquidProbe' &&
39-
errorType === DEFINED_ERROR_TYPES.LIQUID_NOT_FOUND
40-
) {
41-
return ERROR_KINDS.NO_LIQUID_DETECTED
42-
} else if (
43-
commandType === 'pickUpTip' &&
44-
errorType === DEFINED_ERROR_TYPES.TIP_PHYSICALLY_MISSING
45-
) {
46-
return ERROR_KINDS.TIP_NOT_DETECTED
47-
} else if (
48-
(commandType === 'dropTip' || commandType === 'dropTipInPlace') &&
49-
errorType === DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED
50-
) {
51-
return ERROR_KINDS.TIP_DROP_FAILED
52-
} else if (
53-
commandType === 'moveLabware' &&
54-
errorType === DEFINED_ERROR_TYPES.GRIPPER_MOVEMENT
55-
) {
56-
return ERROR_KINDS.GRIPPER_ERROR
57-
} else if (errorType === DEFINED_ERROR_TYPES.STALL_OR_COLLISION) {
58-
return ERROR_KINDS.STALL_OR_COLLISION
59-
} else if (errorType === DEFINED_ERROR_TYPES.STACKER_STALL) {
60-
return ERROR_KINDS.STALL_WHILE_STACKING
61-
} else if (errorType === DEFINED_ERROR_TYPES.HOPPER_LABWARE_MISSING) {
62-
return ERROR_KINDS.LABWARE_MISSING_IN_HOPPER
63-
} else if (errorType === DEFINED_ERROR_TYPES.SHUTTLE_MISSING) {
64-
return ERROR_KINDS.SHUTTLE_MISSING
65-
} else if (errorType === DEFINED_ERROR_TYPES.LABWARE_MISSING_IN_SHUTTLE) {
66-
return ERROR_KINDS.LABWARE_MISSING_IN_SHUTTLE
22+
switch (errorType) {
23+
case DEFINED_ERROR_TYPES.OVERPRESSURE:
24+
// The recovery flow varies dependent on the exact failed command.
25+
switch (commandType) {
26+
case 'prepareToAspirate':
27+
return ERROR_KINDS.OVERPRESSURE_PREPARE_TO_ASPIRATE
28+
case 'aspirate':
29+
case 'aspirateInPlace': {
30+
return ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING
31+
}
32+
case 'dispense':
33+
case 'dispenseInPlace':
34+
case 'blowout':
35+
case 'blowOutInPlace':
36+
return ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING
37+
default: {
38+
console.error(`Unhandled overpressure command ${commandType}`)
39+
return ERROR_KINDS.GENERAL_ERROR
40+
}
41+
}
42+
case DEFINED_ERROR_TYPES.LIQUID_NOT_FOUND:
43+
return ERROR_KINDS.NO_LIQUID_DETECTED
44+
case DEFINED_ERROR_TYPES.TIP_PHYSICALLY_MISSING:
45+
return ERROR_KINDS.TIP_NOT_DETECTED
46+
case DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED:
47+
return ERROR_KINDS.TIP_DROP_FAILED
48+
case DEFINED_ERROR_TYPES.GRIPPER_MOVEMENT:
49+
return ERROR_KINDS.GRIPPER_ERROR
50+
case DEFINED_ERROR_TYPES.STALL_OR_COLLISION:
51+
return ERROR_KINDS.STALL_OR_COLLISION
52+
case DEFINED_ERROR_TYPES.STACKER_STALL:
53+
return ERROR_KINDS.STALL_WHILE_STACKING
54+
case DEFINED_ERROR_TYPES.HOPPER_LABWARE_MISSING:
55+
return ERROR_KINDS.LABWARE_MISSING_IN_HOPPER
56+
case DEFINED_ERROR_TYPES.SHUTTLE_MISSING:
57+
return ERROR_KINDS.SHUTTLE_MISSING
58+
case DEFINED_ERROR_TYPES.LABWARE_MISSING_IN_SHUTTLE:
59+
return ERROR_KINDS.LABWARE_MISSING_IN_SHUTTLE
60+
default: {
61+
console.error(`Unhandled error type ${errorType}`)
62+
return ERROR_KINDS.GENERAL_ERROR
63+
}
6764
}
65+
} else {
66+
console.warn(
67+
`Run status is "awaiting for recovery", but error is not defined: ${failedCommandByRunRecord}`
68+
)
69+
return ERROR_KINDS.GENERAL_ERROR
6870
}
69-
70-
return ERROR_KINDS.GENERAL_ERROR
7171
}

0 commit comments

Comments
 (0)