Skip to content

Commit 6ee528b

Browse files
fix(api): set_stored_labware(): preserve prior behavior for lid/adapter namespace/version (#19717)
## Overview This fixes a backwards compatibility bug in my implementation of #19348 / EXEC-1750. ## Details #19348 did two things, in various places: 1. It added new params * `adapter_namespace` * `adapter_version` * `lid_namespace` * `lid_version` 2. It adjusted the behavior when those params were omitted In one of those places, I forgot: * to raise an error if you tried using the new params on an older `apiLevel`s * to preserve the old behavior when the params were omitted This PR adds that backwards-compatibility behavior, following the pattern from the rest of #19348. This is targeting `chore_release-8.7.0`. v8.7.0 is the first robot software release that would have the changes from #19348.
1 parent 6287318 commit 6ee528b

File tree

2 files changed

+187
-33
lines changed

2 files changed

+187
-33
lines changed

api/src/opentrons/protocol_api/module_contexts.py

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,16 +1467,61 @@ def set_stored_labware(
14671467
- Labware with lid and adapter: the adapter (bottom side) of the upper labware unit overlaps with the lid (top side) of the unit below.
14681468
"""
14691469

1470+
if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
1471+
if adapter_namespace is not None:
1472+
raise APIVersionError(
1473+
api_element="The `adapter_namespace` parameter",
1474+
until_version=str(
1475+
validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1476+
),
1477+
current_version=str(self._api_version),
1478+
)
1479+
if adapter_version is not None:
1480+
raise APIVersionError(
1481+
api_element="The `adapter_version` parameter",
1482+
until_version=str(
1483+
validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1484+
),
1485+
current_version=str(self._api_version),
1486+
)
1487+
if lid_namespace is not None:
1488+
raise APIVersionError(
1489+
api_element="The `lid_namespace` parameter",
1490+
until_version=str(
1491+
validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1492+
),
1493+
current_version=str(self._api_version),
1494+
)
1495+
if lid_version is not None:
1496+
raise APIVersionError(
1497+
api_element="The `lid_version` parameter",
1498+
until_version=str(
1499+
validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1500+
),
1501+
current_version=str(self._api_version),
1502+
)
1503+
1504+
if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
1505+
checked_adapter_namespace = namespace
1506+
checked_adapter_version = version
1507+
checked_lid_namespace = namespace
1508+
checked_lid_version = version
1509+
else:
1510+
checked_adapter_namespace = adapter_namespace
1511+
checked_adapter_version = adapter_version
1512+
checked_lid_namespace = lid_namespace
1513+
checked_lid_version = lid_version
1514+
14701515
self._core.set_stored_labware(
14711516
main_load_name=load_name,
14721517
main_namespace=namespace,
14731518
main_version=version,
14741519
lid_load_name=lid,
1475-
lid_namespace=lid_namespace,
1476-
lid_version=lid_version,
1520+
lid_namespace=checked_lid_namespace,
1521+
lid_version=checked_lid_version,
14771522
adapter_load_name=adapter,
1478-
adapter_namespace=adapter_namespace,
1479-
adapter_version=adapter_version,
1523+
adapter_namespace=checked_adapter_namespace,
1524+
adapter_version=checked_adapter_version,
14801525
count=count,
14811526
stacking_offset_z=stacking_offset_z,
14821527
)

api/tests/opentrons/protocol_api/test_flex_stacker_context.py

Lines changed: 138 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
"""Tests for Protocol API Flex Stacker contexts."""
22

3+
from unittest.mock import sentinel
4+
35
import pytest
46
from decoy import Decoy, matchers
57

8+
from opentrons.protocols.api_support.util import APIVersionError
69
from opentrons.types import DeckSlotName
710
from opentrons.legacy_broker import LegacyBroker
811
from opentrons.protocols.api_support.types import APIVersion
@@ -14,7 +17,7 @@
1417
)
1518
from opentrons.protocol_api.core.core_map import LoadedCoreMap
1619

17-
from . import versions_at_or_above
20+
from . import versions_at_or_above, versions_between
1821

1922

2023
@pytest.fixture
@@ -105,55 +108,161 @@ def test_empty(
105108

106109

107110
@pytest.mark.parametrize(
108-
"api_version", versions_at_or_above(from_version=APIVersion(2, 25))
111+
"api_version", versions_at_or_above(from_version=APIVersion(2, 26))
109112
)
110113
def test_set_stored_labware(
111114
decoy: Decoy, mock_core: FlexStackerCore, subject: FlexStackerContext
112115
) -> None:
113116
"""It should route arguments appropriately."""
114117
subject.set_stored_labware(
115-
"load_name", "namespace", 1, "adapter", "lid", 2, stacking_offset_z=1.0
118+
load_name=sentinel.main_load_name,
119+
namespace=sentinel.main_namespace,
120+
version=sentinel.main_version,
121+
adapter=sentinel.adapter_load_name,
122+
lid=sentinel.lid_load_name,
123+
count=sentinel.count,
124+
stacking_offset_z=sentinel.stacking_offset_z,
116125
)
117126
decoy.verify(
118127
mock_core.set_stored_labware(
119-
main_load_name="load_name",
120-
main_namespace="namespace",
121-
main_version=1,
122-
lid_load_name="lid",
128+
main_load_name=sentinel.main_load_name,
129+
main_namespace=sentinel.main_namespace,
130+
main_version=sentinel.main_version,
131+
lid_load_name=sentinel.lid_load_name,
123132
lid_namespace=None,
124133
lid_version=None,
125-
adapter_load_name="adapter",
134+
adapter_load_name=sentinel.adapter_load_name,
126135
adapter_namespace=None,
127136
adapter_version=None,
128-
count=2,
129-
stacking_offset_z=1.0,
137+
count=sentinel.count,
138+
stacking_offset_z=sentinel.stacking_offset_z,
130139
)
131140
)
132141

133142
subject.set_stored_labware(
134-
"load_name",
135-
"namespace",
136-
1,
137-
"adapter",
138-
"lid",
139-
2,
140-
stacking_offset_z=1.0,
141-
adapter_namespace="adapter_namespace",
142-
adapter_version=3,
143+
load_name=sentinel.main_load_name,
144+
namespace=sentinel.main_namespace,
145+
version=sentinel.main_version,
146+
adapter=sentinel.adapter_load_name,
147+
lid=sentinel.lid_load_name,
148+
count=sentinel.count,
149+
stacking_offset_z=sentinel.stacking_offset_z,
150+
adapter_namespace=sentinel.adapter_namespace,
151+
adapter_version=sentinel.adapter_version,
152+
lid_namespace=sentinel.lid_namespace,
153+
lid_version=sentinel.lid_version,
143154
)
144155
decoy.verify(
145156
mock_core.set_stored_labware(
146-
main_load_name="load_name",
147-
main_namespace="namespace",
148-
main_version=1,
149-
lid_load_name="lid",
150-
lid_namespace=None,
151-
lid_version=None,
152-
adapter_load_name="adapter",
153-
adapter_namespace="adapter_namespace",
154-
adapter_version=3,
155-
count=2,
157+
main_load_name=sentinel.main_load_name,
158+
main_namespace=sentinel.main_namespace,
159+
main_version=sentinel.main_version,
160+
lid_load_name=sentinel.lid_load_name,
161+
lid_namespace=sentinel.lid_namespace,
162+
lid_version=sentinel.lid_version,
163+
adapter_load_name=sentinel.adapter_load_name,
164+
adapter_namespace=sentinel.adapter_namespace,
165+
adapter_version=sentinel.adapter_version,
166+
count=sentinel.count,
167+
stacking_offset_z=sentinel.stacking_offset_z,
168+
)
169+
)
170+
171+
172+
@pytest.mark.parametrize(
173+
"api_version",
174+
versions_between(
175+
low_inclusive_bound=APIVersion(2, 25), high_exclusive_bound=APIVersion(2, 26)
176+
),
177+
)
178+
def test_set_stored_labware_namespace_version_params_minimum_version(
179+
subject: FlexStackerContext,
180+
) -> None:
181+
"""{adapter,lid}_{namespace,version} params were unavailable before version 2.26."""
182+
with pytest.raises(APIVersionError):
183+
subject.set_stored_labware(
184+
"load_name",
185+
"namespace",
186+
1,
187+
"adapter",
188+
"lid",
189+
2,
190+
stacking_offset_z=1.0,
191+
adapter_namespace="foo",
192+
)
193+
with pytest.raises(APIVersionError):
194+
subject.set_stored_labware(
195+
"load_name",
196+
"namespace",
197+
1,
198+
"adapter",
199+
"lid",
200+
2,
201+
stacking_offset_z=1.0,
202+
adapter_version=123,
203+
)
204+
with pytest.raises(APIVersionError):
205+
subject.set_stored_labware(
206+
"load_name",
207+
"namespace",
208+
1,
209+
"adapter",
210+
"lid",
211+
2,
156212
stacking_offset_z=1.0,
213+
lid_namespace="foo",
214+
)
215+
with pytest.raises(APIVersionError):
216+
subject.set_stored_labware(
217+
"load_name",
218+
"namespace",
219+
1,
220+
"adapter",
221+
"lid",
222+
2,
223+
stacking_offset_z=1.0,
224+
lid_version=123,
225+
)
226+
227+
228+
@pytest.mark.parametrize(
229+
"api_version",
230+
versions_between(
231+
low_inclusive_bound=APIVersion(2, 25), high_exclusive_bound=APIVersion(2, 26)
232+
),
233+
)
234+
def test_set_stored_labware_namespace_version_params_legacy_behavior(
235+
decoy: Decoy,
236+
mock_core: FlexStackerCore,
237+
subject: FlexStackerContext,
238+
) -> None:
239+
"""Test legacy (version <2.26) behavior when the {adapter,lid}_{namespace,version} params were omitted.
240+
241+
The adapter and lid namespace and version were taken from the main labware's namespace and version.
242+
"""
243+
subject.set_stored_labware(
244+
load_name=sentinel.main_load_name,
245+
namespace=sentinel.main_namespace,
246+
version=sentinel.main_version,
247+
adapter=sentinel.adapter_load_name,
248+
lid=sentinel.lid_load_name,
249+
count=sentinel.count,
250+
stacking_offset_z=sentinel.stacking_offset_z,
251+
)
252+
253+
decoy.verify(
254+
mock_core.set_stored_labware(
255+
main_load_name=sentinel.main_load_name,
256+
main_namespace=sentinel.main_namespace,
257+
main_version=sentinel.main_version,
258+
lid_load_name=sentinel.lid_load_name,
259+
lid_namespace=sentinel.main_namespace,
260+
lid_version=sentinel.main_version,
261+
adapter_load_name=sentinel.adapter_load_name,
262+
adapter_namespace=sentinel.main_namespace,
263+
adapter_version=sentinel.main_version,
264+
count=sentinel.count,
265+
stacking_offset_z=sentinel.stacking_offset_z,
157266
)
158267
)
159268

0 commit comments

Comments
 (0)