opentrons 8.6.0a11__py3-none-any.whl → 8.7.0a0__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 (27) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/cli/analyze.py +58 -2
  3. opentrons/hardware_control/backends/ot3controller.py +22 -13
  4. opentrons/hardware_control/backends/ot3simulator.py +1 -1
  5. opentrons/hardware_control/ot3api.py +1 -1
  6. opentrons/protocol_api/core/engine/_default_liquid_class_versions.py +54 -0
  7. opentrons/protocol_api/core/engine/protocol.py +11 -2
  8. opentrons/protocol_api/core/engine/transfer_components_executor.py +36 -20
  9. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -1
  10. opentrons/protocol_api/core/protocol.py +1 -1
  11. opentrons/protocol_api/labware.py +36 -2
  12. opentrons/protocol_api/module_contexts.py +100 -13
  13. opentrons/protocol_api/protocol_context.py +162 -12
  14. opentrons/protocol_api/validation.py +4 -0
  15. opentrons/protocol_engine/commands/command_unions.py +2 -0
  16. opentrons/protocol_engine/commands/flex_stacker/common.py +13 -0
  17. opentrons/protocol_engine/commands/flex_stacker/store.py +20 -2
  18. opentrons/protocol_engine/execution/labware_movement.py +5 -11
  19. opentrons/protocol_engine/state/labware.py +66 -0
  20. opentrons/protocol_engine/types/__init__.py +2 -0
  21. opentrons/protocol_engine/types/labware.py +9 -0
  22. opentrons/protocols/api_support/definitions.py +1 -1
  23. {opentrons-8.6.0a11.dist-info → opentrons-8.7.0a0.dist-info}/METADATA +4 -4
  24. {opentrons-8.6.0a11.dist-info → opentrons-8.7.0a0.dist-info}/RECORD +27 -26
  25. {opentrons-8.6.0a11.dist-info → opentrons-8.7.0a0.dist-info}/WHEEL +0 -0
  26. {opentrons-8.6.0a11.dist-info → opentrons-8.7.0a0.dist-info}/entry_points.txt +0 -0
  27. {opentrons-8.6.0a11.dist-info → opentrons-8.7.0a0.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.0a11'
32
- __version_tuple__ = version_tuple = (8, 6, 0, 'a11')
31
+ __version__ = version = '8.7.0a0'
32
+ __version_tuple__ = version_tuple = (8, 7, 0, 'a0')
33
33
 
34
34
  __commit_id__ = commit_id = None
opentrons/cli/analyze.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Opentrons analyze CLI."""
2
+
2
3
  import click
3
4
 
4
5
  from anyio import run
@@ -24,7 +25,9 @@ from typing import (
24
25
  import logging
25
26
  import sys
26
27
  import json
28
+ import gc
27
29
 
30
+ from opentrons.protocol_engine import ProtocolEngine
28
31
  from opentrons.protocol_engine.types import (
29
32
  RunTimeParameter,
30
33
  CSVRuntimeParamPaths,
@@ -94,6 +97,18 @@ class _Output:
94
97
  help="Return analysis results as JSON, formatted for human eyes. Specify --human-json-output=- to use stdout, but be aware that Python protocols may contain print() which will make the output JSON invalid.",
95
98
  type=click.File(mode="wb"),
96
99
  )
100
+ @click.option(
101
+ "--leaks",
102
+ help="Fail (via exit code) if the analysis engine has not been garbage collected after analysis is complete.",
103
+ is_flag=True,
104
+ default=False,
105
+ )
106
+ @click.option(
107
+ "--leaks-debug",
108
+ help="Drop into a PDB shell if a leak is detected",
109
+ is_flag=True,
110
+ default=False,
111
+ )
97
112
  @click.option(
98
113
  "--check",
99
114
  help="Fail (via exit code) if the protocol had an error. If not specified, always succeed.",
@@ -133,6 +148,8 @@ def analyze(
133
148
  log_output: str,
134
149
  log_level: str,
135
150
  check: bool,
151
+ leaks: bool,
152
+ leaks_debug: bool,
136
153
  ) -> int:
137
154
  """Analyze a protocol.
138
155
 
@@ -147,7 +164,18 @@ def analyze(
147
164
 
148
165
  try:
149
166
  with _capture_logs(log_output, log_level):
150
- sys.exit(run(_analyze, files, rtp_values, rtp_files, outputs, check))
167
+ sys.exit(
168
+ run(
169
+ _analyze,
170
+ files,
171
+ rtp_values,
172
+ rtp_files,
173
+ outputs,
174
+ check,
175
+ leaks or leaks_debug,
176
+ leaks_debug,
177
+ )
178
+ )
151
179
  except click.ClickException:
152
180
  raise
153
181
  except Exception as e:
@@ -344,12 +372,14 @@ async def _do_analyze(
344
372
  return await orchestrator.run(deck_configuration=[])
345
373
 
346
374
 
347
- async def _analyze(
375
+ async def _analyze( # noqa: C901
348
376
  files_and_dirs: Sequence[Path],
349
377
  rtp_values: str,
350
378
  rtp_files: str,
351
379
  outputs: Sequence[_Output],
352
380
  check: bool,
381
+ fail_on_leak: bool,
382
+ debug_on_leak: bool,
353
383
  ) -> int:
354
384
  input_files = _get_input_files(files_and_dirs)
355
385
  parsed_rtp_values = _get_runtime_parameter_values(rtp_values)
@@ -366,6 +396,32 @@ async def _analyze(
366
396
  analysis = await _do_analyze(protocol_source, parsed_rtp_values, rtp_paths)
367
397
  return_code = _get_return_code(analysis)
368
398
 
399
+ # This ugly code checks to see if an engine remains past garbage collection
400
+ # after analysis is complete.
401
+ # It should be here and open coded to make it a little easier to present
402
+ # the debug option.
403
+ if fail_on_leak or debug_on_leak:
404
+ gc.collect()
405
+ leaked_engine = next(
406
+ (obj for obj in gc.get_objects() if isinstance(obj, ProtocolEngine)), None
407
+ )
408
+ if leaked_engine:
409
+ if fail_on_leak:
410
+ print(
411
+ "A ProtocolEngine instance exists even after garbage collection; "
412
+ "some thing (likely in the protocol) has caused it to be leaked, "
413
+ "likely by reference to the engine or something that refers to the "
414
+ "engine after the run function ends.",
415
+ file=sys.stderr,
416
+ )
417
+ return_code = -2
418
+ if debug_on_leak:
419
+ print(
420
+ "You are now in an interactive PDB (https://docs.python.org/3.10/library/pdb.html) "
421
+ "session; the leaked engine is bound to the variable leaked_engine."
422
+ )
423
+ breakpoint()
424
+
369
425
  if not outputs:
370
426
  return return_code
371
427
 
@@ -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,54 @@
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
+ "water": 2,
32
+ },
33
+ }
34
+
35
+
36
+ def get_liquid_class_version(
37
+ api_version: APIVersion,
38
+ liquid_class_name: str,
39
+ ) -> int:
40
+ """Return what version of a liquid class the Protocol API should load by default."""
41
+ default_lc_versions_newest_to_oldest = sorted(
42
+ DEFAULT_LIQUID_CLASS_VERSIONS.items(), key=lambda kv: kv[0], reverse=True
43
+ )
44
+ for (
45
+ breakpoint_api_version,
46
+ breakpoint_liquid_class_versions,
47
+ ) in default_lc_versions_newest_to_oldest:
48
+ if (
49
+ api_version >= breakpoint_api_version
50
+ and liquid_class_name in breakpoint_liquid_class_versions
51
+ ):
52
+ return breakpoint_liquid_class_versions[liquid_class_name]
53
+
54
+ return 1
@@ -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)]
@@ -5,7 +5,7 @@ import logging
5
5
  from copy import deepcopy
6
6
  from enum import Enum
7
7
  from typing import TYPE_CHECKING, Optional, Union, Literal
8
- from dataclasses import dataclass, field
8
+ from dataclasses import dataclass, field, replace
9
9
 
10
10
  from opentrons_shared_data.liquid_classes.liquid_class_definition import (
11
11
  PositionReference,
@@ -21,7 +21,6 @@ from opentrons.protocol_api._liquid_properties import (
21
21
  MultiDispenseProperties,
22
22
  TouchTipProperties,
23
23
  )
24
- from opentrons.protocol_engine.errors import TouchTipDisabledError
25
24
  from opentrons.types import Location, Point, Mount
26
25
  from opentrons.protocols.advanced_control.transfers.transfer_liquid_utils import (
27
26
  LocationCheckDescriptors,
@@ -466,7 +465,7 @@ class TransferComponentsExecutor:
466
465
  2. If blowout is enabled and “destination”
467
466
  - Do blow-out (at the retract position)
468
467
  - Leave plunger down
469
- 3. Touch-tip
468
+ 3. Touch-tip in the destination well.
470
469
  4. If not ready-to-aspirate
471
470
  - Prepare-to-aspirate (at the retract position)
472
471
  5. Air-gap (at the retract position)
@@ -479,7 +478,7 @@ class TransferComponentsExecutor:
479
478
  6. If blowout is “source” or “trash”
480
479
  - Move to location (top of Well)
481
480
  - Do blow-out (top of well)
482
- - Do touch-tip (?????) (only if it’s in a non-trash location)
481
+ - Do touch-tip AGAIN at the source well (if blowout in a non-trash location)
483
482
  - Prepare-to-aspirate (top of well)
484
483
  - Do air-gap (top of well)
485
484
  7. If drop tip, move to drop tip location, drop tip
@@ -563,9 +562,9 @@ class TransferComponentsExecutor:
563
562
  blowout_props.enabled
564
563
  and blowout_props.location != BlowoutLocation.DESTINATION
565
564
  ):
566
- # TODO: no-op touch tip if touch tip is enabled and blowout is in trash/ reservoir/ any labware with touch-tip disabled
567
565
  assert blowout_props.flow_rate is not None
568
566
  self._instrument.set_flow_rate(blow_out=blowout_props.flow_rate)
567
+ blowout_touch_tip_props = retract_props.touch_tip
569
568
  touch_tip_and_air_gap_location: Union[Location, TrashBin, WasteChute]
570
569
  if blowout_props.location == BlowoutLocation.SOURCE:
571
570
  if source_location is None or source_well is None:
@@ -584,6 +583,13 @@ class TransferComponentsExecutor:
584
583
  source_well.get_top(0), labware=source_location.labware
585
584
  )
586
585
  touch_tip_and_air_gap_well = source_well
586
+ # Skip touch tip if blowing out at the SOURCE and it's untouchable:
587
+ if (
588
+ "touchTipDisabled"
589
+ in source_location.labware.quirks_from_any_parent()
590
+ ):
591
+ blowout_touch_tip_props = replace(blowout_touch_tip_props)
592
+ blowout_touch_tip_props.enabled = False
587
593
  else:
588
594
  self._instrument.blow_out(
589
595
  location=trash_location,
@@ -612,7 +618,7 @@ class TransferComponentsExecutor:
612
618
  )
613
619
  # Do touch tip and air gap again after blowing out into source well or trash
614
620
  self._do_touch_tip_and_air_gap_after_dispense(
615
- touch_tip_properties=retract_props.touch_tip,
621
+ touch_tip_properties=blowout_touch_tip_props,
616
622
  location=touch_tip_and_air_gap_location,
617
623
  well=touch_tip_and_air_gap_well,
618
624
  air_gap_volume=air_gap_volume,
@@ -758,6 +764,7 @@ class TransferComponentsExecutor:
758
764
  ):
759
765
  assert blowout_props.flow_rate is not None
760
766
  self._instrument.set_flow_rate(blow_out=blowout_props.flow_rate)
767
+ blowout_touch_tip_props = retract_props.touch_tip
761
768
  touch_tip_and_air_gap_location: Union[Location, TrashBin, WasteChute]
762
769
  if blowout_props.location == BlowoutLocation.SOURCE:
763
770
  if source_location is None or source_well is None:
@@ -776,6 +783,13 @@ class TransferComponentsExecutor:
776
783
  source_well.get_top(0), labware=source_location.labware
777
784
  )
778
785
  touch_tip_and_air_gap_well = source_well
786
+ # Skip touch tip if blowing out at the SOURCE and it's untouchable:
787
+ if (
788
+ "touchTipDisabled"
789
+ in source_location.labware.quirks_from_any_parent()
790
+ ):
791
+ blowout_touch_tip_props = replace(blowout_touch_tip_props)
792
+ blowout_touch_tip_props.enabled = False
779
793
  else:
780
794
  self._instrument.blow_out(
781
795
  location=trash_location,
@@ -807,13 +821,13 @@ class TransferComponentsExecutor:
807
821
  air_gap_volume = 0
808
822
  # Do touch tip and air gap again after blowing out into source well or trash
809
823
  self._do_touch_tip_and_air_gap_after_dispense(
810
- touch_tip_properties=retract_props.touch_tip,
824
+ touch_tip_properties=blowout_touch_tip_props,
811
825
  location=touch_tip_and_air_gap_location,
812
826
  well=touch_tip_and_air_gap_well,
813
827
  air_gap_volume=air_gap_volume,
814
828
  )
815
829
 
816
- def _do_touch_tip_and_air_gap_after_dispense( # noqa: C901
830
+ def _do_touch_tip_and_air_gap_after_dispense(
817
831
  self,
818
832
  touch_tip_properties: TouchTipProperties,
819
833
  location: Union[Location, TrashBin, WasteChute],
@@ -822,6 +836,12 @@ class TransferComponentsExecutor:
822
836
  ) -> None:
823
837
  """Perform touch tip and air gap as part of post-dispense retract.
824
838
 
839
+ This function can be invoked up to 2 times for each dispense:
840
+ 1) Once for touching tip at the dispense location.
841
+ 2) Then again in the blowout location if it is not the dispense location.
842
+ For case (2), the caller should disable touch-tip in touch_tip_properties
843
+ if the blowout location is not touchable (such as reservoirs).
844
+
825
845
  If the retract location is at or above the safe location of
826
846
  AIR_GAP_LOC_Z_OFFSET_FROM_WELL_TOP, then add the air gap at the retract location
827
847
  (where the pipette is already assumed to be at).
@@ -842,18 +862,14 @@ class TransferComponentsExecutor:
842
862
  # whether the touch tip params from transfer props should be used for
843
863
  # both dest-well touch tip and non-dest-well touch tip.
844
864
  if isinstance(location, Location) and well is not None:
845
- try:
846
- self._instrument.touch_tip(
847
- location=location,
848
- well_core=well,
849
- radius=1,
850
- z_offset=touch_tip_properties.z_offset,
851
- speed=touch_tip_properties.speed,
852
- mm_from_edge=touch_tip_properties.mm_from_edge,
853
- )
854
- except TouchTipDisabledError:
855
- # TODO: log a warning
856
- pass
865
+ self._instrument.touch_tip(
866
+ location=location,
867
+ well_core=well,
868
+ radius=1,
869
+ z_offset=touch_tip_properties.z_offset,
870
+ speed=touch_tip_properties.speed,
871
+ mm_from_edge=touch_tip_properties.mm_from_edge,
872
+ )
857
873
 
858
874
  # Move back to the 'retract' position
859
875
  self._instrument.move_to(
@@ -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