Skip to content

Commit 1754667

Browse files
fix(shared-data): Re-apply update tip overlap values for Flex Pipettes (#15147) (#15284)
This is #15147 again but this time outside the context of an extremely imminent release. While this code needs to be merged, we should carefully consider how we do so. We can't ship this until we can separate this behavior by API level so that customers who may have tuned in offsets based on the old incorrect tip offsets won't have their protocols invalidated - this data needs to be loaded by API level. Closes EXEC-452 --------- Co-authored-by: Carlos-fernandez <[email protected]>
1 parent 085c140 commit 1754667

File tree

26 files changed

+258
-8
lines changed

26 files changed

+258
-8
lines changed

api/src/opentrons/protocol_api/core/engine/instrument.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from opentrons.protocol_api._nozzle_layout import NozzleLayout
3535
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
3636
from opentrons.hardware_control.nozzle_manager import NozzleMap
37-
from . import deck_conflict
37+
from . import deck_conflict, overlap_versions
3838

3939
from ..instrument import AbstractInstrument
4040
from .well import WellCore
@@ -745,7 +745,11 @@ def set_flow_rate(
745745

746746
def configure_for_volume(self, volume: float) -> None:
747747
self._engine_client.configure_for_volume(
748-
pipette_id=self._pipette_id, volume=volume, tip_overlap_version="v0"
748+
pipette_id=self._pipette_id,
749+
volume=volume,
750+
tip_overlap_version=overlap_versions.overlap_for_api_version(
751+
self._protocol_core.api_version
752+
),
749753
)
750754

751755
def prepare_to_aspirate(self) -> None:
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Mappings between API versions and overlap versions."""
2+
from functools import lru_cache
3+
from typing_extensions import Final
4+
from opentrons.protocols.api_support.types import APIVersion
5+
6+
_OVERLAP_VERSION_MAP: Final = {APIVersion(2, 0): "v0", APIVersion(2, 19): "v1"}
7+
8+
9+
@lru_cache(1)
10+
def overlap_for_api_version(api_version: APIVersion) -> str:
11+
"""Get the overlap version for a specific API version."""
12+
defined = list(reversed(sorted(_OVERLAP_VERSION_MAP.keys())))
13+
for version in defined:
14+
if version <= api_version:
15+
return _OVERLAP_VERSION_MAP[version]
16+
return _OVERLAP_VERSION_MAP[APIVersion(2, 0)]

api/src/opentrons/protocol_api/core/engine/protocol.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@
6666
MagneticBlockCore,
6767
)
6868
from .exceptions import InvalidModuleLocationError
69-
from . import load_labware_params
70-
from . import deck_conflict
69+
from . import load_labware_params, deck_conflict, overlap_versions
7170

7271
if TYPE_CHECKING:
7372
from ...labware import Labware
@@ -499,7 +498,11 @@ def load_instrument(
499498
"""
500499
engine_mount = MountType[mount.name]
501500
load_result = self._engine_client.load_pipette(
502-
instrument_name, engine_mount, tip_overlap_version="v0"
501+
instrument_name,
502+
engine_mount,
503+
tip_overlap_version=overlap_versions.overlap_for_api_version(
504+
self._api_version
505+
),
503506
)
504507

505508
return InstrumentCore(

api/tests/opentrons/protocol_api/core/engine/test_instrument_core.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
from opentrons.protocols.api_support.types import APIVersion
4848
from opentrons.types import Location, Mount, MountType, Point
4949

50+
from ... import versions_below, versions_at_or_above
51+
5052

5153
@pytest.fixture
5254
def mock_engine_client(decoy: Decoy) -> EngineClient:
@@ -1173,15 +1175,37 @@ def test_is_tip_tracking_available(
11731175
assert subject.is_tip_tracking_available() == expected_result
11741176

11751177

1176-
def test_configure_for_volume(
1178+
@pytest.mark.parametrize("version", versions_below(APIVersion(2, 19), flex_only=False))
1179+
def test_configure_for_volume_pre_219(
11771180
decoy: Decoy,
11781181
mock_engine_client: EngineClient,
1182+
mock_protocol_core: ProtocolCore,
11791183
subject: InstrumentCore,
1184+
version: APIVersion,
11801185
) -> None:
11811186
"""Configure_for_volume should specify overlap version."""
1187+
decoy.when(mock_protocol_core.api_version).then_return(version)
11821188
subject.configure_for_volume(123.0)
11831189
decoy.verify(
11841190
mock_engine_client.configure_for_volume(
11851191
pipette_id=subject.pipette_id, volume=123.0, tip_overlap_version="v0"
11861192
)
11871193
)
1194+
1195+
1196+
@pytest.mark.parametrize("version", versions_at_or_above(APIVersion(2, 19)))
1197+
def test_configure_for_volume_post_219(
1198+
decoy: Decoy,
1199+
mock_engine_client: EngineClient,
1200+
mock_protocol_core: ProtocolCore,
1201+
subject: InstrumentCore,
1202+
version: APIVersion,
1203+
) -> None:
1204+
"""Configure_for_volume should specify overlap version."""
1205+
decoy.when(mock_protocol_core.api_version).then_return(version)
1206+
subject.configure_for_volume(123.0)
1207+
decoy.verify(
1208+
mock_engine_client.configure_for_volume(
1209+
pipette_id=subject.pipette_id, volume=123.0, tip_overlap_version="v1"
1210+
)
1211+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Test the tip overlap selection logic in the API core."""
2+
import pytest
3+
4+
from opentrons.protocol_api.core.engine.overlap_versions import overlap_for_api_version
5+
from opentrons.protocols.api_support.types import APIVersion
6+
7+
from ... import versions_below, versions_at_or_above
8+
9+
10+
@pytest.mark.parametrize(
11+
"api_version", versions_below(APIVersion(2, 19), flex_only=False)
12+
)
13+
def test_all_below_219_use_v0(api_version: APIVersion) -> None:
14+
"""Versions below 2.19 should use v0."""
15+
assert overlap_for_api_version(api_version) == "v0"
16+
17+
18+
@pytest.mark.parametrize("api_version", versions_at_or_above(APIVersion(2, 19)))
19+
def test_all_above_219_use_v1(api_version: APIVersion) -> None:
20+
"""Versions above 2.19 should use v1."""
21+
assert overlap_for_api_version(api_version) == "v1"
22+
23+
24+
def test_future_api_version_uses_v1() -> None:
25+
"""Future versions should use v1."""
26+
assert overlap_for_api_version(APIVersion(2, 99)) == "v1"

api/tests/opentrons/protocol_api/core/engine/test_protocol_core.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@
8686
STANDARD_OT3_DECK,
8787
)
8888

89+
from ... import versions_below, versions_at_or_above
90+
8991

9092
@pytest.fixture(scope="session")
9193
def ot2_standard_deck_def() -> DeckDefinitionV5:
@@ -235,7 +237,10 @@ def test_get_slot_item_empty(
235237
assert subject.get_slot_item(DeckSlotName.SLOT_1) is None
236238

237239

238-
def test_load_instrument(
240+
@pytest.mark.parametrize(
241+
"api_version", versions_below(APIVersion(2, 19), flex_only=False)
242+
)
243+
def test_load_instrument_pre_219(
239244
decoy: Decoy,
240245
mock_sync_hardware_api: SyncHardwareAPI,
241246
mock_engine_client: EngineClient,
@@ -268,6 +273,40 @@ def test_load_instrument(
268273
assert result.pipette_id == "cool-pipette"
269274

270275

276+
@pytest.mark.parametrize("api_version", versions_at_or_above(APIVersion(2, 19)))
277+
def test_load_instrument_post_219(
278+
decoy: Decoy,
279+
mock_sync_hardware_api: SyncHardwareAPI,
280+
mock_engine_client: EngineClient,
281+
subject: ProtocolCore,
282+
) -> None:
283+
"""It should issue a LoadPipette command."""
284+
decoy.when(
285+
mock_engine_client.load_pipette(
286+
pipette_name=PipetteNameType.P300_SINGLE,
287+
mount=MountType.LEFT,
288+
tip_overlap_version="v1",
289+
)
290+
).then_return(commands.LoadPipetteResult(pipetteId="cool-pipette"))
291+
292+
decoy.when(
293+
mock_engine_client.state.pipettes.get_flow_rates("cool-pipette")
294+
).then_return(
295+
FlowRates(
296+
default_aspirate={"1.1": 22},
297+
default_dispense={"3.3": 44},
298+
default_blow_out={"5.5": 66},
299+
),
300+
)
301+
302+
result = subject.load_instrument(
303+
instrument_name=PipetteNameType.P300_SINGLE, mount=Mount.LEFT
304+
)
305+
306+
assert isinstance(result, InstrumentCore)
307+
assert result.pipette_id == "cool-pipette"
308+
309+
271310
def test_load_labware(
272311
decoy: Decoy,
273312
mock_engine_client: EngineClient,

shared-data/js/__tests__/pipettes.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ describe('pipette data accessors', () => {
9292
'opentrons/opentrons_flex_96_filtertiprack_200ul/1': 10.5,
9393
'opentrons/opentrons_flex_96_filtertiprack_50ul/1': 10.5,
9494
},
95+
v1: {
96+
default: 10.5,
97+
'opentrons/opentrons_flex_96_tiprack_1000ul/1': 9.65,
98+
'opentrons/opentrons_flex_96_tiprack_200ul/1': 9.76,
99+
'opentrons/opentrons_flex_96_tiprack_50ul/1': 10.09,
100+
'opentrons/opentrons_flex_96_filtertiprack_1000ul/1': 9.65,
101+
'opentrons/opentrons_flex_96_filtertiprack_200ul/1': 9.76,
102+
'opentrons/opentrons_flex_96_filtertiprack_50ul/1': 10.09,
103+
},
95104
},
96105
defaultTipracks: [
97106
'opentrons/opentrons_flex_96_tiprack_1000ul/1',
@@ -156,6 +165,11 @@ describe('pipette data accessors', () => {
156165
[tiprackFilter50uL]: 10.5,
157166
[tiprack50uL]: 10.5,
158167
},
168+
v1: {
169+
default: 10.5,
170+
[tiprackFilter50uL]: 10.09,
171+
[tiprack50uL]: 10.09,
172+
},
159173
},
160174
defaultTipracks: [tiprack50uL, tiprackFilter50uL],
161175
maxVolume: 50,
@@ -206,6 +220,11 @@ describe('pipette data accessors', () => {
206220
[tiprackFilter50uL]: 10.5,
207221
[tiprack50uL]: 10.5,
208222
},
223+
v1: {
224+
default: 10.5,
225+
[tiprackFilter50uL]: 10.09,
226+
[tiprack50uL]: 10.09,
227+
},
209228
},
210229
defaultTipracks: [tiprack50uL, tiprackFilter50uL],
211230
maxVolume: 30,

shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_4.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,15 @@
362362
"opentrons/opentrons_flex_96_filtertiprack_200ul/1": 10.1,
363363
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 10.05,
364364
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1": 10.17
365+
},
366+
"v1": {
367+
"default": 10.5,
368+
"opentrons/opentrons_flex_96_tiprack_200ul/1": 9.42,
369+
"opentrons/opentrons_flex_96_tiprack_50ul/1": 9.27,
370+
"opentrons/opentrons_flex_96_tiprack_1000ul/1": 9.67,
371+
"opentrons/opentrons_flex_96_filtertiprack_200ul/1": 9.42,
372+
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 9.27,
373+
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1": 9.67
365374
}
366375
}
367376
}

shared-data/pipette/definitions/2/liquid/eight_channel/p1000/default/3_5.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@
242242
"opentrons/opentrons_flex_96_filtertiprack_200ul/1": 10.1,
243243
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 10.05,
244244
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1": 10.17
245+
},
246+
"v1": {
247+
"default": 10.5,
248+
"opentrons/opentrons_flex_96_tiprack_200ul/1": 9.42,
249+
"opentrons/opentrons_flex_96_tiprack_50ul/1": 9.27,
250+
"opentrons/opentrons_flex_96_tiprack_1000ul/1": 9.67,
251+
"opentrons/opentrons_flex_96_filtertiprack_200ul/1": 9.42,
252+
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 9.27,
253+
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1": 9.67
245254
}
246255
}
247256
}

shared-data/pipette/definitions/2/liquid/eight_channel/p50/default/3_4.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@
100100
"default": 10.5,
101101
"opentrons/opentrons_flex_96_tiprack_50ul/1": 10.05,
102102
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 10.05
103+
},
104+
"v1": {
105+
"default": 10.5,
106+
"opentrons/opentrons_flex_96_tiprack_50ul/1": 9.27,
107+
"opentrons/opentrons_flex_96_filtertiprack_50ul/1": 9.27
103108
}
104109
}
105110
}

0 commit comments

Comments
 (0)