opentrons 8.3.1a1__py2.py3-none-any.whl → 8.4.0a1__py2.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.
Files changed (192) hide show
  1. opentrons/calibration_storage/ot2/mark_bad_calibration.py +2 -0
  2. opentrons/calibration_storage/ot2/tip_length.py +6 -6
  3. opentrons/config/advanced_settings.py +9 -11
  4. opentrons/config/feature_flags.py +0 -4
  5. opentrons/config/reset.py +7 -2
  6. opentrons/drivers/asyncio/communication/__init__.py +2 -0
  7. opentrons/drivers/asyncio/communication/async_serial.py +4 -0
  8. opentrons/drivers/asyncio/communication/errors.py +41 -8
  9. opentrons/drivers/asyncio/communication/serial_connection.py +36 -10
  10. opentrons/drivers/flex_stacker/__init__.py +9 -3
  11. opentrons/drivers/flex_stacker/abstract.py +140 -15
  12. opentrons/drivers/flex_stacker/driver.py +593 -47
  13. opentrons/drivers/flex_stacker/errors.py +64 -0
  14. opentrons/drivers/flex_stacker/simulator.py +222 -24
  15. opentrons/drivers/flex_stacker/types.py +211 -15
  16. opentrons/drivers/flex_stacker/utils.py +19 -0
  17. opentrons/execute.py +4 -2
  18. opentrons/hardware_control/api.py +5 -0
  19. opentrons/hardware_control/backends/flex_protocol.py +4 -0
  20. opentrons/hardware_control/backends/ot3controller.py +12 -1
  21. opentrons/hardware_control/backends/ot3simulator.py +3 -0
  22. opentrons/hardware_control/backends/subsystem_manager.py +8 -4
  23. opentrons/hardware_control/instruments/ot2/instrument_calibration.py +10 -6
  24. opentrons/hardware_control/instruments/ot3/pipette_handler.py +59 -6
  25. opentrons/hardware_control/modules/__init__.py +12 -1
  26. opentrons/hardware_control/modules/absorbance_reader.py +11 -9
  27. opentrons/hardware_control/modules/flex_stacker.py +498 -0
  28. opentrons/hardware_control/modules/heater_shaker.py +12 -10
  29. opentrons/hardware_control/modules/magdeck.py +5 -1
  30. opentrons/hardware_control/modules/tempdeck.py +5 -1
  31. opentrons/hardware_control/modules/thermocycler.py +15 -14
  32. opentrons/hardware_control/modules/types.py +191 -1
  33. opentrons/hardware_control/modules/utils.py +3 -0
  34. opentrons/hardware_control/motion_utilities.py +20 -0
  35. opentrons/hardware_control/ot3api.py +145 -15
  36. opentrons/hardware_control/protocols/liquid_handler.py +47 -1
  37. opentrons/hardware_control/types.py +6 -0
  38. opentrons/legacy_commands/commands.py +19 -3
  39. opentrons/legacy_commands/helpers.py +15 -0
  40. opentrons/legacy_commands/types.py +3 -2
  41. opentrons/protocol_api/__init__.py +2 -0
  42. opentrons/protocol_api/_liquid.py +39 -8
  43. opentrons/protocol_api/_liquid_properties.py +20 -19
  44. opentrons/protocol_api/_transfer_liquid_validation.py +91 -0
  45. opentrons/protocol_api/core/common.py +3 -1
  46. opentrons/protocol_api/core/engine/deck_conflict.py +11 -1
  47. opentrons/protocol_api/core/engine/instrument.py +1233 -65
  48. opentrons/protocol_api/core/engine/labware.py +8 -4
  49. opentrons/protocol_api/core/engine/load_labware_params.py +68 -10
  50. opentrons/protocol_api/core/engine/module_core.py +118 -2
  51. opentrons/protocol_api/core/engine/protocol.py +253 -11
  52. opentrons/protocol_api/core/engine/stringify.py +19 -8
  53. opentrons/protocol_api/core/engine/transfer_components_executor.py +853 -0
  54. opentrons/protocol_api/core/engine/well.py +60 -5
  55. opentrons/protocol_api/core/instrument.py +65 -19
  56. opentrons/protocol_api/core/labware.py +6 -2
  57. opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
  58. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +69 -21
  59. opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
  60. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
  61. opentrons/protocol_api/core/legacy/legacy_well_core.py +25 -1
  62. opentrons/protocol_api/core/legacy/load_info.py +4 -12
  63. opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
  64. opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
  65. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +67 -21
  66. opentrons/protocol_api/core/module.py +43 -0
  67. opentrons/protocol_api/core/protocol.py +33 -0
  68. opentrons/protocol_api/core/well.py +21 -1
  69. opentrons/protocol_api/instrument_context.py +246 -123
  70. opentrons/protocol_api/labware.py +75 -11
  71. opentrons/protocol_api/module_contexts.py +140 -0
  72. opentrons/protocol_api/protocol_context.py +156 -16
  73. opentrons/protocol_api/validation.py +51 -41
  74. opentrons/protocol_engine/__init__.py +21 -2
  75. opentrons/protocol_engine/actions/actions.py +5 -5
  76. opentrons/protocol_engine/clients/sync_client.py +6 -0
  77. opentrons/protocol_engine/commands/__init__.py +30 -0
  78. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
  79. opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
  80. opentrons/protocol_engine/commands/aspirate.py +6 -2
  81. opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
  82. opentrons/protocol_engine/commands/aspirate_while_tracking.py +237 -0
  83. opentrons/protocol_engine/commands/blow_out.py +2 -0
  84. opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
  85. opentrons/protocol_engine/commands/command_unions.py +69 -0
  86. opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
  87. opentrons/protocol_engine/commands/dispense.py +3 -1
  88. opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
  89. opentrons/protocol_engine/commands/dispense_while_tracking.py +240 -0
  90. opentrons/protocol_engine/commands/drop_tip.py +23 -1
  91. opentrons/protocol_engine/commands/evotip_dispense.py +6 -7
  92. opentrons/protocol_engine/commands/evotip_seal_pipette.py +24 -29
  93. opentrons/protocol_engine/commands/evotip_unseal_pipette.py +1 -7
  94. opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
  95. opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
  96. opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
  97. opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
  98. opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
  99. opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
  100. opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
  101. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
  102. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
  103. opentrons/protocol_engine/commands/flex_stacker/store.py +288 -0
  104. opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
  105. opentrons/protocol_engine/commands/labware_handling_common.py +24 -0
  106. opentrons/protocol_engine/commands/liquid_probe.py +21 -12
  107. opentrons/protocol_engine/commands/load_labware.py +42 -39
  108. opentrons/protocol_engine/commands/load_lid.py +21 -13
  109. opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
  110. opentrons/protocol_engine/commands/load_module.py +18 -17
  111. opentrons/protocol_engine/commands/load_pipette.py +3 -0
  112. opentrons/protocol_engine/commands/move_labware.py +139 -20
  113. opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
  114. opentrons/protocol_engine/commands/pipetting_common.py +154 -7
  115. opentrons/protocol_engine/commands/prepare_to_aspirate.py +17 -2
  116. opentrons/protocol_engine/commands/reload_labware.py +6 -19
  117. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
  118. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
  119. opentrons/protocol_engine/errors/__init__.py +8 -0
  120. opentrons/protocol_engine/errors/exceptions.py +50 -0
  121. opentrons/protocol_engine/execution/equipment.py +123 -106
  122. opentrons/protocol_engine/execution/labware_movement.py +8 -6
  123. opentrons/protocol_engine/execution/pipetting.py +233 -26
  124. opentrons/protocol_engine/execution/tip_handler.py +14 -5
  125. opentrons/protocol_engine/labware_offset_standardization.py +173 -0
  126. opentrons/protocol_engine/protocol_engine.py +22 -13
  127. opentrons/protocol_engine/resources/deck_configuration_provider.py +94 -2
  128. opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
  129. opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
  130. opentrons/protocol_engine/resources/labware_validation.py +7 -5
  131. opentrons/protocol_engine/slot_standardization.py +11 -23
  132. opentrons/protocol_engine/state/addressable_areas.py +84 -46
  133. opentrons/protocol_engine/state/frustum_helpers.py +26 -10
  134. opentrons/protocol_engine/state/geometry.py +683 -100
  135. opentrons/protocol_engine/state/labware.py +252 -55
  136. opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
  137. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
  138. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
  139. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
  140. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
  141. opentrons/protocol_engine/state/modules.py +178 -52
  142. opentrons/protocol_engine/state/pipettes.py +54 -0
  143. opentrons/protocol_engine/state/state.py +1 -1
  144. opentrons/protocol_engine/state/tips.py +14 -0
  145. opentrons/protocol_engine/state/update_types.py +180 -25
  146. opentrons/protocol_engine/state/wells.py +54 -8
  147. opentrons/protocol_engine/types/__init__.py +292 -0
  148. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  149. opentrons/protocol_engine/types/command_annotations.py +53 -0
  150. opentrons/protocol_engine/types/deck_configuration.py +72 -0
  151. opentrons/protocol_engine/types/execution.py +96 -0
  152. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  153. opentrons/protocol_engine/types/instrument.py +47 -0
  154. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  155. opentrons/protocol_engine/types/labware.py +110 -0
  156. opentrons/protocol_engine/types/labware_movement.py +22 -0
  157. opentrons/protocol_engine/types/labware_offset_location.py +108 -0
  158. opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
  159. opentrons/protocol_engine/types/liquid.py +40 -0
  160. opentrons/protocol_engine/types/liquid_class.py +59 -0
  161. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  162. opentrons/protocol_engine/types/liquid_level_detection.py +137 -0
  163. opentrons/protocol_engine/types/location.py +193 -0
  164. opentrons/protocol_engine/types/module.py +269 -0
  165. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  166. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  167. opentrons/protocol_engine/types/tip.py +18 -0
  168. opentrons/protocol_engine/types/util.py +21 -0
  169. opentrons/protocol_engine/types/well_position.py +107 -0
  170. opentrons/protocol_reader/extract_labware_definitions.py +7 -3
  171. opentrons/protocol_reader/file_format_validator.py +5 -3
  172. opentrons/protocol_runner/json_translator.py +4 -2
  173. opentrons/protocol_runner/legacy_command_mapper.py +6 -2
  174. opentrons/protocol_runner/run_orchestrator.py +4 -1
  175. opentrons/protocols/advanced_control/transfers/common.py +48 -1
  176. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
  177. opentrons/protocols/api_support/definitions.py +1 -1
  178. opentrons/protocols/api_support/instrument.py +16 -3
  179. opentrons/protocols/labware.py +5 -6
  180. opentrons/protocols/models/__init__.py +0 -21
  181. opentrons/simulate.py +4 -2
  182. opentrons/types.py +15 -6
  183. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/METADATA +4 -4
  184. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/RECORD +188 -148
  185. opentrons/calibration_storage/ot2/models/defaults.py +0 -0
  186. opentrons/calibration_storage/ot3/models/defaults.py +0 -0
  187. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  188. opentrons/protocol_engine/types.py +0 -1311
  189. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/LICENSE +0 -0
  190. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/WHEEL +0 -0
  191. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/entry_points.txt +0 -0
  192. {opentrons-8.3.1a1.dist-info → opentrons-8.4.0a1.dist-info}/top_level.txt +0 -0
@@ -14,13 +14,15 @@ from typing import (
14
14
  from math import isinf, isnan
15
15
  from typing_extensions import TypeGuard
16
16
 
17
- from opentrons_shared_data.labware.labware_definition import LabwareRole
18
- from opentrons_shared_data.pipette.types import PipetteNameType
17
+ from opentrons_shared_data.labware.labware_definition import (
18
+ LabwareDefinition,
19
+ LabwareRole,
20
+ )
21
+ from opentrons_shared_data.pipette.types import PipetteNameType, PIPETTE_API_NAMES_MAP
19
22
  from opentrons_shared_data.robot.types import RobotType
20
23
 
21
24
  from opentrons.protocols.api_support.types import APIVersion, ThermocyclerStep
22
25
  from opentrons.protocols.api_support.util import APIVersionError
23
- from opentrons.protocols.models import LabwareDefinition
24
26
  from opentrons.protocols.advanced_control.transfers.common import TransferTipPolicyV2
25
27
  from opentrons.types import (
26
28
  Mount,
@@ -39,6 +41,7 @@ from opentrons.hardware_control.modules.types import (
39
41
  HeaterShakerModuleModel,
40
42
  MagneticBlockModel,
41
43
  AbsorbanceReaderModel,
44
+ FlexStackerModuleModel,
42
45
  )
43
46
 
44
47
  from .disposal_locations import TrashBin, WasteChute
@@ -56,29 +59,8 @@ _STAGING_DECK_SLOT_VERSION_GATE = APIVersion(2, 16)
56
59
  # The first APIVersion where Python protocols can load lids as stacks and treat them as attributes of a parent labware.
57
60
  LID_STACK_VERSION_GATE = APIVersion(2, 23)
58
61
 
59
- # Mapping of public Python Protocol API pipette load names
60
- # to names used by the internal Opentrons system
61
- _PIPETTE_NAMES_MAP = {
62
- "p10_single": PipetteNameType.P10_SINGLE,
63
- "p10_multi": PipetteNameType.P10_MULTI,
64
- "p20_single_gen2": PipetteNameType.P20_SINGLE_GEN2,
65
- "p20_multi_gen2": PipetteNameType.P20_MULTI_GEN2,
66
- "p50_single": PipetteNameType.P50_SINGLE,
67
- "p50_multi": PipetteNameType.P50_MULTI,
68
- "p300_single": PipetteNameType.P300_SINGLE,
69
- "p300_multi": PipetteNameType.P300_MULTI,
70
- "p300_single_gen2": PipetteNameType.P300_SINGLE_GEN2,
71
- "p300_multi_gen2": PipetteNameType.P300_MULTI_GEN2,
72
- "p1000_single": PipetteNameType.P1000_SINGLE,
73
- "p1000_single_gen2": PipetteNameType.P1000_SINGLE_GEN2,
74
- "flex_1channel_50": PipetteNameType.P50_SINGLE_FLEX,
75
- "flex_8channel_50": PipetteNameType.P50_MULTI_FLEX,
76
- "flex_1channel_1000": PipetteNameType.P1000_SINGLE_FLEX,
77
- "flex_8channel_1000": PipetteNameType.P1000_MULTI_FLEX,
78
- "flex_8channel_1000_em": PipetteNameType.P1000_MULTI_EM,
79
- "flex_96channel_1000": PipetteNameType.P1000_96,
80
- "flex_96channel_200": PipetteNameType.P200_96,
81
- }
62
+ # The first APIVersion where Python protocols can use the Flex Stacker module.
63
+ FLEX_STACKER_VERSION_GATE = APIVersion(2, 23)
82
64
 
83
65
 
84
66
  class InvalidPipetteMountError(ValueError):
@@ -192,7 +174,7 @@ def ensure_pipette_name(pipette_name: str) -> PipetteNameType:
192
174
  pipette_name = ensure_lowercase_name(pipette_name)
193
175
 
194
176
  try:
195
- return _PIPETTE_NAMES_MAP[pipette_name]
177
+ return PIPETTE_API_NAMES_MAP[pipette_name]
196
178
  except KeyError:
197
179
  raise ValueError(
198
180
  f"Cannot resolve {pipette_name} to pipette, must be given valid pipette name."
@@ -411,6 +393,7 @@ _MODULE_MODELS: Dict[str, ModuleModel] = {
411
393
  "heaterShakerModuleV1": HeaterShakerModuleModel.HEATER_SHAKER_V1,
412
394
  "magneticBlockV1": MagneticBlockModel.MAGNETIC_BLOCK_V1,
413
395
  "absorbanceReaderV1": AbsorbanceReaderModel.ABSORBANCE_READER_V1,
396
+ "flexStackerModuleV1": FlexStackerModuleModel.FLEX_STACKER_V1,
414
397
  }
415
398
 
416
399
 
@@ -644,6 +627,16 @@ def ensure_positive_float(value: Union[int, float]) -> float:
644
627
  return float_value
645
628
 
646
629
 
630
+ def ensure_greater_than_zero_float(value: Union[int, float]) -> float:
631
+ """Ensure value is a positive and real float value."""
632
+ float_value = ensure_float(value)
633
+ if isnan(float_value) or isinf(float_value):
634
+ raise ValueError("Value must be a defined, non-infinite number.")
635
+ if float_value <= 0:
636
+ raise ValueError("Value must be a positive float greater than 0.")
637
+ return float_value
638
+
639
+
647
640
  def ensure_positive_int(value: int) -> int:
648
641
  """Ensure value is a positive integer."""
649
642
  if not isinstance(value, int):
@@ -711,20 +704,18 @@ def ensure_valid_flat_wells_list_for_transfer_v2(
711
704
  )
712
705
 
713
706
 
714
- def ensure_valid_tip_drop_location_for_transfer_v2(
715
- tip_drop_location: Union[Location, Well, TrashBin, WasteChute]
716
- ) -> Union[Location, Well, TrashBin, WasteChute]:
717
- """Ensure that the tip drop location is valid for v2 transfer."""
707
+ def ensure_valid_trash_location_for_transfer_v2(
708
+ trash_location: Union[Location, Well, TrashBin, WasteChute]
709
+ ) -> Union[Location, TrashBin, WasteChute]:
710
+ """Ensure that the trash location is valid for v2 transfer."""
718
711
  from .labware import Well
719
712
 
720
- if (
721
- isinstance(tip_drop_location, Well)
722
- or isinstance(tip_drop_location, TrashBin)
723
- or isinstance(tip_drop_location, WasteChute)
724
- ):
725
- return tip_drop_location
726
- elif isinstance(tip_drop_location, Location):
727
- _, maybe_well = tip_drop_location.labware.get_parent_labware_and_well()
713
+ if isinstance(trash_location, TrashBin) or isinstance(trash_location, WasteChute):
714
+ return trash_location
715
+ elif isinstance(trash_location, Well):
716
+ return trash_location.top()
717
+ elif isinstance(trash_location, Location):
718
+ _, maybe_well = trash_location.labware.get_parent_labware_and_well()
728
719
 
729
720
  if maybe_well is None:
730
721
  raise TypeError(
@@ -734,11 +725,30 @@ def ensure_valid_tip_drop_location_for_transfer_v2(
734
725
  " since that is where a tip is dropped."
735
726
  " However, the given location doesn't refer to any well."
736
727
  )
737
- return tip_drop_location
728
+ return trash_location
738
729
  else:
739
730
  raise TypeError(
740
731
  f"If specified, location should be an instance of"
741
732
  f" `types.Location` (e.g. the return value from `Well.top()`)"
742
733
  f" or `Well` (e.g. `reservoir.wells()[0]`) or an instance of `TrashBin` or `WasteChute`."
743
- f" However, it is '{tip_drop_location}'."
734
+ f" However, it is '{trash_location}'."
744
735
  )
736
+
737
+
738
+ def convert_flex_stacker_load_slot(slot_name: StagingSlotName) -> DeckSlotName:
739
+ """
740
+ Ensure a Flex Stacker load location to a deck slot location.
741
+
742
+ Args:
743
+ slot_name: The input staging slot location.
744
+
745
+ Returns:
746
+ A `DeckSlotName` on the deck.
747
+ """
748
+ _map = {
749
+ StagingSlotName.SLOT_A4: DeckSlotName.SLOT_A3,
750
+ StagingSlotName.SLOT_B4: DeckSlotName.SLOT_B3,
751
+ StagingSlotName.SLOT_C4: DeckSlotName.SLOT_C3,
752
+ StagingSlotName.SLOT_D4: DeckSlotName.SLOT_D3,
753
+ }
754
+ return _map[slot_name]
@@ -26,21 +26,30 @@ from .plugins import AbstractPlugin
26
26
 
27
27
  from .types import (
28
28
  LabwareOffset,
29
+ LegacyLabwareOffsetCreate,
29
30
  LabwareOffsetCreate,
30
31
  LabwareOffsetVector,
31
- LabwareOffsetLocation,
32
+ LegacyLabwareOffsetLocation,
33
+ LabwareOffsetLocationSequence,
34
+ OnLabwareOffsetLocationSequenceComponent,
35
+ OnModuleOffsetLocationSequenceComponent,
36
+ OnAddressableAreaOffsetLocationSequenceComponent,
37
+ LabwareOffsetLocationSequenceComponents,
32
38
  LabwareMovementStrategy,
33
39
  AddressableOffsetVector,
34
40
  DeckPoint,
35
41
  DeckType,
36
42
  DeckSlotLocation,
43
+ InStackerHopperLocation,
37
44
  ModuleLocation,
38
45
  OnLabwareLocation,
39
46
  AddressableAreaLocation,
40
47
  OFF_DECK_LOCATION,
48
+ SYSTEM_LOCATION,
41
49
  Dimensions,
42
50
  EngineStatus,
43
51
  LabwareLocation,
52
+ LoadableLabwareLocation,
44
53
  NonStackedLocation,
45
54
  LoadedLabware,
46
55
  LoadedModule,
@@ -94,8 +103,15 @@ __all__ = [
94
103
  # public value interfaces and models
95
104
  "LabwareOffset",
96
105
  "LabwareOffsetCreate",
106
+ "LegacyLabwareOffsetCreate",
107
+ "LabwareOffsetLocationSequence",
97
108
  "LabwareOffsetVector",
98
- "LabwareOffsetLocation",
109
+ "OnLabwareOffsetLocationSequenceComponent",
110
+ "OnModuleOffsetLocationSequenceComponent",
111
+ "OnAddressableAreaOffsetLocationSequenceComponent",
112
+ "LabwareOffsetLocationSequenceComponents",
113
+ "LegacyLabwareOffsetCreate",
114
+ "LegacyLabwareOffsetLocation",
99
115
  "LabwareMovementStrategy",
100
116
  "AddressableOffsetVector",
101
117
  "DeckSlotLocation",
@@ -104,10 +120,13 @@ __all__ = [
104
120
  "ModuleLocation",
105
121
  "OnLabwareLocation",
106
122
  "AddressableAreaLocation",
123
+ "InStackerHopperLocation",
107
124
  "OFF_DECK_LOCATION",
125
+ "SYSTEM_LOCATION",
108
126
  "Dimensions",
109
127
  "EngineStatus",
110
128
  "LabwareLocation",
129
+ "LoadableLabwareLocation",
111
130
  "NonStackedLocation",
112
131
  "LoadedLabware",
113
132
  "LoadedModule",
@@ -8,12 +8,12 @@ from datetime import datetime
8
8
  from enum import Enum
9
9
  from typing import List, Optional, Union
10
10
 
11
- from opentrons.protocols.models import LabwareDefinition
11
+ from opentrons_shared_data.errors import EnumeratedError
12
+ from opentrons_shared_data.labware.labware_definition import LabwareDefinition
13
+
12
14
  from opentrons.hardware_control.types import DoorState
13
15
  from opentrons.hardware_control.modules import LiveData
14
16
 
15
- from opentrons_shared_data.errors import EnumeratedError
16
-
17
17
  from ..commands import (
18
18
  Command,
19
19
  CommandCreate,
@@ -23,7 +23,7 @@ from ..error_recovery_policy import ErrorRecoveryPolicy, ErrorRecoveryType
23
23
  from ..notes.notes import CommandNote
24
24
  from ..state.update_types import StateUpdate
25
25
  from ..types import (
26
- LabwareOffsetCreate,
26
+ LabwareOffsetCreateInternal,
27
27
  ModuleDefinition,
28
28
  Liquid,
29
29
  DeckConfigurationType,
@@ -206,7 +206,7 @@ class AddLabwareOffsetAction:
206
206
 
207
207
  labware_offset_id: str
208
208
  created_at: datetime
209
- request: LabwareOffsetCreate
209
+ request: LabwareOffsetCreateInternal
210
210
 
211
211
 
212
212
  @dataclasses.dataclass(frozen=True)
@@ -107,6 +107,12 @@ class SyncClient:
107
107
  ) -> commands.LoadLiquidClassResult:
108
108
  pass
109
109
 
110
+ @overload
111
+ def execute_command_without_recovery(
112
+ self, params: commands.GetNextTipParams
113
+ ) -> commands.GetNextTipResult:
114
+ pass
115
+
110
116
  def execute_command_without_recovery(
111
117
  self, params: commands.CommandParams
112
118
  ) -> commands.CommandResult:
@@ -14,6 +14,7 @@ and/or schema generation.
14
14
  """
15
15
 
16
16
  from . import absorbance_reader
17
+ from . import flex_stacker
17
18
  from . import heater_shaker
18
19
  from . import magnetic_module
19
20
  from . import temperature_module
@@ -60,6 +61,14 @@ from .aspirate import (
60
61
  AspirateCommandType,
61
62
  )
62
63
 
64
+ from .aspirate_while_tracking import (
65
+ AspirateWhileTracking,
66
+ AspirateWhileTrackingParams,
67
+ AspirateWhileTrackingCreate,
68
+ AspirateWhileTrackingResult,
69
+ AspirateWhileTrackingCommandType,
70
+ )
71
+
63
72
  from .aspirate_in_place import (
64
73
  AspirateInPlace,
65
74
  AspirateInPlaceParams,
@@ -92,6 +101,14 @@ from .dispense import (
92
101
  DispenseCommandType,
93
102
  )
94
103
 
104
+ from .dispense_while_tracking import (
105
+ DispenseWhileTracking,
106
+ DispenseWhileTrackingParams,
107
+ DispenseWhileTrackingCreate,
108
+ DispenseWhileTrackingResult,
109
+ DispenseWhileTrackingCommandType,
110
+ )
111
+
95
112
  from .dispense_in_place import (
96
113
  DispenseInPlace,
97
114
  DispenseInPlaceParams,
@@ -435,6 +452,12 @@ __all__ = [
435
452
  "AspirateParams",
436
453
  "AspirateResult",
437
454
  "AspirateCommandType",
455
+ # aspirate while tracking command models
456
+ "AspirateWhileTracking",
457
+ "AspirateWhileTrackingCreate",
458
+ "AspirateWhileTrackingParams",
459
+ "AspirateWhileTrackingResult",
460
+ "AspirateWhileTrackingCommandType",
438
461
  # aspirate in place command models
439
462
  "AspirateInPlace",
440
463
  "AspirateInPlaceCreate",
@@ -459,6 +482,12 @@ __all__ = [
459
482
  "DispenseParams",
460
483
  "DispenseResult",
461
484
  "DispenseCommandType",
485
+ # dispense while tracking command models
486
+ "DispenseWhileTracking",
487
+ "DispenseWhileTrackingCreate",
488
+ "DispenseWhileTrackingParams",
489
+ "DispenseWhileTrackingResult",
490
+ "DispenseWhileTrackingCommandType",
462
491
  # dispense in place command models
463
492
  "DispenseInPlace",
464
493
  "DispenseInPlaceCreate",
@@ -636,6 +665,7 @@ __all__ = [
636
665
  # hardware control command models
637
666
  # hardware module command bundles
638
667
  "absorbance_reader",
668
+ "flex_stacker",
639
669
  "heater_shaker",
640
670
  "magnetic_module",
641
671
  "temperature_module",
@@ -33,7 +33,6 @@ from .read import (
33
33
 
34
34
 
35
35
  __all__ = [
36
- "MoveLidResult",
37
36
  # absorbanace_reader/closeLid
38
37
  "CloseLidCommandType",
39
38
  "CloseLidParams",
@@ -14,6 +14,7 @@ from .pipetting_common import (
14
14
  FlowRateMixin,
15
15
  BaseLiquidHandlingResult,
16
16
  OverpressureError,
17
+ DEFAULT_CORRECTION_VOLUME,
17
18
  )
18
19
  from .command import (
19
20
  AbstractCommandImpl,
@@ -84,9 +85,8 @@ class AirGapInPlaceImplementation(
84
85
  PipetteNotReadyToAirGapError: pipette plunger is not ready.
85
86
  """
86
87
  ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
87
- pipette_id=params.pipetteId,
88
+ pipette_id=params.pipetteId
88
89
  )
89
-
90
90
  if not ready_to_aspirate:
91
91
  raise PipetteNotReadyToAspirateError(
92
92
  "Pipette cannot air gap in place because of a previous blow out."
@@ -103,6 +103,7 @@ class AirGapInPlaceImplementation(
103
103
  volume=params.volume,
104
104
  flow_rate=params.flowRate,
105
105
  command_note_adder=self._command_note_adder,
106
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
106
107
  )
107
108
  except PipetteOverpressureError as e:
108
109
  return DefinedErrorData(
@@ -12,6 +12,7 @@ from .pipetting_common import (
12
12
  BaseLiquidHandlingResult,
13
13
  aspirate_in_place,
14
14
  prepare_for_aspirate,
15
+ DEFAULT_CORRECTION_VOLUME,
15
16
  )
16
17
  from .movement_common import (
17
18
  LiquidHandlingWellLocationMixin,
@@ -47,7 +48,10 @@ AspirateCommandType = Literal["aspirate"]
47
48
 
48
49
 
49
50
  class AspirateParams(
50
- PipetteIdMixin, AspirateVolumeMixin, FlowRateMixin, LiquidHandlingWellLocationMixin
51
+ PipetteIdMixin,
52
+ AspirateVolumeMixin,
53
+ FlowRateMixin,
54
+ LiquidHandlingWellLocationMixin,
51
55
  ):
52
56
  """Parameters required to aspirate from a specific well."""
53
57
 
@@ -148,7 +152,6 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
148
152
  labware_id=labware_id,
149
153
  well_name=well_name,
150
154
  )
151
-
152
155
  move_result = await move_to_well(
153
156
  movement=self._movement,
154
157
  model_utils=self._model_utils,
@@ -179,6 +182,7 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
179
182
  command_note_adder=self._command_note_adder,
180
183
  pipetting=self._pipetting,
181
184
  model_utils=self._model_utils,
185
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
182
186
  )
183
187
  state_update.append(aspirate_result.state_update)
184
188
  if isinstance(aspirate_result, DefinedErrorData):
@@ -13,6 +13,7 @@ from .pipetting_common import (
13
13
  BaseLiquidHandlingResult,
14
14
  OverpressureError,
15
15
  aspirate_in_place,
16
+ DEFAULT_CORRECTION_VOLUME,
16
17
  )
17
18
  from .command import (
18
19
  AbstractCommandImpl,
@@ -82,7 +83,7 @@ class AspirateInPlaceImplementation(
82
83
  PipetteNotReadyToAspirateError: pipette plunger is not ready.
83
84
  """
84
85
  ready_to_aspirate = self._pipetting.get_is_ready_to_aspirate(
85
- pipette_id=params.pipetteId,
86
+ pipette_id=params.pipetteId
86
87
  )
87
88
  if not ready_to_aspirate:
88
89
  raise PipetteNotReadyToAspirateError(
@@ -108,6 +109,7 @@ class AspirateInPlaceImplementation(
108
109
  command_note_adder=self._command_note_adder,
109
110
  pipetting=self._pipetting,
110
111
  model_utils=self._model_utils,
112
+ correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
111
113
  )
112
114
  if isinstance(result, DefinedErrorData):
113
115
  if (
@@ -0,0 +1,237 @@
1
+ """Aspirate command request, result, and implementation models."""
2
+
3
+ from __future__ import annotations
4
+ from typing import TYPE_CHECKING, Optional, Type, Union
5
+ from typing_extensions import Literal
6
+
7
+ from .pipetting_common import (
8
+ OverpressureError,
9
+ PipetteIdMixin,
10
+ AspirateVolumeMixin,
11
+ FlowRateMixin,
12
+ BaseLiquidHandlingResult,
13
+ aspirate_while_tracking,
14
+ )
15
+ from .movement_common import (
16
+ LiquidHandlingWellLocationMixin,
17
+ DestinationPositionResult,
18
+ StallOrCollisionError,
19
+ move_to_well,
20
+ )
21
+ from .command import (
22
+ AbstractCommandImpl,
23
+ BaseCommand,
24
+ BaseCommandCreate,
25
+ DefinedErrorData,
26
+ SuccessData,
27
+ )
28
+ from ..state.update_types import StateUpdate
29
+ from ..errors.exceptions import PipetteNotReadyToAspirateError
30
+ from opentrons.hardware_control import HardwareControlAPI
31
+ from ..state.update_types import CLEAR
32
+ from ..types import CurrentWell, DeckPoint
33
+
34
+ if TYPE_CHECKING:
35
+ from ..execution import PipettingHandler, GantryMover, MovementHandler
36
+ from ..resources import ModelUtils
37
+ from ..state.state import StateView
38
+ from ..notes import CommandNoteAdder
39
+
40
+
41
+ AspirateWhileTrackingCommandType = Literal["aspirateWhileTracking"]
42
+
43
+
44
+ class AspirateWhileTrackingParams(
45
+ PipetteIdMixin,
46
+ AspirateVolumeMixin,
47
+ FlowRateMixin,
48
+ LiquidHandlingWellLocationMixin,
49
+ ):
50
+ """Parameters required to aspirate from a specific well."""
51
+
52
+ pass
53
+
54
+
55
+ class AspirateWhileTrackingResult(BaseLiquidHandlingResult, DestinationPositionResult):
56
+ """Result data from execution of an Aspirate command."""
57
+
58
+ pass
59
+
60
+
61
+ _ExecuteReturn = Union[
62
+ SuccessData[AspirateWhileTrackingResult],
63
+ DefinedErrorData[OverpressureError] | DefinedErrorData[StallOrCollisionError],
64
+ ]
65
+
66
+
67
+ class AspirateWhileTrackingImplementation(
68
+ AbstractCommandImpl[AspirateWhileTrackingParams, _ExecuteReturn]
69
+ ):
70
+ """AspirateWhileTracking command implementation."""
71
+
72
+ def __init__(
73
+ self,
74
+ pipetting: PipettingHandler,
75
+ state_view: StateView,
76
+ hardware_api: HardwareControlAPI,
77
+ command_note_adder: CommandNoteAdder,
78
+ model_utils: ModelUtils,
79
+ gantry_mover: GantryMover,
80
+ movement: MovementHandler,
81
+ **kwargs: object,
82
+ ) -> None:
83
+ self._pipetting = pipetting
84
+ self._state_view = state_view
85
+ self._hardware_api = hardware_api
86
+ self._command_note_adder = command_note_adder
87
+ self._model_utils = model_utils
88
+ self._gantry_mover = gantry_mover
89
+ self._movement = movement
90
+
91
+ async def execute(self, params: AspirateWhileTrackingParams) -> _ExecuteReturn:
92
+ """Move to and aspirate from the requested well.
93
+
94
+ Raises:
95
+ TipNotAttachedError: if no tip is attached to the pipette.
96
+ PipetteNotReadyToAspirateError: pipette plunger is not ready.
97
+ """
98
+ ready_to_aspirate = self._state_view.pipettes.get_ready_to_aspirate(
99
+ pipette_id=params.pipetteId
100
+ )
101
+ if not ready_to_aspirate:
102
+ raise PipetteNotReadyToAspirateError(
103
+ "Pipette cannot aspirate while tracking because of a previous blow out."
104
+ " The first aspirate following a blow-out must be from a specific well"
105
+ " so the plunger can be reset in a known safe position."
106
+ )
107
+
108
+ current_position = await self._gantry_mover.get_position(params.pipetteId)
109
+ current_location = self._state_view.pipettes.get_current_location()
110
+
111
+ state_update = StateUpdate()
112
+ current_well = CurrentWell(
113
+ pipette_id=params.pipetteId,
114
+ labware_id=params.labwareId,
115
+ well_name=params.wellName,
116
+ )
117
+ move_result = await move_to_well(
118
+ movement=self._movement,
119
+ model_utils=self._model_utils,
120
+ pipette_id=params.pipetteId,
121
+ labware_id=params.labwareId,
122
+ well_name=params.wellName,
123
+ well_location=params.wellLocation,
124
+ current_well=current_well,
125
+ operation_volume=-params.volume,
126
+ )
127
+ state_update.append(move_result.state_update)
128
+ if isinstance(move_result, DefinedErrorData):
129
+ return DefinedErrorData(
130
+ public=move_result.public, state_update=state_update
131
+ )
132
+
133
+ aspirate_result = await aspirate_while_tracking(
134
+ pipette_id=params.pipetteId,
135
+ labware_id=params.labwareId,
136
+ well_name=params.wellName,
137
+ volume=params.volume,
138
+ flow_rate=params.flowRate,
139
+ location_if_error={
140
+ "retryLocation": (
141
+ current_position.x,
142
+ current_position.y,
143
+ current_position.z,
144
+ )
145
+ },
146
+ command_note_adder=self._command_note_adder,
147
+ pipetting=self._pipetting,
148
+ model_utils=self._model_utils,
149
+ )
150
+ position_after_aspirate = await self._gantry_mover.get_position(
151
+ params.pipetteId
152
+ )
153
+ result_deck_point = DeckPoint.model_construct(
154
+ x=position_after_aspirate.x,
155
+ y=position_after_aspirate.y,
156
+ z=position_after_aspirate.z,
157
+ )
158
+ if isinstance(aspirate_result, DefinedErrorData):
159
+ if (
160
+ isinstance(current_location, CurrentWell)
161
+ and current_location.pipette_id == params.pipetteId
162
+ ):
163
+ return DefinedErrorData(
164
+ public=aspirate_result.public,
165
+ state_update=aspirate_result.state_update.set_liquid_operated(
166
+ labware_id=current_location.labware_id,
167
+ well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
168
+ current_location.labware_id,
169
+ current_location.well_name,
170
+ params.pipetteId,
171
+ ),
172
+ volume_added=CLEAR,
173
+ ),
174
+ state_update_if_false_positive=aspirate_result.state_update_if_false_positive,
175
+ )
176
+ else:
177
+ return aspirate_result
178
+ else:
179
+ if (
180
+ isinstance(current_location, CurrentWell)
181
+ and current_location.pipette_id == params.pipetteId
182
+ ):
183
+ return SuccessData(
184
+ public=AspirateWhileTrackingResult(
185
+ volume=aspirate_result.public.volume,
186
+ position=result_deck_point,
187
+ ),
188
+ state_update=aspirate_result.state_update.set_liquid_operated(
189
+ labware_id=current_location.labware_id,
190
+ well_names=self._state_view.geometry.get_wells_covered_by_pipette_with_active_well(
191
+ current_location.labware_id,
192
+ current_location.well_name,
193
+ params.pipetteId,
194
+ ),
195
+ volume_added=-aspirate_result.public.volume
196
+ * self._state_view.geometry.get_nozzles_per_well(
197
+ current_location.labware_id,
198
+ current_location.well_name,
199
+ params.pipetteId,
200
+ ),
201
+ ),
202
+ )
203
+ else:
204
+ return SuccessData(
205
+ public=AspirateWhileTrackingResult(
206
+ volume=aspirate_result.public.volume,
207
+ position=result_deck_point,
208
+ ),
209
+ state_update=aspirate_result.state_update,
210
+ )
211
+
212
+
213
+ class AspirateWhileTracking(
214
+ BaseCommand[
215
+ AspirateWhileTrackingParams,
216
+ AspirateWhileTrackingResult,
217
+ OverpressureError | StallOrCollisionError,
218
+ ]
219
+ ):
220
+ """AspirateWhileTracking command model."""
221
+
222
+ commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking"
223
+ params: AspirateWhileTrackingParams
224
+ result: Optional[AspirateWhileTrackingResult] = None
225
+
226
+ _ImplementationCls: Type[
227
+ AspirateWhileTrackingImplementation
228
+ ] = AspirateWhileTrackingImplementation
229
+
230
+
231
+ class AspirateWhileTrackingCreate(BaseCommandCreate[AspirateWhileTrackingParams]):
232
+ """Create aspirateWhileTracking command request model."""
233
+
234
+ commandType: AspirateWhileTrackingCommandType = "aspirateWhileTracking"
235
+ params: AspirateWhileTrackingParams
236
+
237
+ _CommandCls: Type[AspirateWhileTracking] = AspirateWhileTracking
@@ -115,6 +115,8 @@ class BlowOutImplementation(AbstractCommandImpl[BlowOutParams, _ExecuteReturn]):
115
115
  public=BlowOutResult(position=move_result.public.position),
116
116
  state_update=StateUpdate.reduce(
117
117
  move_result.state_update, blow_out_result.state_update
118
+ ).set_pipette_ready_to_aspirate(
119
+ pipette_id=params.pipetteId, ready_to_aspirate=False
118
120
  ),
119
121
  )
120
122