opentrons 8.7.0a7__py3-none-any.whl → 8.7.0a9__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 (147) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/drivers/asyncio/communication/serial_connection.py +55 -129
  3. opentrons/drivers/flex_stacker/driver.py +6 -1
  4. opentrons/drivers/heater_shaker/abstract.py +0 -5
  5. opentrons/drivers/heater_shaker/driver.py +0 -10
  6. opentrons/drivers/heater_shaker/simulator.py +0 -4
  7. opentrons/drivers/thermocycler/abstract.py +0 -6
  8. opentrons/drivers/thermocycler/driver.py +10 -61
  9. opentrons/drivers/thermocycler/simulator.py +0 -6
  10. opentrons/hardware_control/api.py +5 -24
  11. opentrons/hardware_control/backends/controller.py +2 -8
  12. opentrons/hardware_control/backends/flex_protocol.py +1 -0
  13. opentrons/hardware_control/backends/ot3controller.py +3 -3
  14. opentrons/hardware_control/backends/ot3simulator.py +2 -2
  15. opentrons/hardware_control/backends/simulator.py +1 -2
  16. opentrons/hardware_control/backends/subsystem_manager.py +2 -5
  17. opentrons/hardware_control/emulation/abstract_emulator.py +4 -6
  18. opentrons/hardware_control/emulation/connection_handler.py +5 -8
  19. opentrons/hardware_control/emulation/heater_shaker.py +3 -12
  20. opentrons/hardware_control/emulation/settings.py +1 -1
  21. opentrons/hardware_control/emulation/thermocycler.py +15 -67
  22. opentrons/hardware_control/module_control.py +8 -82
  23. opentrons/hardware_control/modules/__init__.py +0 -3
  24. opentrons/hardware_control/modules/absorbance_reader.py +4 -11
  25. opentrons/hardware_control/modules/flex_stacker.py +9 -38
  26. opentrons/hardware_control/modules/heater_shaker.py +5 -42
  27. opentrons/hardware_control/modules/magdeck.py +4 -8
  28. opentrons/hardware_control/modules/mod_abc.py +5 -13
  29. opentrons/hardware_control/modules/tempdeck.py +5 -25
  30. opentrons/hardware_control/modules/thermocycler.py +11 -68
  31. opentrons/hardware_control/modules/types.py +1 -20
  32. opentrons/hardware_control/modules/utils.py +4 -11
  33. opentrons/hardware_control/nozzle_manager.py +0 -3
  34. opentrons/hardware_control/ot3api.py +7 -26
  35. opentrons/hardware_control/poller.py +8 -22
  36. opentrons/hardware_control/protocols/gripper_controller.py +1 -0
  37. opentrons/hardware_control/scripts/update_module_fw.py +0 -5
  38. opentrons/hardware_control/types.py +2 -31
  39. opentrons/legacy_commands/module_commands.py +0 -23
  40. opentrons/legacy_commands/protocol_commands.py +0 -20
  41. opentrons/legacy_commands/types.py +0 -80
  42. opentrons/motion_planning/deck_conflict.py +12 -17
  43. opentrons/motion_planning/waypoints.py +29 -15
  44. opentrons/protocol_api/__init__.py +1 -5
  45. opentrons/protocol_api/_types.py +1 -6
  46. opentrons/protocol_api/core/common.py +1 -3
  47. opentrons/protocol_api/core/engine/_default_labware_versions.py +11 -32
  48. opentrons/protocol_api/core/engine/labware.py +1 -8
  49. opentrons/protocol_api/core/engine/module_core.py +8 -75
  50. opentrons/protocol_api/core/engine/protocol.py +1 -18
  51. opentrons/protocol_api/core/engine/well.py +0 -8
  52. opentrons/protocol_api/core/legacy/legacy_module_core.py +4 -24
  53. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +1 -11
  54. opentrons/protocol_api/core/legacy/legacy_well_core.py +0 -4
  55. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +2 -14
  56. opentrons/protocol_api/core/module.py +4 -37
  57. opentrons/protocol_api/core/protocol.py +2 -11
  58. opentrons/protocol_api/core/well.py +0 -4
  59. opentrons/protocol_api/labware.py +0 -5
  60. opentrons/protocol_api/module_contexts.py +61 -122
  61. opentrons/protocol_api/protocol_context.py +4 -26
  62. opentrons/protocol_api/robot_context.py +21 -38
  63. opentrons/protocol_api/validation.py +1 -6
  64. opentrons/protocol_engine/actions/__init__.py +2 -4
  65. opentrons/protocol_engine/actions/actions.py +9 -22
  66. opentrons/protocol_engine/clients/sync_client.py +7 -42
  67. opentrons/protocol_engine/commands/__init__.py +0 -42
  68. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +15 -2
  69. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +15 -2
  70. opentrons/protocol_engine/commands/aspirate.py +0 -1
  71. opentrons/protocol_engine/commands/command.py +0 -1
  72. opentrons/protocol_engine/commands/command_unions.py +0 -49
  73. opentrons/protocol_engine/commands/dispense.py +0 -1
  74. opentrons/protocol_engine/commands/drop_tip.py +8 -32
  75. opentrons/protocol_engine/commands/heater_shaker/__init__.py +0 -14
  76. opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +4 -5
  77. opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +5 -31
  78. opentrons/protocol_engine/commands/movement_common.py +0 -2
  79. opentrons/protocol_engine/commands/pick_up_tip.py +11 -21
  80. opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +7 -38
  81. opentrons/protocol_engine/commands/thermocycler/__init__.py +0 -16
  82. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +0 -6
  83. opentrons/protocol_engine/commands/thermocycler/run_profile.py +0 -8
  84. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +6 -40
  85. opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +5 -29
  86. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  87. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +22 -6
  88. opentrons/protocol_engine/errors/__init__.py +0 -4
  89. opentrons/protocol_engine/errors/exceptions.py +0 -55
  90. opentrons/protocol_engine/execution/__init__.py +0 -2
  91. opentrons/protocol_engine/execution/command_executor.py +0 -8
  92. opentrons/protocol_engine/execution/create_queue_worker.py +1 -5
  93. opentrons/protocol_engine/execution/labware_movement.py +21 -10
  94. opentrons/protocol_engine/execution/movement.py +0 -2
  95. opentrons/protocol_engine/execution/queue_worker.py +0 -4
  96. opentrons/protocol_engine/execution/run_control.py +0 -8
  97. opentrons/protocol_engine/protocol_engine.py +34 -75
  98. opentrons/protocol_engine/resources/__init__.py +0 -2
  99. opentrons/protocol_engine/resources/deck_configuration_provider.py +0 -7
  100. opentrons/protocol_engine/resources/labware_validation.py +6 -10
  101. opentrons/protocol_engine/state/_labware_origin_math.py +636 -0
  102. opentrons/protocol_engine/state/_well_math.py +18 -60
  103. opentrons/protocol_engine/state/addressable_areas.py +0 -2
  104. opentrons/protocol_engine/state/commands.py +11 -14
  105. opentrons/protocol_engine/state/geometry.py +374 -213
  106. opentrons/protocol_engine/state/labware.py +102 -52
  107. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +0 -37
  108. opentrons/protocol_engine/state/modules.py +8 -21
  109. opentrons/protocol_engine/state/motion.py +0 -44
  110. opentrons/protocol_engine/state/state.py +0 -14
  111. opentrons/protocol_engine/state/state_summary.py +0 -2
  112. opentrons/protocol_engine/state/tips.py +258 -177
  113. opentrons/protocol_engine/state/update_types.py +9 -16
  114. opentrons/protocol_engine/types/__init__.py +3 -9
  115. opentrons/protocol_engine/types/deck_configuration.py +1 -5
  116. opentrons/protocol_engine/types/instrument.py +1 -8
  117. opentrons/protocol_engine/types/labware.py +13 -1
  118. opentrons/protocol_engine/types/module.py +0 -10
  119. opentrons/protocol_engine/types/tip.py +0 -9
  120. opentrons/protocol_runner/create_simulating_orchestrator.py +2 -29
  121. opentrons/protocol_runner/run_orchestrator.py +2 -18
  122. opentrons/protocols/api_support/definitions.py +1 -1
  123. opentrons/protocols/api_support/types.py +1 -2
  124. opentrons/simulate.py +15 -48
  125. opentrons/system/camera.py +1 -1
  126. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/METADATA +4 -4
  127. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/RECORD +130 -146
  128. opentrons/protocol_api/core/engine/tasks.py +0 -48
  129. opentrons/protocol_api/core/legacy/tasks.py +0 -19
  130. opentrons/protocol_api/core/legacy_simulator/tasks.py +0 -19
  131. opentrons/protocol_api/core/tasks.py +0 -31
  132. opentrons/protocol_api/tasks.py +0 -48
  133. opentrons/protocol_engine/commands/create_timer.py +0 -83
  134. opentrons/protocol_engine/commands/heater_shaker/common.py +0 -20
  135. opentrons/protocol_engine/commands/heater_shaker/set_shake_speed.py +0 -136
  136. opentrons/protocol_engine/commands/set_tip_state.py +0 -97
  137. opentrons/protocol_engine/commands/thermocycler/start_run_extended_profile.py +0 -191
  138. opentrons/protocol_engine/commands/wait_for_tasks.py +0 -98
  139. opentrons/protocol_engine/execution/task_handler.py +0 -157
  140. opentrons/protocol_engine/resources/concurrency_provider.py +0 -27
  141. opentrons/protocol_engine/state/labware_origin_math/errors.py +0 -94
  142. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +0 -1331
  143. opentrons/protocol_engine/state/tasks.py +0 -139
  144. opentrons/protocol_engine/types/tasks.py +0 -38
  145. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/WHEEL +0 -0
  146. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/entry_points.txt +0 -0
  147. {opentrons-8.7.0a7.dist-info → opentrons-8.7.0a9.dist-info}/licenses/LICENSE +0 -0
@@ -56,6 +56,7 @@ from ..types import (
56
56
  LoadedLabware,
57
57
  ModuleLocation,
58
58
  OverlapOffset,
59
+ LabwareMovementOffsetData,
59
60
  OnDeckLabwareLocation,
60
61
  OFF_DECK_LOCATION,
61
62
  )
@@ -400,7 +401,7 @@ class LabwareView:
400
401
  return self._state.labware_by_id[labware_id]
401
402
  except KeyError as e:
402
403
  raise errors.LabwareNotLoadedError(
403
- f"Labware with id {labware_id} not found."
404
+ f"Labware {labware_id} not found."
404
405
  ) from e
405
406
 
406
407
  def known(self, labware_id: str) -> bool:
@@ -429,7 +430,7 @@ class LabwareView:
429
430
  ):
430
431
  return labware.id
431
432
  raise errors.exceptions.LabwareNotLoadedOnLabwareError(
432
- f"There is not labware loaded onto labware {self.get_display_name(labware_id)}"
433
+ f"There is not labware loaded onto labware {labware_id}"
433
434
  )
434
435
 
435
436
  def raise_if_labware_has_non_lid_labware_on_top(self, labware_id: str) -> None:
@@ -442,8 +443,7 @@ class LabwareView:
442
443
  and candidate_id != lid_id
443
444
  ):
444
445
  raise errors.LabwareIsInStackError(
445
- f"Cannot access labware {self.get_display_name(labware_id)} because it has"
446
- " a non-lid labware stacked on top."
446
+ f"Cannot access labware {labware_id} because it has a non-lid labware stacked on top."
447
447
  )
448
448
 
449
449
  def raise_if_labware_has_labware_on_top(self, labware_id: str) -> None:
@@ -454,29 +454,9 @@ class LabwareView:
454
454
  and labware.location.labwareId == labware_id
455
455
  ):
456
456
  raise errors.LabwareIsInStackError(
457
- f"Cannot access labware {self.get_display_name(labware_id)} because it has"
458
- " another labware stacked on top."
457
+ f"Cannot access labware {labware_id} because it has another labware stacked on top."
459
458
  )
460
459
 
461
- def raise_if_not_tip_rack(self, labware_id: str) -> None:
462
- """Raise if a labware is not a tip rack."""
463
- if not self.is_tiprack(labware_id):
464
- raise errors.LabwareIsNotTipRackError(
465
- f"Labware {self.get_display_name(labware_id)} is not a tip rack and cannot have its well states set."
466
- )
467
-
468
- def raise_if_wells_are_invalid(
469
- self, labware_id: str, well_names: List[str]
470
- ) -> None:
471
- """Raise if given wells do not exist with the given labware ID."""
472
- non_existent_wells = set(well_names) - set(
473
- self.get_definition(labware_id).wells
474
- )
475
- if non_existent_wells:
476
- raise errors.WellDoesNotExistError(
477
- f"Tip rack {self.get_display_name(labware_id)} does not have wells: {', '.join(non_existent_wells)}"
478
- )
479
-
480
460
  def get_by_slot(
481
461
  self,
482
462
  slot_name: Union[DeckSlotName, StagingSlotName],
@@ -683,14 +663,6 @@ class LabwareView:
683
663
  or len(self.get_definition(labware_id).wells) >= 96
684
664
  )
685
665
 
686
- def get_has_96_subwells(self, labware_id: str) -> bool:
687
- """True if a labware is a reservoir with a 96-grid of sub-wells."""
688
- return self.get_has_quirk(labware_id, "offsetPipetteFor96GridSubwells")
689
-
690
- def get_has_12_subwells(self, labware_id: str) -> bool:
691
- """True if a labware is a reservoir with a 12-grid of sub-wells."""
692
- return self.get_has_quirk(labware_id, "offsetPipetteFor12GridSubwells")
693
-
694
666
  def get_well_definition(
695
667
  self,
696
668
  labware_id: str,
@@ -709,7 +681,7 @@ class LabwareView:
709
681
  return definition.wells[well_name]
710
682
  except KeyError as e:
711
683
  raise errors.WellDoesNotExistError(
712
- f"{well_name} does not exist in {self.get_display_name(labware_id)}."
684
+ f"{well_name} does not exist in {labware_id}."
713
685
  ) from e
714
686
 
715
687
  def get_well_geometry(
@@ -719,21 +691,19 @@ class LabwareView:
719
691
  labware_def = self.get_definition(labware_id)
720
692
  if labware_def.innerLabwareGeometry is None:
721
693
  raise errors.IncompleteLabwareDefinitionError(
722
- message=f"No innerLabwareGeometry found in labware definition for {self.get_display_name(labware_id)}."
694
+ message=f"No innerLabwareGeometry found in labware definition for labware_id: {labware_id}."
723
695
  )
724
696
  well_def = self.get_well_definition(labware_id, well_name)
725
697
  geometry_id = well_def.geometryDefinitionId
726
698
  if geometry_id is None:
727
699
  raise errors.IncompleteWellDefinitionError(
728
- message=f"No geometryDefinitionId found in well definition for well {well_name}"
729
- f" for {self.get_display_name(labware_id)}"
700
+ message=f"No geometryDefinitionId found in well definition for well: {well_name} in labware_id: {labware_id}"
730
701
  )
731
702
  else:
732
703
  well_geometry = labware_def.innerLabwareGeometry.get(geometry_id)
733
704
  if well_geometry is None:
734
705
  raise errors.IncompleteLabwareDefinitionError(
735
- message=f"No innerLabwareGeometry found in labware definition for geometry id {geometry_id}"
736
- f" for {self.get_display_name(labware_id)}"
706
+ message=f"No innerLabwareGeometry found in labware definition for well_id: {geometry_id} in labware_id: {labware_id}"
737
707
  )
738
708
  return well_geometry
739
709
 
@@ -802,15 +772,15 @@ class LabwareView:
802
772
  contains_wells = all(well_name in labware_wells for well_name in iter(wells))
803
773
  if labware_definition.parameters.isTiprack:
804
774
  raise errors.LabwareIsTipRackError(
805
- f"Given labware {self.get_display_name(labware_id)} is a tip rack. Can not load liquid."
775
+ f"Given labware: {labware_id} is a tiprack. Can not load liquid."
806
776
  )
807
777
  if LabwareRole.adapter in labware_definition.allowedRoles:
808
778
  raise errors.LabwareIsAdapterError(
809
- f"Given labware {self.get_display_name(labware_id)} is an adapter. Can not load liquid."
779
+ f"Given labware: {labware_id} is an adapter. Can not load liquid."
810
780
  )
811
781
  if not contains_wells:
812
782
  raise errors.WellDoesNotExistError(
813
- f"Some of the supplied wells do not match the labware {self.get_display_name(labware_id)}."
783
+ f"Some of the supplied wells do not match the labwareId: {labware_id}."
814
784
  )
815
785
  return list(wells)
816
786
 
@@ -819,7 +789,7 @@ class LabwareView:
819
789
  definition = self.get_definition(labware_id)
820
790
  if definition.parameters.tipLength is None:
821
791
  raise errors.LabwareIsNotTipRackError(
822
- f"Labware {self.get_display_name(labware_id)} has no tip length defined."
792
+ f"Labware {labware_id} has no tip length defined."
823
793
  )
824
794
 
825
795
  return definition.parameters.tipLength - overlap
@@ -1125,9 +1095,7 @@ class LabwareView:
1125
1095
  raise errors.LabwareCannotBeStackedError(
1126
1096
  f"Labware {lid_labware_definition.parameters.loadName} cannot be used as a lid in the Flex Stacker."
1127
1097
  )
1128
- if isinstance(
1129
- lid_labware_definition, LabwareDefinition2
1130
- ) and not labware_validation.validate_legacy_labware_can_be_stacked(
1098
+ if not labware_validation.validate_labware_can_be_stacked(
1131
1099
  lid_labware_definition, primary_labware_definition.parameters.loadName
1132
1100
  ):
1133
1101
  raise errors.LabwareCannotBeStackedError(
@@ -1140,9 +1108,7 @@ class LabwareView:
1140
1108
  raise errors.LabwareCannotBeStackedError(
1141
1109
  f"Labware {adapter_labware_definition.parameters.loadName} cannot be used as an adapter in the Flex Stacker."
1142
1110
  )
1143
- if isinstance(
1144
- primary_labware_definition, LabwareDefinition2
1145
- ) and not labware_validation.validate_legacy_labware_can_be_stacked(
1111
+ if not labware_validation.validate_labware_can_be_stacked(
1146
1112
  primary_labware_definition,
1147
1113
  adapter_labware_definition.parameters.loadName,
1148
1114
  ):
@@ -1196,9 +1162,9 @@ class LabwareView:
1196
1162
  below_labware = self.get(bottom_labware_id)
1197
1163
  if isinstance(
1198
1164
  top_labware_definition, LabwareDefinition2
1199
- ) and not labware_validation.validate_legacy_labware_can_be_stacked(
1200
- child_labware_definition=top_labware_definition,
1201
- parent_labware_load_name=below_labware.loadName,
1165
+ ) and not labware_validation.validate_labware_can_be_stacked(
1166
+ top_labware_definition=top_labware_definition,
1167
+ below_labware_load_name=below_labware.loadName,
1202
1168
  ):
1203
1169
  raise errors.LabwareCannotBeStackedError(
1204
1170
  f"Labware {top_labware_definition.parameters.loadName} cannot be loaded onto labware {below_labware.loadName}"
@@ -1259,6 +1225,28 @@ class LabwareView:
1259
1225
  uri = self.get_uri_from_definition(self.get_definition(labware_id))
1260
1226
  return uri in _MAGDECK_HALF_MM_LABWARE
1261
1227
 
1228
+ def get_deck_default_gripper_offsets(self) -> Optional[LabwareMovementOffsetData]:
1229
+ """Get the deck's default gripper offsets."""
1230
+ parsed_offsets = (
1231
+ self.get_deck_definition().get("gripperOffsets", {}).get("default")
1232
+ )
1233
+ return (
1234
+ LabwareMovementOffsetData(
1235
+ pickUpOffset=LabwareOffsetVector(
1236
+ x=parsed_offsets["pickUpOffset"]["x"],
1237
+ y=parsed_offsets["pickUpOffset"]["y"],
1238
+ z=parsed_offsets["pickUpOffset"]["z"],
1239
+ ),
1240
+ dropOffset=LabwareOffsetVector(
1241
+ x=parsed_offsets["dropOffset"]["x"],
1242
+ y=parsed_offsets["dropOffset"]["y"],
1243
+ z=parsed_offsets["dropOffset"]["z"],
1244
+ ),
1245
+ )
1246
+ if parsed_offsets
1247
+ else None
1248
+ )
1249
+
1262
1250
  def get_absorbance_reader_lid_definition(self) -> LabwareDefinition:
1263
1251
  """Return the special labware definition for the plate reader lid.
1264
1252
 
@@ -1269,6 +1257,68 @@ class LabwareView:
1269
1257
  "opentrons/opentrons_flex_lid_absorbance_plate_reader_module/1"
1270
1258
  ]
1271
1259
 
1260
+ @overload
1261
+ def get_child_gripper_offsets(
1262
+ self,
1263
+ *,
1264
+ labware_definition: LabwareDefinition,
1265
+ slot_name: Optional[DeckSlotName],
1266
+ ) -> Optional[LabwareMovementOffsetData]:
1267
+ pass
1268
+
1269
+ @overload
1270
+ def get_child_gripper_offsets(
1271
+ self, *, labware_id: str, slot_name: Optional[DeckSlotName]
1272
+ ) -> Optional[LabwareMovementOffsetData]:
1273
+ pass
1274
+
1275
+ def get_child_gripper_offsets(
1276
+ self,
1277
+ *,
1278
+ labware_definition: Optional[LabwareDefinition] = None,
1279
+ labware_id: Optional[str] = None,
1280
+ slot_name: Optional[DeckSlotName],
1281
+ ) -> Optional[LabwareMovementOffsetData]:
1282
+ """Get the grip offsets that a labware says should be applied to children stacked atop it.
1283
+
1284
+ Params:
1285
+ labware_id: The ID of a parent labware (atop which another labware, the child, will be stacked).
1286
+ slot_name: The ancestor slot that the parent labware is ultimately loaded into,
1287
+ perhaps after going through a module in the middle.
1288
+
1289
+ Returns:
1290
+ If `slot_name` is provided, returns the gripper offsets that the parent labware definition
1291
+ specifies just for that slot, or `None` if the labware definition doesn't have an
1292
+ exact match.
1293
+
1294
+ If `slot_name` is `None`, returns the gripper offsets that the parent labware
1295
+ definition designates as "default," or `None` if it doesn't designate any as such.
1296
+ """
1297
+ if labware_id is not None:
1298
+ labware_definition = self.get_definition(labware_id)
1299
+ else:
1300
+ # Should be ensured by our @overloads.
1301
+ assert labware_definition is not None
1302
+
1303
+ parsed_offsets = labware_definition.gripperOffsets
1304
+ offset_key = slot_name.id if slot_name else "default"
1305
+
1306
+ if parsed_offsets is None or offset_key not in parsed_offsets:
1307
+ return None
1308
+ else:
1309
+ return LabwareMovementOffsetData(
1310
+ pickUpOffset=LabwareOffsetVector.model_construct(
1311
+ x=parsed_offsets[offset_key].pickUpOffset.x,
1312
+ y=parsed_offsets[offset_key].pickUpOffset.y,
1313
+ z=parsed_offsets[offset_key].pickUpOffset.z,
1314
+ ),
1315
+ dropOffset=LabwareOffsetVector.model_construct(
1316
+ x=parsed_offsets[offset_key].dropOffset.x,
1317
+ y=parsed_offsets[offset_key].dropOffset.y,
1318
+ z=parsed_offsets[offset_key].dropOffset.z,
1319
+ ),
1320
+ )
1321
+
1272
1322
  def get_grip_force(self, labware_definition: LabwareDefinition) -> float:
1273
1323
  """Get the recommended grip force for gripping labware using gripper."""
1274
1324
  recommended_force = labware_definition.gripForce
@@ -5,7 +5,6 @@ from typing import NewType, Optional
5
5
  from opentrons.protocol_engine.errors import (
6
6
  InvalidTargetTemperatureError,
7
7
  InvalidBlockVolumeError,
8
- InvalidRampRateError,
9
8
  NoTargetTemperatureSetError,
10
9
  InvalidHoldTimeError,
11
10
  )
@@ -24,10 +23,6 @@ from opentrons.hardware_control.modules import ModuleData, ModuleDataValidator
24
23
 
25
24
  ThermocyclerModuleId = NewType("ThermocyclerModuleId", str)
26
25
 
27
- # These are our published numbers, and from testing they are good bounds
28
- MAX_HEATING_RATE = 4.25
29
- MAX_COOLING_RATE = 2.0
30
-
31
26
 
32
27
  @dataclass(frozen=True)
33
28
  class ThermocyclerModuleSubState:
@@ -148,38 +143,6 @@ class ThermocyclerModuleSubState:
148
143
  )
149
144
  return target
150
145
 
151
- def validate_ramp_rate(
152
- self, ramp_rate: Optional[float], target_temp: float
153
- ) -> Optional[float]:
154
- """Validate a given temperature ramp rate.
155
-
156
- Args:
157
- ramp_rate: The requested ramp rate in °C/second.
158
- target_temp: The requested block temperature.
159
-
160
- Raises:
161
- InvalidRampRateError: The given ramp_rate is invalid
162
-
163
- Returns:
164
- The validated ramp rate in °C/second
165
- """
166
- if ramp_rate is None:
167
- return ramp_rate
168
-
169
- heating = target_temp > self.get_target_block_temperature()
170
- if (heating and ramp_rate > MAX_HEATING_RATE) or (
171
- not heating and ramp_rate > MAX_COOLING_RATE
172
- ):
173
- raise InvalidRampRateError(
174
- f"Thermocycler ramp rate cannot exceed {MAX_HEATING_RATE}°C/s"
175
- f" while heating or {MAX_COOLING_RATE}°C/s when cooling."
176
- )
177
- if ramp_rate <= 0:
178
- raise InvalidRampRateError(
179
- f"Thermocycler ramp rate cannot be less than or equal to 0, got {ramp_rate}"
180
- )
181
- return ramp_rate
182
-
183
146
  @classmethod
184
147
  def from_live_data(
185
148
  cls, module_id: ThermocyclerModuleId, data: ModuleData | None
@@ -56,6 +56,7 @@ from ..types import (
56
56
  HeaterShakerLatchStatus,
57
57
  HeaterShakerMovementRestrictors,
58
58
  DeckType,
59
+ LabwareMovementOffsetData,
59
60
  AddressableAreaLocation,
60
61
  StackerStoredLabwareGroup,
61
62
  )
@@ -1335,6 +1336,13 @@ class ModuleView:
1335
1336
  return True
1336
1337
  return False
1337
1338
 
1339
+ def get_default_gripper_offsets(
1340
+ self, module_id: str
1341
+ ) -> Optional[LabwareMovementOffsetData]:
1342
+ """Get the deck's default gripper offsets."""
1343
+ offsets = self.get_definition(module_id).gripperOffsets
1344
+ return offsets.get("default") if offsets else None
1345
+
1338
1346
  def get_overflowed_module_in_slot(
1339
1347
  self, slot_name: DeckSlotName
1340
1348
  ) -> Optional[LoadedModule]:
@@ -1511,24 +1519,3 @@ class ModuleView:
1511
1519
  f"Provided overlap offset {overlap_offset} does not match "
1512
1520
  f"configured {configured}."
1513
1521
  )
1514
-
1515
- def get_has_module_probably_matching_hardware_details(
1516
- self, module_model: ModuleModel, module_serial: str | None
1517
- ) -> bool:
1518
- """Get the ID of a model that possibly matches the provided details.
1519
-
1520
- If the provided serial is not None, return True if there is a module with the same serial or
1521
- False if there is not.
1522
- If the provided serial is None, return True if there is a module with the same model or False if
1523
- there is not.
1524
-
1525
- This is intended to provide a good probability that a module matching the provided details
1526
- is or is not present in the state store. It is used to drive whether the engine cancels a protocol
1527
- in response to an asynchronous module error or not.
1528
- """
1529
- for module_id, module in self._state.hardware_by_module_id.items():
1530
- if module_serial is not None and module_serial == module.serial_number:
1531
- return True
1532
- if module_serial is None and module.definition.model == module_model:
1533
- return True
1534
- return False
@@ -1,7 +1,6 @@
1
1
  """Motion state store and getters."""
2
2
  from dataclasses import dataclass
3
3
  from typing import List, Optional, Union
4
- import logging
5
4
 
6
5
  from opentrons.types import MountType, Point, StagingSlotName
7
6
  from opentrons.hardware_control.types import CriticalPoint
@@ -29,8 +28,6 @@ from .geometry import GeometryView
29
28
  from .modules import ModuleView
30
29
  from .module_substates import HeaterShakerModuleId
31
30
 
32
- log = logging.getLogger(__name__)
33
-
34
31
 
35
32
  @dataclass(frozen=True)
36
33
  class PipetteLocationData:
@@ -88,42 +85,6 @@ class MotionView:
88
85
  critical_point = CriticalPoint.XY_CENTER
89
86
  return PipetteLocationData(mount=mount, critical_point=critical_point)
90
87
 
91
- def _get_pipette_offset_for_reservoirs(
92
- self, labware_id: str, well_name: str, pipette_id: str
93
- ) -> Point:
94
- # 8 rows, 12 columns
95
- subwells_96 = self._labware.get_has_96_subwells(labware_id)
96
- # 1 row, 12 columns
97
- subwells_12 = self._labware.get_has_12_subwells(labware_id)
98
- if subwells_12 and subwells_96:
99
- log.warning(
100
- f"{self._labware.get_display_name(labware_id)} has both offsetPipetteFor96GridSubwells and"
101
- " offsetPipetteFor12GridSubwells quirks."
102
- )
103
-
104
- pipette_rows = self._pipettes.get_nozzle_configuration(pipette_id).rows
105
- pipette_cols = self._pipettes.get_nozzle_configuration(pipette_id).columns
106
-
107
- even_labware_rows = subwells_96
108
- even_labware_columns = subwells_96 or subwells_12
109
- odd_pipette_rows = len(pipette_rows) % 2 == 1
110
- odd_pipette_cols = len(pipette_cols) % 2 == 1
111
-
112
- well_x_dim, well_y_dim, well_z_dim = self._labware.get_well_size(
113
- labware_id=labware_id, well_name=well_name
114
- )
115
- x_offset = 0.0
116
- y_offset = 0.0
117
- if even_labware_rows and odd_pipette_rows:
118
- # need to move up half a row
119
- # there's 8 rows, so move 1/16 of reservoir length
120
- y_offset = well_y_dim / 16
121
- if even_labware_columns and odd_pipette_cols:
122
- # need to move left half a column
123
- # there's 12 columns, so move 1/24 of reservoir width
124
- x_offset = -1 * well_x_dim / 24
125
- return Point(x=x_offset, y=y_offset)
126
-
127
88
  def get_movement_waypoints_to_well(
128
89
  self,
129
90
  pipette_id: str,
@@ -137,7 +98,6 @@ class MotionView:
137
98
  force_direct: bool = False,
138
99
  minimum_z_height: Optional[float] = None,
139
100
  operation_volume: Optional[float] = None,
140
- offset_pipette_for_reservoir_subwells: bool = False,
141
101
  ) -> List[motion_planning.Waypoint]:
142
102
  """Calculate waypoints to a destination that's specified as a well."""
143
103
  location = current_well or self._pipettes.get_current_location()
@@ -155,10 +115,6 @@ class MotionView:
155
115
  operation_volume=operation_volume,
156
116
  pipette_id=pipette_id,
157
117
  )
158
- if offset_pipette_for_reservoir_subwells:
159
- destination += self._get_pipette_offset_for_reservoirs(
160
- labware_id=labware_id, well_name=well_name, pipette_id=pipette_id
161
- )
162
118
 
163
119
  move_type = _move_types.get_move_type_to_well(
164
120
  pipette_id, labware_id, well_name, location, force_direct
@@ -34,7 +34,6 @@ from .files import FileView, FileState, FileStore
34
34
  from .config import Config
35
35
  from .state_summary import StateSummary
36
36
  from ..types import DeckConfigurationType
37
- from .tasks import TaskState, TaskView, TaskStore
38
37
 
39
38
 
40
39
  _ParamsT = ParamSpec("_ParamsT")
@@ -55,7 +54,6 @@ class State:
55
54
  tips: TipState
56
55
  wells: WellState
57
56
  files: FileState
58
- tasks: TaskState
59
57
 
60
58
 
61
59
  class StateView(HasState[State]):
@@ -75,7 +73,6 @@ class StateView(HasState[State]):
75
73
  _motion: MotionView
76
74
  _files: FileView
77
75
  _config: Config
78
- _tasks: TaskView
79
76
 
80
77
  @property
81
78
  def commands(self) -> CommandView:
@@ -142,11 +139,6 @@ class StateView(HasState[State]):
142
139
  """Get ProtocolEngine configuration."""
143
140
  return self._config
144
141
 
145
- @property
146
- def tasks(self) -> TaskView:
147
- """Get state view selectors for task state."""
148
- return self._tasks
149
-
150
142
  def get_summary(self) -> StateSummary:
151
143
  """Get protocol run data."""
152
144
  error = self._commands.get_error()
@@ -170,7 +162,6 @@ class StateView(HasState[State]):
170
162
  )
171
163
  for liquid_class_id, liquid_class_record in self._liquid_classes.get_all().items()
172
164
  ],
173
- tasks=self._tasks.get_summary(),
174
165
  )
175
166
 
176
167
 
@@ -240,7 +231,6 @@ class StateStore(StateView, ActionHandler):
240
231
  self._tip_store = TipStore()
241
232
  self._well_store = WellStore()
242
233
  self._file_store = FileStore()
243
- self._task_store = TaskStore()
244
234
 
245
235
  self._substores: List[HandlesActions] = [
246
236
  self._command_store,
@@ -253,7 +243,6 @@ class StateStore(StateView, ActionHandler):
253
243
  self._tip_store,
254
244
  self._well_store,
255
245
  self._file_store,
256
- self._task_store,
257
246
  ]
258
247
  self._config = config
259
248
  self._change_notifier = change_notifier or ChangeNotifier()
@@ -377,7 +366,6 @@ class StateStore(StateView, ActionHandler):
377
366
  tips=self._tip_store.state,
378
367
  wells=self._well_store.state,
379
368
  files=self._file_store.state,
380
- tasks=self._task_store.state,
381
369
  )
382
370
 
383
371
  def _initialize_state(self) -> None:
@@ -396,7 +384,6 @@ class StateStore(StateView, ActionHandler):
396
384
  self._tips = TipView(state.tips)
397
385
  self._wells = WellView(state.wells)
398
386
  self._files = FileView(state.files)
399
- self._tasks = TaskView(state.tasks)
400
387
 
401
388
  # Derived states
402
389
  self._geometry = GeometryView(
@@ -429,7 +416,6 @@ class StateStore(StateView, ActionHandler):
429
416
  self._liquid_classes._state = next_state.liquid_classes
430
417
  self._tips._state = next_state.tips
431
418
  self._wells._state = next_state.wells
432
- self._tasks._state = next_state.tasks
433
419
  self._change_notifier.notify()
434
420
  if self._notify_robot_server is not None:
435
421
  self._notify_robot_server()
@@ -13,7 +13,6 @@ from ..types import (
13
13
  Liquid,
14
14
  LiquidClassRecordWithId,
15
15
  WellInfoSummary,
16
- TaskSummary,
17
16
  )
18
17
 
19
18
 
@@ -35,4 +34,3 @@ class StateSummary(BaseModel):
35
34
  wells: List[WellInfoSummary] = Field(default_factory=list)
36
35
  files: List[str] = Field(default_factory=list)
37
36
  liquidClasses: List[LiquidClassRecordWithId] = Field(default_factory=list)
38
- tasks: List[TaskSummary] = Field(default_factory=list)