opentrons 8.6.0a12__py3-none-any.whl → 8.7.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of opentrons might be problematic. Click here for more details.

Files changed (28) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/hardware_control/backends/ot3controller.py +22 -13
  3. opentrons/hardware_control/backends/ot3simulator.py +1 -1
  4. opentrons/hardware_control/ot3api.py +1 -1
  5. opentrons/protocol_api/core/engine/_default_liquid_class_versions.py +56 -0
  6. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +77 -17
  7. opentrons/protocol_api/core/engine/protocol.py +11 -2
  8. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -1
  9. opentrons/protocol_api/core/protocol.py +1 -1
  10. opentrons/protocol_api/labware.py +36 -2
  11. opentrons/protocol_api/module_contexts.py +100 -13
  12. opentrons/protocol_api/protocol_context.py +162 -12
  13. opentrons/protocol_api/validation.py +4 -0
  14. opentrons/protocol_engine/commands/command_unions.py +2 -0
  15. opentrons/protocol_engine/commands/flex_stacker/common.py +13 -0
  16. opentrons/protocol_engine/commands/flex_stacker/store.py +20 -2
  17. opentrons/protocol_engine/execution/labware_movement.py +5 -11
  18. opentrons/protocol_engine/state/geometry.py +33 -5
  19. opentrons/protocol_engine/state/labware.py +66 -0
  20. opentrons/protocol_engine/state/modules.py +6 -0
  21. opentrons/protocol_engine/types/__init__.py +2 -0
  22. opentrons/protocol_engine/types/labware.py +9 -0
  23. opentrons/protocols/api_support/definitions.py +1 -1
  24. {opentrons-8.6.0a12.dist-info → opentrons-8.7.0a1.dist-info}/METADATA +4 -4
  25. {opentrons-8.6.0a12.dist-info → opentrons-8.7.0a1.dist-info}/RECORD +28 -27
  26. {opentrons-8.6.0a12.dist-info → opentrons-8.7.0a1.dist-info}/WHEEL +0 -0
  27. {opentrons-8.6.0a12.dist-info → opentrons-8.7.0a1.dist-info}/entry_points.txt +0 -0
  28. {opentrons-8.6.0a12.dist-info → opentrons-8.7.0a1.dist-info}/licenses/LICENSE +0 -0
opentrons/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '8.6.0a12'
32
- __version_tuple__ = version_tuple = (8, 6, 0, 'a12')
31
+ __version__ = version = '8.7.0a1'
32
+ __version_tuple__ = version_tuple = (8, 7, 0, 'a1')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -686,9 +686,9 @@ class OT3Controller(FlexBackend):
686
686
  return (
687
687
  MoveGroupRunner(
688
688
  move_groups=[move_group],
689
- ignore_stalls=True
690
- if not self._feature_flags.stall_detection_enabled
691
- else False,
689
+ ignore_stalls=(
690
+ True if not self._feature_flags.stall_detection_enabled else False
691
+ ),
692
692
  ),
693
693
  False,
694
694
  )
@@ -712,9 +712,9 @@ class OT3Controller(FlexBackend):
712
712
  return (
713
713
  MoveGroupRunner(
714
714
  move_groups=[tip_motor_move_group],
715
- ignore_stalls=True
716
- if not self._feature_flags.stall_detection_enabled
717
- else False,
715
+ ignore_stalls=(
716
+ True if not self._feature_flags.stall_detection_enabled else False
717
+ ),
718
718
  ),
719
719
  True,
720
720
  )
@@ -939,9 +939,9 @@ class OT3Controller(FlexBackend):
939
939
 
940
940
  runner = MoveGroupRunner(
941
941
  move_groups=[move_group],
942
- ignore_stalls=True
943
- if not self._feature_flags.stall_detection_enabled
944
- else False,
942
+ ignore_stalls=(
943
+ True if not self._feature_flags.stall_detection_enabled else False
944
+ ),
945
945
  )
946
946
  try:
947
947
  positions = await runner.run(can_messenger=self._messenger)
@@ -976,9 +976,9 @@ class OT3Controller(FlexBackend):
976
976
  move_group = self._build_tip_action_group(origin, targets)
977
977
  runner = MoveGroupRunner(
978
978
  move_groups=[move_group],
979
- ignore_stalls=True
980
- if not self._feature_flags.stall_detection_enabled
981
- else False,
979
+ ignore_stalls=(
980
+ True if not self._feature_flags.stall_detection_enabled else False
981
+ ),
982
982
  )
983
983
  try:
984
984
  positions = await runner.run(can_messenger=self._messenger)
@@ -1777,7 +1777,16 @@ class OT3Controller(FlexBackend):
1777
1777
  expected_grip_width + grip_width_uncertainty_wider
1778
1778
  )
1779
1779
  current_gripper_position = jaw_width
1780
- if isclose(current_gripper_position, hard_limit_lower):
1780
+ log.info(
1781
+ f"Checking gripper position: current {jaw_width}; max error {max_allowed_grip_error}; hard limits {hard_limit_lower}, {hard_limit_upper}; expected {expected_gripper_position_min}, {expected_grip_width}, {expected_gripper_position_max}; uncertainty {grip_width_uncertainty_narrower}, {grip_width_uncertainty_wider}"
1782
+ )
1783
+ if (
1784
+ isclose(current_gripper_position, hard_limit_lower)
1785
+ # this odd check handles internal backlash that can lead the position to read as if
1786
+ # the gripper has overshot its lower bound; this is physically impossible and an
1787
+ # artifact of the gearing, so it always indicates a hard stop
1788
+ or current_gripper_position < hard_limit_lower
1789
+ ):
1781
1790
  raise FailedGripperPickupError(
1782
1791
  message="Failed to grip: jaws all the way closed",
1783
1792
  details={
@@ -781,7 +781,7 @@ class OT3Simulator(FlexBackend):
781
781
  next_fw_version=1,
782
782
  fw_update_needed=False,
783
783
  current_fw_sha="simulated",
784
- pcba_revision="A1",
784
+ pcba_revision="A1.0",
785
785
  update_state=None,
786
786
  )
787
787
  for axis in self._present_axes
@@ -1480,8 +1480,8 @@ class OT3API(
1480
1480
  grip_width_uncertainty_narrower,
1481
1481
  gripper.jaw_width,
1482
1482
  gripper.max_allowed_grip_error,
1483
- gripper.max_jaw_width,
1484
1483
  gripper.min_jaw_width,
1484
+ gripper.max_jaw_width,
1485
1485
  )
1486
1486
 
1487
1487
  def gripper_jaw_can_home(self) -> bool:
@@ -0,0 +1,56 @@
1
+ """The versions of standard liquid classes that the Protocol API should load by default."""
2
+
3
+ from typing import TypeAlias
4
+ from opentrons.protocols.api_support.types import APIVersion
5
+
6
+
7
+ DefaultLiquidClassVersions: TypeAlias = dict[APIVersion, dict[str, int]]
8
+
9
+
10
+ # This:
11
+ #
12
+ # {
13
+ # APIVersion(2, 100): {
14
+ # "foo_liquid": 3,
15
+ # },
16
+ # APIVersion(2, 105): {
17
+ # "foo_liquid": 7
18
+ # }
19
+ # }
20
+ #
21
+ # Means this:
22
+ #
23
+ # apiLevels name Default liquid class version
24
+ # ---------------------------------------------------------------
25
+ # <2.100 foo_liquid 1
26
+ # >=2.100,<2.105 foo_liquid 3
27
+ # >=2.105 foo_liquid 7
28
+ # [any] [anything else] 1
29
+ DEFAULT_LIQUID_CLASS_VERSIONS: DefaultLiquidClassVersions = {
30
+ APIVersion(2, 26): {
31
+ "ethanol_80": 2,
32
+ "glycerol_50": 2,
33
+ "water": 2,
34
+ },
35
+ }
36
+
37
+
38
+ def get_liquid_class_version(
39
+ api_version: APIVersion,
40
+ liquid_class_name: str,
41
+ ) -> int:
42
+ """Return what version of a liquid class the Protocol API should load by default."""
43
+ default_lc_versions_newest_to_oldest = sorted(
44
+ DEFAULT_LIQUID_CLASS_VERSIONS.items(), key=lambda kv: kv[0], reverse=True
45
+ )
46
+ for (
47
+ breakpoint_api_version,
48
+ breakpoint_liquid_class_versions,
49
+ ) in default_lc_versions_newest_to_oldest:
50
+ if (
51
+ api_version >= breakpoint_api_version
52
+ and liquid_class_name in breakpoint_liquid_class_versions
53
+ ):
54
+ return breakpoint_liquid_class_versions[liquid_class_name]
55
+
56
+ return 1
@@ -21,7 +21,11 @@ from opentrons.protocol_engine import (
21
21
  OnLabwareLocation,
22
22
  DropTipWellLocation,
23
23
  )
24
- from opentrons.protocol_engine.types import StagingSlotLocation, WellLocationType
24
+ from opentrons.protocol_engine.types import (
25
+ StagingSlotLocation,
26
+ WellLocationType,
27
+ LoadedModule,
28
+ )
25
29
  from opentrons.types import DeckSlotName, StagingSlotName, Point
26
30
  from . import point_calculations
27
31
 
@@ -136,22 +140,47 @@ def check_safe_for_pipette_movement( # noqa: C901
136
140
  f" will result in collision with thermocycler lid in deck slot A1."
137
141
  )
138
142
 
143
+ def _check_for_column_4_module_collision(slot: DeckSlotName) -> None:
144
+ slot_module = engine_state.modules.get_by_slot(slot)
145
+ if (
146
+ slot_module
147
+ and engine_state.modules.is_column_4_module(slot_module.model)
148
+ and _slot_has_potential_colliding_object(
149
+ engine_state=engine_state,
150
+ pipette_bounds=pipette_bounds_at_well_location,
151
+ surrounding_location=slot_module,
152
+ )
153
+ ):
154
+ raise PartialTipMovementNotAllowedError(
155
+ f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
156
+ f" {slot} with {primary_nozzle} nozzle partial configuration will"
157
+ f" result in collision with items on {slot_module.model} mounted in {slot}."
158
+ )
159
+
160
+ # We check the labware slot for a module that is mounted in the same cutout
161
+ # as the labwares slot but does not occupy the same heirarchy (like the stacker).
162
+ _check_for_column_4_module_collision(labware_slot)
163
+
139
164
  for regular_slot in surrounding_slots.regular_slots:
140
165
  if _slot_has_potential_colliding_object(
141
166
  engine_state=engine_state,
142
167
  pipette_bounds=pipette_bounds_at_well_location,
143
- surrounding_slot=regular_slot,
168
+ surrounding_location=regular_slot,
144
169
  ):
145
170
  raise PartialTipMovementNotAllowedError(
146
171
  f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
147
172
  f" {labware_slot} with {primary_nozzle} nozzle partial configuration"
148
173
  f" will result in collision with items in deck slot {regular_slot}."
149
174
  )
175
+
176
+ # Check for Column 4 Modules that may be descendants of a given surrounding slot
177
+ _check_for_column_4_module_collision(regular_slot)
178
+
150
179
  for staging_slot in surrounding_slots.staging_slots:
151
180
  if _slot_has_potential_colliding_object(
152
181
  engine_state=engine_state,
153
182
  pipette_bounds=pipette_bounds_at_well_location,
154
- surrounding_slot=staging_slot,
183
+ surrounding_location=staging_slot,
155
184
  ):
156
185
  raise PartialTipMovementNotAllowedError(
157
186
  f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
@@ -178,18 +207,45 @@ def _get_critical_point_to_use(
178
207
  def _slot_has_potential_colliding_object(
179
208
  engine_state: StateView,
180
209
  pipette_bounds: Tuple[Point, Point, Point, Point],
181
- surrounding_slot: Union[DeckSlotName, StagingSlotName],
210
+ surrounding_location: Union[DeckSlotName, StagingSlotName, LoadedModule],
182
211
  ) -> bool:
183
- """Return the slot, if any, that has an item that the pipette might collide into."""
184
- # Check if slot overlaps with pipette position
185
- slot_pos = engine_state.addressable_areas.get_addressable_area_position(
186
- addressable_area_name=surrounding_slot.id,
187
- do_compatibility_check=False,
188
- )
189
- slot_bounds = engine_state.addressable_areas.get_addressable_area_bounding_box(
190
- addressable_area_name=surrounding_slot.id,
191
- do_compatibility_check=False,
192
- )
212
+ """Return the slot, if any, that has an item that the pipette might collide into.
213
+ Can be provided a Deck Slot, Staging Slot, or Column 4 Module.
214
+ """
215
+ if isinstance(surrounding_location, LoadedModule):
216
+ if (
217
+ engine_state.modules.is_column_4_module(surrounding_location.model)
218
+ and surrounding_location.location is not None
219
+ ):
220
+ module_area = (
221
+ engine_state.modules.ensure_and_convert_module_fixture_location(
222
+ surrounding_location.location.slotName, surrounding_location.model
223
+ )
224
+ )
225
+ slot_pos = engine_state.addressable_areas.get_addressable_area_position(
226
+ addressable_area_name=module_area,
227
+ do_compatibility_check=False,
228
+ )
229
+ slot_bounds = (
230
+ engine_state.addressable_areas.get_addressable_area_bounding_box(
231
+ addressable_area_name=module_area,
232
+ do_compatibility_check=False,
233
+ )
234
+ )
235
+ else:
236
+ raise ValueError(
237
+ f"Error during collision validation, Module {surrounding_location.model} must be in Column 4."
238
+ )
239
+ else:
240
+ # Check if slot overlaps with pipette position
241
+ slot_pos = engine_state.addressable_areas.get_addressable_area_position(
242
+ addressable_area_name=surrounding_location.id,
243
+ do_compatibility_check=False,
244
+ )
245
+ slot_bounds = engine_state.addressable_areas.get_addressable_area_bounding_box(
246
+ addressable_area_name=surrounding_location.id,
247
+ do_compatibility_check=False,
248
+ )
193
249
  slot_back_left_coords = Point(slot_pos.x, slot_pos.y + slot_bounds.y, slot_pos.z)
194
250
  slot_front_right_coords = Point(slot_pos.x + slot_bounds.x, slot_pos.y, slot_pos.z)
195
251
 
@@ -199,13 +255,17 @@ def _slot_has_potential_colliding_object(
199
255
  rectangle2=(slot_back_left_coords, slot_front_right_coords),
200
256
  ):
201
257
  # Check z-height of items in overlapping slot
202
- if isinstance(surrounding_slot, DeckSlotName):
258
+ if isinstance(surrounding_location, DeckSlotName):
203
259
  slot_highest_z = engine_state.geometry.get_highest_z_in_slot(
204
- DeckSlotLocation(slotName=surrounding_slot)
260
+ DeckSlotLocation(slotName=surrounding_location)
261
+ )
262
+ elif isinstance(surrounding_location, LoadedModule):
263
+ slot_highest_z = engine_state.geometry.get_highest_z_of_column_4_module(
264
+ surrounding_location
205
265
  )
206
266
  else:
207
267
  slot_highest_z = engine_state.geometry.get_highest_z_in_slot(
208
- StagingSlotLocation(slotName=surrounding_slot)
268
+ StagingSlotLocation(slotName=surrounding_location)
209
269
  )
210
270
  return slot_highest_z >= pipette_bounds[0].z
211
271
  return False
@@ -78,7 +78,12 @@ from .module_core import (
78
78
  FlexStackerCore,
79
79
  )
80
80
  from .exceptions import InvalidModuleLocationError
81
- from . import load_labware_params, deck_conflict, overlap_versions
81
+ from . import (
82
+ load_labware_params,
83
+ deck_conflict,
84
+ overlap_versions,
85
+ _default_liquid_class_versions,
86
+ )
82
87
  from opentrons.protocol_engine.resources import labware_validation
83
88
 
84
89
  if TYPE_CHECKING:
@@ -1068,8 +1073,12 @@ class ProtocolCore(
1068
1073
  display_color=(liquid.displayColor.root if liquid.displayColor else None),
1069
1074
  )
1070
1075
 
1071
- def get_liquid_class(self, name: str, version: int) -> LiquidClass:
1076
+ def get_liquid_class(self, name: str, version: Optional[int]) -> LiquidClass:
1072
1077
  """Get an instance of a built-in liquid class."""
1078
+ if version is None:
1079
+ version = _default_liquid_class_versions.get_liquid_class_version(
1080
+ self._api_version, name
1081
+ )
1073
1082
  try:
1074
1083
  # Check if we have already loaded this liquid class' definition
1075
1084
  liquid_class_def = self._liquid_class_def_cache[(name, version)]
@@ -599,7 +599,7 @@ class LegacyProtocolCore(
599
599
  """Define a liquid to load into a well."""
600
600
  assert False, "define_liquid only supported on engine core"
601
601
 
602
- def get_liquid_class(self, name: str, version: int) -> LiquidClass:
602
+ def get_liquid_class(self, name: str, version: Optional[int]) -> LiquidClass:
603
603
  """Get an instance of a built-in liquid class."""
604
604
  assert False, "define_liquid_class is only supported on engine core"
605
605
 
@@ -297,7 +297,7 @@ class AbstractProtocol(
297
297
  """Define a liquid to load into a well."""
298
298
 
299
299
  @abstractmethod
300
- def get_liquid_class(self, name: str, version: int) -> LiquidClass:
300
+ def get_liquid_class(self, name: str, version: Optional[int]) -> LiquidClass:
301
301
  """Get an instance of a built-in liquid class."""
302
302
 
303
303
  @abstractmethod
@@ -640,6 +640,9 @@ class Labware:
640
640
  lid: Optional[str] = None,
641
641
  namespace: Optional[str] = None,
642
642
  version: Optional[int] = None,
643
+ *,
644
+ lid_namespace: Optional[str] = None,
645
+ lid_version: Optional[int] = None,
643
646
  ) -> Labware:
644
647
  """Load a compatible labware onto the labware using its load parameters.
645
648
 
@@ -650,6 +653,24 @@ class Labware:
650
653
 
651
654
  :returns: The initialized and loaded labware object.
652
655
  """
656
+ if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
657
+ if lid_namespace is not None:
658
+ raise APIVersionError(
659
+ api_element="The `lid_namespace` parameter",
660
+ until_version=str(
661
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
662
+ ),
663
+ current_version=str(self._api_version),
664
+ )
665
+ if lid_version is not None:
666
+ raise APIVersionError(
667
+ api_element="The `lid_version` parameter",
668
+ until_version=str(
669
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
670
+ ),
671
+ current_version=str(self._api_version),
672
+ )
673
+
653
674
  labware_core = self._protocol_core.load_labware(
654
675
  load_name=name,
655
676
  label=label,
@@ -674,11 +695,24 @@ class Labware:
674
695
  until_version="2.23",
675
696
  current_version=f"{self._api_version}",
676
697
  )
698
+ if (
699
+ self._api_version
700
+ < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
701
+ ):
702
+ checked_lid_namespace = namespace
703
+ checked_lid_version = version
704
+ else:
705
+ # This is currently impossible to reach because of the
706
+ # `if self._api_version < validation.validation.LID_STACK_VERSION_GATE`
707
+ # check above. This is here for now in case that check is removed in
708
+ # the future, and for symmetry with the other labware load methods.
709
+ checked_lid_namespace = lid_namespace
710
+ checked_lid_version = lid_version
677
711
  self._protocol_core.load_lid(
678
712
  load_name=lid,
679
713
  location=labware_core,
680
- namespace=namespace,
681
- version=version,
714
+ namespace=checked_lid_namespace,
715
+ version=checked_lid_version,
682
716
  )
683
717
 
684
718
  return labware
@@ -123,7 +123,7 @@ class ModuleContext(CommandPublisher):
123
123
 
124
124
  return core.geometry.add_labware(labware)
125
125
 
126
- def load_labware(
126
+ def load_labware( # noqa: C901
127
127
  self,
128
128
  name: str,
129
129
  label: Optional[str] = None,
@@ -131,6 +131,11 @@ class ModuleContext(CommandPublisher):
131
131
  version: Optional[int] = None,
132
132
  adapter: Optional[str] = None,
133
133
  lid: Optional[str] = None,
134
+ *,
135
+ adapter_namespace: Optional[str] = None,
136
+ adapter_version: Optional[int] = None,
137
+ lid_namespace: Optional[str] = None,
138
+ lid_version: Optional[int] = None,
134
139
  ) -> Labware:
135
140
  """Load a labware onto the module using its load parameters.
136
141
 
@@ -142,7 +147,11 @@ class ModuleContext(CommandPublisher):
142
147
  :returns: The initialized and loaded labware object.
143
148
 
144
149
  .. versionadded:: 2.1
145
- The *label,* *namespace,* and *version* parameters.
150
+ The ``label``, ``namespace``, and ``version`` parameters.
151
+
152
+ .. versionadded:: 2.26
153
+ The ``adapter_namespace``, ``adapter_version``,
154
+ ``lid_namespace``, and ``lid_version`` parameters.
146
155
  """
147
156
  if self._api_version < APIVersion(2, 1) and (
148
157
  label is not None or namespace is not None or version != 1
@@ -152,6 +161,40 @@ class ModuleContext(CommandPublisher):
152
161
  "are trying to utilize new load_labware parameters in 2.1"
153
162
  )
154
163
 
164
+ if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
165
+ if adapter_namespace is not None:
166
+ raise APIVersionError(
167
+ api_element="The `adapter_namespace` parameter",
168
+ until_version=str(
169
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
170
+ ),
171
+ current_version=str(self._api_version),
172
+ )
173
+ if adapter_version is not None:
174
+ raise APIVersionError(
175
+ api_element="The `adapter_version` parameter",
176
+ until_version=str(
177
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
178
+ ),
179
+ current_version=str(self._api_version),
180
+ )
181
+ if lid_namespace is not None:
182
+ raise APIVersionError(
183
+ api_element="The `lid_namespace` parameter",
184
+ until_version=str(
185
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
186
+ ),
187
+ current_version=str(self._api_version),
188
+ )
189
+ if lid_version is not None:
190
+ raise APIVersionError(
191
+ api_element="The `lid_version` parameter",
192
+ until_version=str(
193
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
194
+ ),
195
+ current_version=str(self._api_version),
196
+ )
197
+
155
198
  load_location: Union[ModuleCore, LabwareCore]
156
199
  if adapter is not None:
157
200
  if self._api_version < APIVersion(2, 15):
@@ -160,9 +203,21 @@ class ModuleContext(CommandPublisher):
160
203
  until_version="2.15",
161
204
  current_version=f"{self._api_version}",
162
205
  )
206
+
207
+ if (
208
+ self._api_version
209
+ < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
210
+ ):
211
+ checked_adapter_namespace = namespace
212
+ checked_adapter_version = None
213
+ else:
214
+ checked_adapter_namespace = adapter_namespace
215
+ checked_adapter_version = adapter_version
216
+
163
217
  loaded_adapter = self.load_adapter(
164
218
  name=adapter,
165
- namespace=namespace,
219
+ namespace=checked_adapter_namespace,
220
+ version=checked_adapter_version,
166
221
  )
167
222
  load_location = loaded_adapter._core
168
223
  else:
@@ -193,11 +248,22 @@ class ModuleContext(CommandPublisher):
193
248
  until_version="2.23",
194
249
  current_version=f"{self._api_version}",
195
250
  )
251
+
252
+ if (
253
+ self._api_version
254
+ < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
255
+ ):
256
+ checked_lid_namespace = namespace
257
+ checked_lid_version = None
258
+ else:
259
+ checked_lid_namespace = lid_namespace
260
+ checked_lid_version = lid_version
261
+
196
262
  self._protocol_core.load_lid(
197
263
  load_name=lid,
198
264
  location=labware_core,
199
- namespace=namespace,
200
- version=version,
265
+ namespace=checked_lid_namespace,
266
+ version=checked_lid_version,
201
267
  )
202
268
 
203
269
  if isinstance(self._core, LegacyModuleCore):
@@ -1330,6 +1396,11 @@ class FlexStackerContext(ModuleContext):
1330
1396
  lid: str | None = None,
1331
1397
  count: int | None = None,
1332
1398
  stacking_offset_z: float | None = None,
1399
+ *,
1400
+ adapter_namespace: str | None = None,
1401
+ adapter_version: int | None = None,
1402
+ lid_namespace: str | None = None,
1403
+ lid_version: int | None = None,
1333
1404
  ) -> None:
1334
1405
  """Configure the type and starting quantity of labware the Flex Stacker will store during a protocol. This is the only type of labware you'll be able to store in the Stacker until it's reconfigured.
1335
1406
 
@@ -1338,6 +1409,7 @@ class FlexStackerContext(ModuleContext):
1338
1409
  :param str load_name: A string to use for looking up a labware definition.
1339
1410
  You can find the ``load_name`` for any Opentrons-verified labware on the
1340
1411
  `Labware Library <https://labware.opentrons.com>`__.
1412
+
1341
1413
  :param str namespace: The namespace that the labware definition belongs to.
1342
1414
  If unspecified, the API will automatically search two namespaces:
1343
1415
 
@@ -1348,19 +1420,34 @@ class FlexStackerContext(ModuleContext):
1348
1420
  You might need to specify an explicit ``namespace`` if you have a custom
1349
1421
  definition whose ``load_name`` is the same as an Opentrons-verified
1350
1422
  definition, and you want to explicitly choose one or the other.
1423
+
1351
1424
  :param version: The version of the labware definition. You should normally
1352
1425
  leave this unspecified to let the method choose a version
1353
1426
  automatically.
1427
+
1354
1428
  :param adapter: An adapter to load the labware on top of. Accepts the same
1355
- values as the ``load_name`` parameter of :py:meth:`.load_adapter`. The
1356
- adapter will use the same namespace as the labware, and the API will
1357
- choose the adapter's version automatically.
1429
+ values as the ``load_name`` parameter of :py:meth:`.load_adapter`.
1430
+
1431
+ :param adapter_namespace: Applies to ``adapter`` the same way that ``namespace``
1432
+ applies to ``load_name``.
1433
+
1434
+ :param adapter_version: Applies to ``adapter`` the same way that ``version``
1435
+ applies to ``load_name``.
1436
+
1358
1437
  :param lid: A lid to load the on top of the main labware. Accepts the same
1359
1438
  values as the ``load_name`` parameter of :py:meth:`~.ProtocolContext.load_lid_stack`. The
1360
1439
  lid will use the same namespace as the labware, and the API will
1361
1440
  choose the lid's version automatically.
1441
+
1442
+ :param lid_namespace: Applies to ``lid`` the same way that ``namespace``
1443
+ applies to ``load_name``.
1444
+
1445
+ :param lid_version: Applies to ``lid`` the same way that ``version``
1446
+ applies to ``load_name``.
1447
+
1362
1448
  :param count: The number of labware that the Flex Stacker should store. If not specified, this will be the maximum amount of this kind of
1363
1449
  labware that the Flex Stacker is capable of storing.
1450
+
1364
1451
  :param stacking_offset_z: Stacking ``z`` offset in mm of stored labware. If specified, this overrides the
1365
1452
  calculated value in the labware definition.
1366
1453
 
@@ -1378,18 +1465,18 @@ class FlexStackerContext(ModuleContext):
1378
1465
  - Labware on adapter: the adapter (bottom side) of the upper labware unit overlaps with the top side of the labware below.
1379
1466
  - Labware with lid: the labware (bottom side) of the upper labware unit overlaps with the lid (top side) of the unit below.
1380
1467
  - Labware with lid and adapter: the adapter (bottom side) of the upper labware unit overlaps with the lid (top side) of the unit below.
1381
-
1382
1468
  """
1469
+
1383
1470
  self._core.set_stored_labware(
1384
1471
  main_load_name=load_name,
1385
1472
  main_namespace=namespace,
1386
1473
  main_version=version,
1387
1474
  lid_load_name=lid,
1388
- lid_namespace=namespace,
1389
- lid_version=version,
1475
+ lid_namespace=lid_namespace,
1476
+ lid_version=lid_version,
1390
1477
  adapter_load_name=adapter,
1391
- adapter_namespace=namespace,
1392
- adapter_version=version,
1478
+ adapter_namespace=adapter_namespace,
1479
+ adapter_version=adapter_version,
1393
1480
  count=count,
1394
1481
  stacking_offset_z=stacking_offset_z,
1395
1482
  )