opentrons 8.3.2a0__py2.py3-none-any.whl → 8.4.0__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.

Potentially problematic release.


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

Files changed (196) 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 +102 -5
  39. opentrons/legacy_commands/helpers.py +74 -1
  40. opentrons/legacy_commands/types.py +33 -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 +1356 -107
  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/pipette_movement_conflict.py +6 -14
  52. opentrons/protocol_api/core/engine/protocol.py +253 -11
  53. opentrons/protocol_api/core/engine/stringify.py +19 -8
  54. opentrons/protocol_api/core/engine/transfer_components_executor.py +858 -0
  55. opentrons/protocol_api/core/engine/well.py +73 -5
  56. opentrons/protocol_api/core/instrument.py +71 -21
  57. opentrons/protocol_api/core/labware.py +6 -2
  58. opentrons/protocol_api/core/legacy/labware_offset_provider.py +7 -3
  59. opentrons/protocol_api/core/legacy/legacy_instrument_core.py +76 -49
  60. opentrons/protocol_api/core/legacy/legacy_labware_core.py +8 -4
  61. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +36 -0
  62. opentrons/protocol_api/core/legacy/legacy_well_core.py +27 -2
  63. opentrons/protocol_api/core/legacy/load_info.py +4 -12
  64. opentrons/protocol_api/core/legacy/module_geometry.py +6 -1
  65. opentrons/protocol_api/core/legacy/well_geometry.py +3 -3
  66. opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +73 -23
  67. opentrons/protocol_api/core/module.py +43 -0
  68. opentrons/protocol_api/core/protocol.py +33 -0
  69. opentrons/protocol_api/core/well.py +23 -2
  70. opentrons/protocol_api/instrument_context.py +454 -150
  71. opentrons/protocol_api/labware.py +98 -50
  72. opentrons/protocol_api/module_contexts.py +140 -0
  73. opentrons/protocol_api/protocol_context.py +163 -19
  74. opentrons/protocol_api/validation.py +51 -41
  75. opentrons/protocol_engine/__init__.py +21 -2
  76. opentrons/protocol_engine/actions/actions.py +5 -5
  77. opentrons/protocol_engine/clients/sync_client.py +6 -0
  78. opentrons/protocol_engine/commands/__init__.py +66 -36
  79. opentrons/protocol_engine/commands/absorbance_reader/__init__.py +0 -1
  80. opentrons/protocol_engine/commands/air_gap_in_place.py +3 -2
  81. opentrons/protocol_engine/commands/aspirate.py +6 -2
  82. opentrons/protocol_engine/commands/aspirate_in_place.py +3 -1
  83. opentrons/protocol_engine/commands/aspirate_while_tracking.py +210 -0
  84. opentrons/protocol_engine/commands/blow_out.py +2 -0
  85. opentrons/protocol_engine/commands/blow_out_in_place.py +4 -1
  86. opentrons/protocol_engine/commands/command_unions.py +102 -33
  87. opentrons/protocol_engine/commands/configure_for_volume.py +3 -0
  88. opentrons/protocol_engine/commands/dispense.py +3 -1
  89. opentrons/protocol_engine/commands/dispense_in_place.py +3 -0
  90. opentrons/protocol_engine/commands/dispense_while_tracking.py +204 -0
  91. opentrons/protocol_engine/commands/drop_tip.py +23 -1
  92. opentrons/protocol_engine/commands/flex_stacker/__init__.py +106 -0
  93. opentrons/protocol_engine/commands/flex_stacker/close_latch.py +72 -0
  94. opentrons/protocol_engine/commands/flex_stacker/common.py +15 -0
  95. opentrons/protocol_engine/commands/flex_stacker/empty.py +161 -0
  96. opentrons/protocol_engine/commands/flex_stacker/fill.py +164 -0
  97. opentrons/protocol_engine/commands/flex_stacker/open_latch.py +70 -0
  98. opentrons/protocol_engine/commands/flex_stacker/prepare_shuttle.py +112 -0
  99. opentrons/protocol_engine/commands/flex_stacker/retrieve.py +394 -0
  100. opentrons/protocol_engine/commands/flex_stacker/set_stored_labware.py +190 -0
  101. opentrons/protocol_engine/commands/flex_stacker/store.py +291 -0
  102. opentrons/protocol_engine/commands/generate_command_schema.py +31 -2
  103. opentrons/protocol_engine/commands/labware_handling_common.py +29 -0
  104. opentrons/protocol_engine/commands/liquid_probe.py +27 -13
  105. opentrons/protocol_engine/commands/load_labware.py +42 -39
  106. opentrons/protocol_engine/commands/load_lid.py +21 -13
  107. opentrons/protocol_engine/commands/load_lid_stack.py +130 -47
  108. opentrons/protocol_engine/commands/load_module.py +18 -17
  109. opentrons/protocol_engine/commands/load_pipette.py +3 -0
  110. opentrons/protocol_engine/commands/move_labware.py +139 -20
  111. opentrons/protocol_engine/commands/move_to_well.py +5 -11
  112. opentrons/protocol_engine/commands/pick_up_tip.py +5 -2
  113. opentrons/protocol_engine/commands/pipetting_common.py +159 -8
  114. opentrons/protocol_engine/commands/prepare_to_aspirate.py +15 -5
  115. opentrons/protocol_engine/commands/{evotip_dispense.py → pressure_dispense.py} +33 -34
  116. opentrons/protocol_engine/commands/reload_labware.py +6 -19
  117. opentrons/protocol_engine/commands/{evotip_seal_pipette.py → seal_pipette_to_tip.py} +97 -76
  118. opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +3 -1
  119. opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +6 -1
  120. opentrons/protocol_engine/commands/{evotip_unseal_pipette.py → unseal_pipette_from_tip.py} +31 -40
  121. opentrons/protocol_engine/errors/__init__.py +10 -0
  122. opentrons/protocol_engine/errors/exceptions.py +62 -0
  123. opentrons/protocol_engine/execution/equipment.py +123 -106
  124. opentrons/protocol_engine/execution/labware_movement.py +8 -6
  125. opentrons/protocol_engine/execution/pipetting.py +235 -25
  126. opentrons/protocol_engine/execution/tip_handler.py +82 -32
  127. opentrons/protocol_engine/labware_offset_standardization.py +194 -0
  128. opentrons/protocol_engine/protocol_engine.py +22 -13
  129. opentrons/protocol_engine/resources/deck_configuration_provider.py +98 -2
  130. opentrons/protocol_engine/resources/deck_data_provider.py +1 -1
  131. opentrons/protocol_engine/resources/labware_data_provider.py +32 -12
  132. opentrons/protocol_engine/resources/labware_validation.py +7 -5
  133. opentrons/protocol_engine/slot_standardization.py +11 -23
  134. opentrons/protocol_engine/state/addressable_areas.py +84 -46
  135. opentrons/protocol_engine/state/frustum_helpers.py +36 -14
  136. opentrons/protocol_engine/state/geometry.py +892 -227
  137. opentrons/protocol_engine/state/labware.py +252 -55
  138. opentrons/protocol_engine/state/module_substates/__init__.py +4 -0
  139. opentrons/protocol_engine/state/module_substates/flex_stacker_substate.py +68 -0
  140. opentrons/protocol_engine/state/module_substates/heater_shaker_module_substate.py +22 -0
  141. opentrons/protocol_engine/state/module_substates/temperature_module_substate.py +13 -0
  142. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +20 -0
  143. opentrons/protocol_engine/state/modules.py +210 -67
  144. opentrons/protocol_engine/state/pipettes.py +54 -0
  145. opentrons/protocol_engine/state/state.py +1 -1
  146. opentrons/protocol_engine/state/tips.py +14 -0
  147. opentrons/protocol_engine/state/update_types.py +180 -25
  148. opentrons/protocol_engine/state/wells.py +55 -9
  149. opentrons/protocol_engine/types/__init__.py +300 -0
  150. opentrons/protocol_engine/types/automatic_tip_selection.py +39 -0
  151. opentrons/protocol_engine/types/command_annotations.py +53 -0
  152. opentrons/protocol_engine/types/deck_configuration.py +72 -0
  153. opentrons/protocol_engine/types/execution.py +96 -0
  154. opentrons/protocol_engine/types/hardware_passthrough.py +25 -0
  155. opentrons/protocol_engine/types/instrument.py +47 -0
  156. opentrons/protocol_engine/types/instrument_sensors.py +47 -0
  157. opentrons/protocol_engine/types/labware.py +111 -0
  158. opentrons/protocol_engine/types/labware_movement.py +22 -0
  159. opentrons/protocol_engine/types/labware_offset_location.py +111 -0
  160. opentrons/protocol_engine/types/labware_offset_vector.py +33 -0
  161. opentrons/protocol_engine/types/liquid.py +40 -0
  162. opentrons/protocol_engine/types/liquid_class.py +59 -0
  163. opentrons/protocol_engine/types/liquid_handling.py +13 -0
  164. opentrons/protocol_engine/types/liquid_level_detection.py +131 -0
  165. opentrons/protocol_engine/types/location.py +194 -0
  166. opentrons/protocol_engine/types/module.py +301 -0
  167. opentrons/protocol_engine/types/partial_tip_configuration.py +76 -0
  168. opentrons/protocol_engine/types/run_time_parameters.py +133 -0
  169. opentrons/protocol_engine/types/tip.py +18 -0
  170. opentrons/protocol_engine/types/util.py +21 -0
  171. opentrons/protocol_engine/types/well_position.py +124 -0
  172. opentrons/protocol_reader/extract_labware_definitions.py +7 -3
  173. opentrons/protocol_reader/file_format_validator.py +5 -3
  174. opentrons/protocol_runner/json_translator.py +4 -2
  175. opentrons/protocol_runner/legacy_command_mapper.py +6 -2
  176. opentrons/protocol_runner/run_orchestrator.py +4 -1
  177. opentrons/protocols/advanced_control/transfers/common.py +48 -1
  178. opentrons/protocols/advanced_control/transfers/transfer_liquid_utils.py +204 -0
  179. opentrons/protocols/api_support/definitions.py +1 -1
  180. opentrons/protocols/api_support/instrument.py +16 -3
  181. opentrons/protocols/labware.py +27 -23
  182. opentrons/protocols/models/__init__.py +0 -21
  183. opentrons/simulate.py +4 -2
  184. opentrons/types.py +20 -7
  185. opentrons/util/logging_config.py +94 -25
  186. opentrons/util/logging_queue_handler.py +61 -0
  187. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/METADATA +4 -4
  188. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/RECORD +192 -151
  189. opentrons/calibration_storage/ot2/models/defaults.py +0 -0
  190. opentrons/calibration_storage/ot3/models/defaults.py +0 -0
  191. opentrons/protocol_api/core/legacy/legacy_robot_core.py +0 -0
  192. opentrons/protocol_engine/types.py +0 -1311
  193. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/LICENSE +0 -0
  194. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/WHEEL +0 -0
  195. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/entry_points.txt +0 -0
  196. {opentrons-8.3.2a0.dist-info → opentrons-8.4.0.dist-info}/top_level.txt +0 -0
@@ -209,6 +209,10 @@ class LegacyProtocolCore(
209
209
  bundled_defs=self._bundled_labware,
210
210
  extra_defs=self._extra_labware,
211
211
  )
212
+ # For type checking. This should always pass because
213
+ # opentrons.protocol_api.core.legacy should only load labware with schema 2.
214
+ assert labware_def["schemaVersion"] == 2
215
+
212
216
  labware_core = LegacyLabwareCore(
213
217
  definition=labware_def,
214
218
  parent=parent,
@@ -307,6 +311,25 @@ class LegacyProtocolCore(
307
311
  """Move labware to new location."""
308
312
  raise APIVersionError(api_element="Labware movement")
309
313
 
314
+ def move_lid(
315
+ self,
316
+ source_location: Union[DeckSlotName, StagingSlotName, LegacyLabwareCore],
317
+ new_location: Union[
318
+ DeckSlotName,
319
+ StagingSlotName,
320
+ LegacyLabwareCore,
321
+ OffDeckType,
322
+ WasteChute,
323
+ TrashBin,
324
+ ],
325
+ use_gripper: bool,
326
+ pause_for_manual_move: bool,
327
+ pick_up_offset: Optional[Tuple[float, float, float]],
328
+ drop_offset: Optional[Tuple[float, float, float]],
329
+ ) -> LegacyLabwareCore | None:
330
+ """Move lid to new location."""
331
+ raise APIVersionError(api_element="Lid movement")
332
+
310
333
  def load_module(
311
334
  self,
312
335
  model: ModuleModel,
@@ -505,6 +528,19 @@ class LegacyProtocolCore(
505
528
  """Load a Stack of Lids to a given location, creating a Lid Stack."""
506
529
  raise APIVersionError(api_element="Lid stack")
507
530
 
531
+ def load_labware_to_flex_stacker_hopper(
532
+ self,
533
+ module_core: legacy_module_core.LegacyModuleCore,
534
+ load_name: str,
535
+ quantity: int,
536
+ label: Optional[str],
537
+ namespace: Optional[str],
538
+ version: Optional[int],
539
+ lid: Optional[str],
540
+ ) -> None:
541
+ """Load labware to a Flex stacker hopper."""
542
+ raise APIVersionError(api_element="Flex stacker")
543
+
508
544
  def get_module_cores(self) -> List[legacy_module_core.LegacyModuleCore]:
509
545
  """Get loaded module cores."""
510
546
  return self._module_cores
@@ -1,11 +1,16 @@
1
1
  """Legacy Well core implementation."""
2
- from typing import Optional
2
+ from typing import Optional, Union
3
3
 
4
4
  from opentrons_shared_data.labware.constants import WELL_NAME_PATTERN
5
5
 
6
6
  from opentrons.protocols.api_support.util import APIVersionError
7
7
 
8
- from opentrons.types import Point
8
+ from opentrons.types import Point, Mount
9
+
10
+ from opentrons.protocol_engine.types.liquid_level_detection import (
11
+ SimulatedProbeResult,
12
+ LiquidTrackingType,
13
+ )
9
14
 
10
15
  from .well_geometry import WellGeometry
11
16
  from ..well import AbstractWellCore
@@ -106,6 +111,10 @@ class LegacyWellCore(AbstractWellCore):
106
111
  """Get the coordinate of the well's center."""
107
112
  return self._geometry.center()
108
113
 
114
+ def get_meniscus(self) -> Union[Point, SimulatedProbeResult]:
115
+ """Get the coordinate of the well's center."""
116
+ raise APIVersionError(api_element="Getting a meniscus")
117
+
109
118
  def load_liquid(
110
119
  self,
111
120
  liquid: Liquid,
@@ -118,6 +127,22 @@ class LegacyWellCore(AbstractWellCore):
118
127
  """Gets point in deck coordinates based on percentage of the radius of each axis."""
119
128
  return self._geometry.from_center_cartesian(x, y, z)
120
129
 
130
+ def estimate_liquid_height_after_pipetting(
131
+ self,
132
+ mount: Mount | str,
133
+ operation_volume: float,
134
+ ) -> LiquidTrackingType:
135
+ """Estimate what the liquid height will be after pipetting, without raising an error."""
136
+ return 0.0
137
+
138
+ def current_liquid_height(self) -> LiquidTrackingType:
139
+ """Get the current liquid height."""
140
+ return 0.0
141
+
142
+ def get_liquid_volume(self) -> LiquidTrackingType:
143
+ """Get the current well volume."""
144
+ return 0.0
145
+
121
146
  # TODO(mc, 2022-10-28): is this used and/or necessary?
122
147
  def __repr__(self) -> str:
123
148
  """Use the well's display name as its repr."""
@@ -7,7 +7,7 @@ It's only for internal Opentrons use.
7
7
 
8
8
  from dataclasses import dataclass
9
9
  from typing import Optional, Union
10
- from opentrons_shared_data.labware.types import LabwareDefinition
10
+ from opentrons_shared_data.labware.types import LabwareDefinition2
11
11
 
12
12
  from opentrons.hardware_control.dev_types import PipetteDict
13
13
  from opentrons.hardware_control.modules.types import ModuleModel
@@ -18,13 +18,11 @@ from opentrons.types import Mount, DeckSlotName
18
18
  class LabwareLoadInfo:
19
19
  """Information about a successful labware load.
20
20
 
21
- :meta private:
22
-
23
21
  This is a separate class from the main user-facing `Labware` class
24
22
  because this is easier to construct in unit tests.
25
23
  """
26
24
 
27
- labware_definition: LabwareDefinition
25
+ labware_definition: LabwareDefinition2
28
26
 
29
27
  # todo(mm, 2021-10-11): Namespace, load name, and version can be derived from the
30
28
  # definition. Should they be removed from here?
@@ -47,10 +45,7 @@ class LabwareLoadInfo:
47
45
 
48
46
  @dataclass(frozen=True)
49
47
  class InstrumentLoadInfo:
50
- """Like `LabwareLoadInfo`, but for instruments (pipettes).
51
-
52
- :meta private:
53
- """
48
+ """Like `LabwareLoadInfo`, but for instruments (pipettes)."""
54
49
 
55
50
  instrument_load_name: str
56
51
  mount: Mount
@@ -59,10 +54,7 @@ class InstrumentLoadInfo:
59
54
 
60
55
  @dataclass(frozen=True)
61
56
  class ModuleLoadInfo:
62
- """Like `LabwareLoadInfo`, but for hardware modules.
63
-
64
- :meta private:
65
- """
57
+ """Like `LabwareLoadInfo`, but for hardware modules."""
66
58
 
67
59
  requested_model: ModuleModel
68
60
  loaded_model: ModuleModel
@@ -273,8 +273,13 @@ class ThermocyclerGeometry(ModuleGeometry):
273
273
  LegacyLabwareCore,
274
274
  )
275
275
 
276
- # Block first three columns from being accessed
277
276
  definition = labware._core.get_definition()
277
+
278
+ # For type checking. This should always pass because
279
+ # opentrons.protocol_api.core.legacy should only load labware with schema 2.
280
+ assert definition["schemaVersion"] == 2
281
+
282
+ # Block first three columns from being accessed
278
283
  definition["ordering"] = definition["ordering"][2::]
279
284
  return Labware(
280
285
  core=LegacyLabwareCore(definition, super().location),
@@ -4,9 +4,9 @@ from typing import Optional, cast, TYPE_CHECKING
4
4
 
5
5
  from opentrons.types import Point
6
6
  from opentrons_shared_data.labware.types import (
7
- WellDefinition,
8
- CircularWellDefinition,
9
- RectangularWellDefinition,
7
+ WellDefinition2 as WellDefinition,
8
+ CircularWellDefinition2 as CircularWellDefinition,
9
+ RectangularWellDefinition2 as RectangularWellDefinition,
10
10
  )
11
11
 
12
12
  if TYPE_CHECKING:
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING, Optional, Union, List
4
+ from typing import TYPE_CHECKING, Optional, Union, List, Tuple, Literal
5
5
 
6
6
  from opentrons import types
7
7
  from opentrons.hardware_control.dev_types import PipetteDict
@@ -23,6 +23,9 @@ from opentrons_shared_data.errors.exceptions import (
23
23
  UnexpectedTipAttachError,
24
24
  )
25
25
 
26
+ from opentrons.protocol_engine.types import LiquidTrackingType
27
+
28
+ from ..legacy.legacy_labware_core import LegacyLabwareCore
26
29
  from ...disposal_locations import TrashBin, WasteChute
27
30
  from opentrons.protocol_api._nozzle_layout import NozzleLayout
28
31
  from opentrons.protocol_api._liquid import LiquidClass
@@ -42,7 +45,9 @@ _PRE_2_2_TIP_DROP_HEIGHT_MM = 10
42
45
  """In PAPIv2.1 and below, tips are always dropped 10 mm from the bottom of the well."""
43
46
 
44
47
 
45
- class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
48
+ class LegacyInstrumentCoreSimulator(
49
+ AbstractInstrument[LegacyWellCore, LegacyLabwareCore]
50
+ ):
46
51
  """A simulation of an instrument context."""
47
52
 
48
53
  def __init__(
@@ -84,7 +89,9 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
84
89
  def set_default_speed(self, speed: float) -> None:
85
90
  self._default_speed = speed
86
91
 
87
- def air_gap_in_place(self, volume: float, flow_rate: float) -> None:
92
+ def air_gap_in_place(
93
+ self, volume: float, flow_rate: float, correction_volume: Optional[float] = None
94
+ ) -> None:
88
95
  assert False, "Air gap tracking only available in API version 2.22 and later"
89
96
 
90
97
  def aspirate(
@@ -95,7 +102,8 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
95
102
  rate: float,
96
103
  flow_rate: float,
97
104
  in_place: bool,
98
- is_meniscus: Optional[bool] = None,
105
+ meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
106
+ correction_volume: Optional[float] = None,
99
107
  ) -> None:
100
108
  if self.get_current_volume() == 0:
101
109
  # Make sure we're at the top of the labware and clear of any
@@ -137,7 +145,8 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
137
145
  flow_rate: float,
138
146
  in_place: bool,
139
147
  push_out: Optional[float],
140
- is_meniscus: Optional[bool] = None,
148
+ meniscus_tracking: Optional[types.MeniscusTrackingTarget] = None,
149
+ correction_volume: Optional[float] = None,
141
150
  ) -> None:
142
151
  if isinstance(location, (TrashBin, WasteChute)):
143
152
  raise APIVersionError(
@@ -177,7 +186,10 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
177
186
  radius: float,
178
187
  z_offset: float,
179
188
  speed: float,
189
+ mm_from_edge: Optional[float] = None,
180
190
  ) -> None:
191
+ if mm_from_edge is not None:
192
+ raise APIVersionError(api_element="mm_from_edge argument")
181
193
  self.move_to(location)
182
194
 
183
195
  def pick_up_tip(
@@ -286,7 +298,7 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
286
298
 
287
299
  def resin_tip_unseal(
288
300
  self,
289
- location: types.Location,
301
+ location: types.Location | None,
290
302
  well_core: WellCore,
291
303
  ) -> None:
292
304
  raise APIVersionError(api_element="Unsealing resin tips.")
@@ -313,6 +325,7 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
313
325
  force_direct: bool = False,
314
326
  minimum_z_height: Optional[float] = None,
315
327
  speed: Optional[float] = None,
328
+ check_for_movement_conflicts: bool = False, # Not used in this implementation
316
329
  ) -> None:
317
330
  """Simulation of only the motion planning portion of move_to."""
318
331
  if isinstance(location, (TrashBin, WasteChute)):
@@ -365,6 +378,9 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
365
378
  def get_current_volume(self) -> float:
366
379
  return self._pipette_dict["current_volume"]
367
380
 
381
+ def get_has_clean_tip(self) -> bool:
382
+ return False
383
+
368
384
  def get_available_volume(self) -> float:
369
385
  return self._pipette_dict["available_volume"]
370
386
 
@@ -498,29 +514,51 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
498
514
  """This will never be called because it was added in API 2.15."""
499
515
  pass
500
516
 
501
- def load_liquid_class(
517
+ def transfer_with_liquid_class(
502
518
  self,
503
519
  liquid_class: LiquidClass,
504
- pipette_load_name: str,
505
- tiprack_uri: str,
506
- ) -> str:
507
- """This will never be called because it was added in .."""
508
- # TODO(spp, 2024-11-20): update the docstring and error to include API version
509
- assert False, "load_liquid_class is not supported in legacy context"
510
-
511
- def transfer_liquid(
512
- self,
513
- liquid_class_id: str,
514
520
  volume: float,
515
- source: List[LegacyWellCore],
516
- dest: List[LegacyWellCore],
521
+ source: List[Tuple[types.Location, LegacyWellCore]],
522
+ dest: List[Tuple[types.Location, LegacyWellCore]],
517
523
  new_tip: TransferTipPolicyV2,
518
- trash_location: Union[LegacyWellCore, types.Location, TrashBin, WasteChute],
524
+ tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
525
+ starting_tip: Optional[LegacyWellCore],
526
+ trash_location: Union[types.Location, TrashBin, WasteChute],
527
+ return_tip: bool,
519
528
  ) -> None:
520
- """Transfer a liquid from source to dest according to liquid class properties."""
521
- # TODO(spp, 2024-11-20): update the docstring and error to include API version
529
+ """This will never be called because it was added in API 2.23."""
522
530
  assert False, "transfer_liquid is not supported in legacy context"
523
531
 
532
+ def distribute_with_liquid_class(
533
+ self,
534
+ liquid_class: LiquidClass,
535
+ volume: float,
536
+ source: Tuple[types.Location, LegacyWellCore],
537
+ dest: List[Tuple[types.Location, LegacyWellCore]],
538
+ new_tip: Literal[TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE],
539
+ tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
540
+ starting_tip: Optional[LegacyWellCore],
541
+ trash_location: Union[types.Location, TrashBin, WasteChute],
542
+ return_tip: bool,
543
+ ) -> None:
544
+ """This will never be called because it was added in API 2.23."""
545
+ assert False, "distribute_liquid is not supported in legacy context"
546
+
547
+ def consolidate_with_liquid_class(
548
+ self,
549
+ liquid_class: LiquidClass,
550
+ volume: float,
551
+ source: List[Tuple[types.Location, LegacyWellCore]],
552
+ dest: Tuple[types.Location, LegacyWellCore],
553
+ new_tip: Literal[TransferTipPolicyV2.NEVER, TransferTipPolicyV2.ONCE],
554
+ tip_racks: List[Tuple[types.Location, LegacyLabwareCore]],
555
+ starting_tip: Optional[LegacyWellCore],
556
+ trash_location: Union[types.Location, TrashBin, WasteChute],
557
+ return_tip: bool,
558
+ ) -> None:
559
+ """This will never be called because it was added in API 2.23."""
560
+ assert False, "consolidate_liquid is not supported in legacy context"
561
+
524
562
  def get_active_channels(self) -> int:
525
563
  """This will never be called because it was added in API 2.16."""
526
564
  assert False, "get_active_channels only supported in API 2.16 & later"
@@ -549,7 +587,7 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
549
587
 
550
588
  def liquid_probe_without_recovery(
551
589
  self, well_core: WellCore, loc: types.Location
552
- ) -> float:
590
+ ) -> LiquidTrackingType:
553
591
  """This will never be called because it was added in API 2.20."""
554
592
  assert False, "liquid_probe_without_recovery only supported in API 2.20 & later"
555
593
 
@@ -559,3 +597,15 @@ class LegacyInstrumentCoreSimulator(AbstractInstrument[LegacyWellCore]):
559
597
  def nozzle_configuration_valid_for_lld(self) -> bool:
560
598
  """Check if the nozzle configuration currently supports LLD."""
561
599
  return False
600
+
601
+ def get_minimum_liquid_sense_height(self) -> float:
602
+ return 0.0
603
+
604
+ def estimate_liquid_height(
605
+ self,
606
+ well_core: LegacyWellCore,
607
+ starting_liquid_height: float,
608
+ operation_volume: float,
609
+ ) -> float:
610
+ """This will never be called because it was added in API 2.21."""
611
+ assert False, "estimate_liquid_height only supported in API 2.21 & later"
@@ -1,4 +1,5 @@
1
1
  """Core module control interfaces."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from abc import ABC, abstractmethod
@@ -379,3 +380,45 @@ class AbstractAbsorbanceReaderCore(AbstractModuleCore):
379
380
  @abstractmethod
380
381
  def is_lid_on(self) -> bool:
381
382
  """Return True if the Absorbance Reader's lid is currently closed."""
383
+
384
+
385
+ class AbstractFlexStackerCore(AbstractModuleCore):
386
+ """Core control interface for an attached Flex Stacker."""
387
+
388
+ MODULE_TYPE: ClassVar = ModuleType.FLEX_STACKER
389
+
390
+ @abstractmethod
391
+ def get_serial_number(self) -> str:
392
+ """Get the module's unique hardware serial number."""
393
+
394
+ @abstractmethod
395
+ def retrieve(self) -> None:
396
+ """Release a labware from the hopper to the staging slot."""
397
+
398
+ @abstractmethod
399
+ def store(self) -> None:
400
+ """Store a labware in the stacker hopper."""
401
+
402
+ @abstractmethod
403
+ def fill(self, message: str, count: int | None) -> None:
404
+ """Pause the protocol to allow for filling the stacker."""
405
+
406
+ @abstractmethod
407
+ def empty(self, message: str) -> None:
408
+ """Pause the protocol to allow for emptying the stacker."""
409
+
410
+ @abstractmethod
411
+ def set_stored_labware(
412
+ self,
413
+ main_load_name: str,
414
+ main_namespace: str | None,
415
+ main_version: int | None,
416
+ lid_load_name: str | None,
417
+ lid_namespace: str | None,
418
+ lid_version: int | None,
419
+ adapter_load_name: str | None,
420
+ adapter_namespace: str | None,
421
+ adapter_version: int | None,
422
+ count: int | None,
423
+ ) -> None:
424
+ """Configure the kind of labware that the stacker stores."""
@@ -111,6 +111,20 @@ class AbstractProtocol(
111
111
  """Load an individual lid labware using its identifying parameters. Must be loaded on a labware."""
112
112
  ...
113
113
 
114
+ @abstractmethod
115
+ def load_labware_to_flex_stacker_hopper(
116
+ self,
117
+ module_core: ModuleCoreType,
118
+ load_name: str,
119
+ quantity: int,
120
+ label: Optional[str],
121
+ namespace: Optional[str],
122
+ version: Optional[int],
123
+ lid: Optional[str],
124
+ ) -> None:
125
+ """Load one or more labware with or without a lid to the flex stacker hopper."""
126
+ ...
127
+
114
128
  @abstractmethod
115
129
  def move_labware(
116
130
  self,
@@ -131,6 +145,25 @@ class AbstractProtocol(
131
145
  ) -> None:
132
146
  ...
133
147
 
148
+ @abstractmethod
149
+ def move_lid(
150
+ self,
151
+ source_location: Union[DeckSlotName, StagingSlotName, LabwareCoreType],
152
+ new_location: Union[
153
+ DeckSlotName,
154
+ StagingSlotName,
155
+ LabwareCoreType,
156
+ OffDeckType,
157
+ WasteChute,
158
+ TrashBin,
159
+ ],
160
+ use_gripper: bool,
161
+ pause_for_manual_move: bool,
162
+ pick_up_offset: Optional[Tuple[float, float, float]],
163
+ drop_offset: Optional[Tuple[float, float, float]],
164
+ ) -> LabwareCoreType | None:
165
+ ...
166
+
134
167
  @abstractmethod
135
168
  def load_module(
136
169
  self,
@@ -1,9 +1,10 @@
1
1
  """Abstract interface for Well core implementations."""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
- from typing import TypeVar, Optional
4
+ from typing import TypeVar, Optional, Union
5
5
 
6
- from opentrons.types import Point
6
+ from opentrons.types import Point, Mount
7
+ from opentrons.protocol_engine.types import LiquidTrackingType
7
8
 
8
9
  from .._liquid import Liquid
9
10
 
@@ -71,6 +72,10 @@ class AbstractWellCore(ABC):
71
72
  def get_center(self) -> Point:
72
73
  """Get the coordinate of the well's center."""
73
74
 
75
+ @abstractmethod
76
+ def get_meniscus(self) -> Union[Point, LiquidTrackingType]:
77
+ """Get the coordinate of the well's meniscus."""
78
+
74
79
  @abstractmethod
75
80
  def load_liquid(
76
81
  self,
@@ -83,5 +88,21 @@ class AbstractWellCore(ABC):
83
88
  def from_center_cartesian(self, x: float, y: float, z: float) -> Point:
84
89
  """Gets point in deck coordinates based on percentage of the radius of each axis."""
85
90
 
91
+ @abstractmethod
92
+ def estimate_liquid_height_after_pipetting(
93
+ self,
94
+ mount: Mount | str,
95
+ operation_volume: float,
96
+ ) -> LiquidTrackingType:
97
+ """Estimate what the liquid height will be after pipetting, without raising an error."""
98
+
99
+ @abstractmethod
100
+ def current_liquid_height(self) -> LiquidTrackingType:
101
+ """Get the current liquid height."""
102
+
103
+ @abstractmethod
104
+ def get_liquid_volume(self) -> LiquidTrackingType:
105
+ """Get the current volume within a well."""
106
+
86
107
 
87
108
  WellCoreType = TypeVar("WellCoreType", bound=AbstractWellCore)