opentrons 8.7.0a0__py3-none-any.whl → 8.7.0a2__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 (121) hide show
  1. opentrons/_version.py +2 -2
  2. opentrons/drivers/thermocycler/abstract.py +1 -0
  3. opentrons/drivers/thermocycler/driver.py +33 -4
  4. opentrons/drivers/thermocycler/simulator.py +2 -0
  5. opentrons/hardware_control/api.py +24 -5
  6. opentrons/hardware_control/backends/controller.py +8 -2
  7. opentrons/hardware_control/backends/ot3controller.py +3 -0
  8. opentrons/hardware_control/backends/ot3simulator.py +2 -1
  9. opentrons/hardware_control/backends/simulator.py +2 -1
  10. opentrons/hardware_control/backends/subsystem_manager.py +5 -2
  11. opentrons/hardware_control/module_control.py +82 -8
  12. opentrons/hardware_control/modules/__init__.py +3 -0
  13. opentrons/hardware_control/modules/absorbance_reader.py +11 -4
  14. opentrons/hardware_control/modules/flex_stacker.py +38 -9
  15. opentrons/hardware_control/modules/heater_shaker.py +30 -5
  16. opentrons/hardware_control/modules/magdeck.py +8 -4
  17. opentrons/hardware_control/modules/mod_abc.py +13 -5
  18. opentrons/hardware_control/modules/tempdeck.py +25 -5
  19. opentrons/hardware_control/modules/thermocycler.py +56 -10
  20. opentrons/hardware_control/modules/types.py +20 -1
  21. opentrons/hardware_control/modules/utils.py +11 -4
  22. opentrons/hardware_control/nozzle_manager.py +3 -0
  23. opentrons/hardware_control/ot3api.py +26 -5
  24. opentrons/hardware_control/scripts/update_module_fw.py +5 -0
  25. opentrons/hardware_control/types.py +31 -2
  26. opentrons/legacy_commands/protocol_commands.py +20 -0
  27. opentrons/legacy_commands/types.py +42 -0
  28. opentrons/motion_planning/waypoints.py +15 -29
  29. opentrons/protocol_api/__init__.py +5 -0
  30. opentrons/protocol_api/_types.py +6 -1
  31. opentrons/protocol_api/core/common.py +3 -1
  32. opentrons/protocol_api/core/engine/_default_labware_versions.py +32 -11
  33. opentrons/protocol_api/core/engine/_default_liquid_class_versions.py +2 -0
  34. opentrons/protocol_api/core/engine/labware.py +8 -1
  35. opentrons/protocol_api/core/engine/module_core.py +4 -0
  36. opentrons/protocol_api/core/engine/pipette_movement_conflict.py +77 -17
  37. opentrons/protocol_api/core/engine/protocol.py +18 -1
  38. opentrons/protocol_api/core/engine/tasks.py +35 -0
  39. opentrons/protocol_api/core/legacy/legacy_module_core.py +2 -0
  40. opentrons/protocol_api/core/legacy/legacy_protocol_core.py +11 -1
  41. opentrons/protocol_api/core/legacy/tasks.py +19 -0
  42. opentrons/protocol_api/core/legacy_simulator/legacy_protocol_core.py +14 -2
  43. opentrons/protocol_api/core/legacy_simulator/tasks.py +19 -0
  44. opentrons/protocol_api/core/module.py +1 -0
  45. opentrons/protocol_api/core/protocol.py +11 -2
  46. opentrons/protocol_api/core/tasks.py +31 -0
  47. opentrons/protocol_api/module_contexts.py +1 -0
  48. opentrons/protocol_api/protocol_context.py +26 -4
  49. opentrons/protocol_api/robot_context.py +38 -21
  50. opentrons/protocol_api/tasks.py +48 -0
  51. opentrons/protocol_api/validation.py +6 -1
  52. opentrons/protocol_engine/actions/__init__.py +4 -2
  53. opentrons/protocol_engine/actions/actions.py +22 -9
  54. opentrons/protocol_engine/clients/sync_client.py +6 -7
  55. opentrons/protocol_engine/commands/__init__.py +42 -0
  56. opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +2 -15
  57. opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +2 -15
  58. opentrons/protocol_engine/commands/aspirate.py +1 -0
  59. opentrons/protocol_engine/commands/command.py +1 -0
  60. opentrons/protocol_engine/commands/command_unions.py +39 -0
  61. opentrons/protocol_engine/commands/create_timer.py +83 -0
  62. opentrons/protocol_engine/commands/dispense.py +1 -0
  63. opentrons/protocol_engine/commands/drop_tip.py +32 -8
  64. opentrons/protocol_engine/commands/movement_common.py +2 -0
  65. opentrons/protocol_engine/commands/pick_up_tip.py +21 -11
  66. opentrons/protocol_engine/commands/set_tip_state.py +97 -0
  67. opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +6 -0
  68. opentrons/protocol_engine/commands/thermocycler/run_profile.py +8 -0
  69. opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +17 -1
  70. opentrons/protocol_engine/commands/touch_tip.py +1 -1
  71. opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +6 -22
  72. opentrons/protocol_engine/commands/wait_for_tasks.py +98 -0
  73. opentrons/protocol_engine/errors/__init__.py +4 -0
  74. opentrons/protocol_engine/errors/exceptions.py +55 -0
  75. opentrons/protocol_engine/execution/__init__.py +2 -0
  76. opentrons/protocol_engine/execution/command_executor.py +8 -0
  77. opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
  78. opentrons/protocol_engine/execution/labware_movement.py +9 -12
  79. opentrons/protocol_engine/execution/movement.py +2 -0
  80. opentrons/protocol_engine/execution/queue_worker.py +4 -0
  81. opentrons/protocol_engine/execution/run_control.py +8 -0
  82. opentrons/protocol_engine/execution/task_handler.py +157 -0
  83. opentrons/protocol_engine/protocol_engine.py +67 -33
  84. opentrons/protocol_engine/resources/__init__.py +2 -0
  85. opentrons/protocol_engine/resources/concurrency_provider.py +27 -0
  86. opentrons/protocol_engine/resources/deck_configuration_provider.py +7 -0
  87. opentrons/protocol_engine/resources/labware_validation.py +10 -6
  88. opentrons/protocol_engine/state/_well_math.py +60 -18
  89. opentrons/protocol_engine/state/addressable_areas.py +2 -0
  90. opentrons/protocol_engine/state/commands.py +7 -7
  91. opentrons/protocol_engine/state/geometry.py +237 -379
  92. opentrons/protocol_engine/state/labware.py +52 -102
  93. opentrons/protocol_engine/state/labware_origin_math/errors.py +94 -0
  94. opentrons/protocol_engine/state/labware_origin_math/stackup_origin_to_labware_origin.py +1331 -0
  95. opentrons/protocol_engine/state/module_substates/thermocycler_module_substate.py +37 -0
  96. opentrons/protocol_engine/state/modules.py +26 -7
  97. opentrons/protocol_engine/state/motion.py +44 -0
  98. opentrons/protocol_engine/state/state.py +14 -0
  99. opentrons/protocol_engine/state/state_summary.py +2 -0
  100. opentrons/protocol_engine/state/tasks.py +139 -0
  101. opentrons/protocol_engine/state/tips.py +177 -258
  102. opentrons/protocol_engine/state/update_types.py +16 -9
  103. opentrons/protocol_engine/types/__init__.py +9 -3
  104. opentrons/protocol_engine/types/deck_configuration.py +5 -1
  105. opentrons/protocol_engine/types/instrument.py +8 -1
  106. opentrons/protocol_engine/types/labware.py +1 -13
  107. opentrons/protocol_engine/types/module.py +10 -0
  108. opentrons/protocol_engine/types/tasks.py +38 -0
  109. opentrons/protocol_engine/types/tip.py +9 -0
  110. opentrons/protocol_runner/create_simulating_orchestrator.py +29 -2
  111. opentrons/protocol_runner/run_orchestrator.py +18 -2
  112. opentrons/protocols/api_support/definitions.py +1 -1
  113. opentrons/protocols/api_support/types.py +2 -1
  114. opentrons/simulate.py +48 -15
  115. opentrons/system/camera.py +1 -1
  116. {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a2.dist-info}/METADATA +4 -4
  117. {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a2.dist-info}/RECORD +120 -107
  118. opentrons/protocol_engine/state/_labware_origin_math.py +0 -636
  119. {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a2.dist-info}/WHEEL +0 -0
  120. {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a2.dist-info}/entry_points.txt +0 -0
  121. {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -271,6 +271,22 @@ from .wait_for_duration import (
271
271
  WaitForDurationCommandType,
272
272
  )
273
273
 
274
+ from .create_timer import (
275
+ CreateTimer,
276
+ CreateTimerCreate,
277
+ CreateTimerParams,
278
+ CreateTimerResult,
279
+ CreateTimerCommandType,
280
+ )
281
+
282
+ from .wait_for_tasks import (
283
+ WaitForTasks,
284
+ WaitForTasksCreate,
285
+ WaitForTasksParams,
286
+ WaitForTasksResult,
287
+ WaitForTasksCommandType,
288
+ )
289
+
274
290
  from .pick_up_tip import (
275
291
  PickUpTip,
276
292
  PickUpTipParams,
@@ -384,6 +400,14 @@ from .get_next_tip import (
384
400
  GetNextTipCommandType,
385
401
  )
386
402
 
403
+ from .set_tip_state import (
404
+ SetTipState,
405
+ SetTipStateCreate,
406
+ SetTipStateParams,
407
+ SetTipStateResult,
408
+ SetTipStateCommandType,
409
+ )
410
+
387
411
  from .liquid_probe import (
388
412
  LiquidProbe,
389
413
  LiquidProbeParams,
@@ -619,6 +643,12 @@ __all__ = [
619
643
  "WaitForDurationCreate",
620
644
  "WaitForDurationResult",
621
645
  "WaitForDurationCommandType",
646
+ # Timer command models
647
+ "CreateTimer",
648
+ "CreateTimerCreate",
649
+ "CreateTimerParams",
650
+ "CreateTimerResult",
651
+ "CreateTimerCommandType",
622
652
  # pick up tip command models
623
653
  "PickUpTip",
624
654
  "PickUpTipCreate",
@@ -725,6 +755,12 @@ __all__ = [
725
755
  "GetNextTipParams",
726
756
  "GetNextTipResult",
727
757
  "GetNextTipCommandType",
758
+ # set tip state command bundle
759
+ "SetTipState",
760
+ "SetTipStateCreate",
761
+ "SetTipStateParams",
762
+ "SetTipStateResult",
763
+ "SetTipStateCommandType",
728
764
  # liquid probe command bundle
729
765
  "LiquidProbe",
730
766
  "LiquidProbeParams",
@@ -754,4 +790,10 @@ __all__ = [
754
790
  "PressureDispenseCreate",
755
791
  "PressureDispenseResult",
756
792
  "PressureDispenseCommandType",
793
+ # wait for tasks command bundle
794
+ "WaitForTasks",
795
+ "WaitForTasksCreate",
796
+ "WaitForTasksParams",
797
+ "WaitForTasksResult",
798
+ "WaitForTasksCommandType",
757
799
  ]
@@ -102,25 +102,12 @@ class CloseLidImpl(AbstractCommandImpl[CloseLidParams, SuccessData[CloseLidResul
102
102
  )
103
103
  )
104
104
 
105
- # The lid's labware definition stores gripper offsets for itself in the
106
- # space normally meant for offsets for labware stacked atop it.
107
- lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
108
- labware_definition=lid_definition,
109
- slot_name=None,
110
- )
111
- if lid_gripper_offsets is None:
112
- raise ValueError(
113
- "Gripper Offset values for Absorbance Reader Lid labware must not be None."
114
- )
115
-
116
105
  await self._labware_movement.move_labware_with_gripper(
117
106
  labware_definition=lid_definition,
118
107
  current_location=current_location,
119
108
  new_location=new_location,
120
- user_pick_up_offset=Point.from_xyz_attrs(
121
- lid_gripper_offsets.pickUpOffset
122
- ),
123
- user_drop_offset=Point.from_xyz_attrs(lid_gripper_offsets.dropOffset),
109
+ user_pick_up_offset=Point(),
110
+ user_drop_offset=Point(),
124
111
  post_drop_slide_offset=None,
125
112
  gripper_z_offset=LID_Z_CLEARANCE,
126
113
  )
@@ -103,25 +103,12 @@ class OpenLidImpl(AbstractCommandImpl[OpenLidParams, SuccessData[OpenLidResult]]
103
103
  mod_substate.module_id
104
104
  )
105
105
 
106
- # The lid's labware definition stores gripper offsets for itself in the
107
- # space normally meant for offsets for labware stacked atop it.
108
- lid_gripper_offsets = self._state_view.labware.get_child_gripper_offsets(
109
- labware_definition=lid_definition,
110
- slot_name=None,
111
- )
112
- if lid_gripper_offsets is None:
113
- raise ValueError(
114
- "Gripper Offset values for Absorbance Reader Lid labware must not be None."
115
- )
116
-
117
106
  await self._labware_movement.move_labware_with_gripper(
118
107
  labware_definition=lid_definition,
119
108
  current_location=current_location,
120
109
  new_location=new_location,
121
- user_pick_up_offset=Point.from_xyz_attrs(
122
- lid_gripper_offsets.pickUpOffset
123
- ),
124
- user_drop_offset=Point.from_xyz_attrs(lid_gripper_offsets.dropOffset),
110
+ user_pick_up_offset=Point(),
111
+ user_drop_offset=Point(),
125
112
  post_drop_slide_offset=None,
126
113
  gripper_z_offset=LID_Z_CLEARANCE,
127
114
  )
@@ -161,6 +161,7 @@ class AspirateImplementation(AbstractCommandImpl[AspirateParams, _ExecuteReturn]
161
161
  well_location=well_location,
162
162
  current_well=current_well,
163
163
  operation_volume=-params.volume,
164
+ offset_pipette_for_reservoir_subwells=False,
164
165
  )
165
166
  state_update.append(move_result.state_update)
166
167
  if isinstance(move_result, DefinedErrorData):
@@ -185,6 +185,7 @@ class AbstractCommandImpl(
185
185
  tip_handler: execution.TipHandler,
186
186
  run_control: execution.RunControlHandler,
187
187
  rail_lights: execution.RailLightsHandler,
188
+ task_handler: execution.TaskHandler,
188
189
  model_utils: ModelUtils,
189
190
  status_bar: execution.StatusBarHandler,
190
191
  command_note_adder: CommandNoteAdder,
@@ -267,6 +267,22 @@ from .wait_for_duration import (
267
267
  WaitForDurationCommandType,
268
268
  )
269
269
 
270
+ from .create_timer import (
271
+ CreateTimer,
272
+ CreateTimerCreate,
273
+ CreateTimerParams,
274
+ CreateTimerResult,
275
+ CreateTimerCommandType,
276
+ )
277
+
278
+ from .wait_for_tasks import (
279
+ WaitForTasks,
280
+ WaitForTasksCreate,
281
+ WaitForTasksParams,
282
+ WaitForTasksResult,
283
+ WaitForTasksCommandType,
284
+ )
285
+
270
286
  from .pick_up_tip import (
271
287
  PickUpTip,
272
288
  PickUpTipParams,
@@ -372,6 +388,14 @@ from .get_next_tip import (
372
388
  GetNextTipCommandType,
373
389
  )
374
390
 
391
+ from .set_tip_state import (
392
+ SetTipState,
393
+ SetTipStateCreate,
394
+ SetTipStateParams,
395
+ SetTipStateResult,
396
+ SetTipStateCommandType,
397
+ )
398
+
375
399
  from .liquid_probe import (
376
400
  LiquidProbe,
377
401
  LiquidProbeParams,
@@ -454,6 +478,8 @@ Command = Annotated[
454
478
  PrepareToAspirate,
455
479
  WaitForResume,
456
480
  WaitForDuration,
481
+ WaitForTasks,
482
+ CreateTimer,
457
483
  PickUpTip,
458
484
  SavePosition,
459
485
  SetRailLights,
@@ -462,6 +488,7 @@ Command = Annotated[
462
488
  VerifyTipPresence,
463
489
  GetTipPresence,
464
490
  GetNextTip,
491
+ SetTipState,
465
492
  LiquidProbe,
466
493
  TryLiquidProbe,
467
494
  SealPipetteToTip,
@@ -557,6 +584,8 @@ CommandParams = Union[
557
584
  PrepareToAspirateParams,
558
585
  WaitForResumeParams,
559
586
  WaitForDurationParams,
587
+ WaitForTasksParams,
588
+ CreateTimerParams,
560
589
  PickUpTipParams,
561
590
  SavePositionParams,
562
591
  SetRailLightsParams,
@@ -565,6 +594,7 @@ CommandParams = Union[
565
594
  VerifyTipPresenceParams,
566
595
  GetTipPresenceParams,
567
596
  GetNextTipParams,
597
+ SetTipStateParams,
568
598
  LiquidProbeParams,
569
599
  TryLiquidProbeParams,
570
600
  SealPipetteToTipParams,
@@ -658,6 +688,8 @@ CommandType = Union[
658
688
  PrepareToAspirateCommandType,
659
689
  WaitForResumeCommandType,
660
690
  WaitForDurationCommandType,
691
+ WaitForTasksCommandType,
692
+ CreateTimerCommandType,
661
693
  PickUpTipCommandType,
662
694
  SavePositionCommandType,
663
695
  SetRailLightsCommandType,
@@ -666,6 +698,7 @@ CommandType = Union[
666
698
  VerifyTipPresenceCommandType,
667
699
  GetTipPresenceCommandType,
668
700
  GetNextTipCommandType,
701
+ SetTipStateCommandType,
669
702
  LiquidProbeCommandType,
670
703
  TryLiquidProbeCommandType,
671
704
  SealPipetteToTipCommandType,
@@ -760,6 +793,8 @@ CommandCreate = Annotated[
760
793
  PrepareToAspirateCreate,
761
794
  WaitForResumeCreate,
762
795
  WaitForDurationCreate,
796
+ WaitForTasksCreate,
797
+ CreateTimerCreate,
763
798
  PickUpTipCreate,
764
799
  SavePositionCreate,
765
800
  SetRailLightsCreate,
@@ -768,6 +803,7 @@ CommandCreate = Annotated[
768
803
  VerifyTipPresenceCreate,
769
804
  GetTipPresenceCreate,
770
805
  GetNextTipCreate,
806
+ SetTipStateCreate,
771
807
  LiquidProbeCreate,
772
808
  TryLiquidProbeCreate,
773
809
  SealPipetteToTipCreate,
@@ -870,6 +906,8 @@ CommandResult = Union[
870
906
  PrepareToAspirateResult,
871
907
  WaitForResumeResult,
872
908
  WaitForDurationResult,
909
+ WaitForTasksResult,
910
+ CreateTimerResult,
873
911
  PickUpTipResult,
874
912
  SavePositionResult,
875
913
  SetRailLightsResult,
@@ -878,6 +916,7 @@ CommandResult = Union[
878
916
  VerifyTipPresenceResult,
879
917
  GetTipPresenceResult,
880
918
  GetNextTipResult,
919
+ SetTipStateResult,
881
920
  LiquidProbeResult,
882
921
  TryLiquidProbeResult,
883
922
  SealPipetteToTipResult,
@@ -0,0 +1,83 @@
1
+ """CreateTimer command request, result, and implementation models."""
2
+
3
+ from __future__ import annotations
4
+ from pydantic import BaseModel, Field
5
+ from typing import Optional, Type, TYPE_CHECKING
6
+ from typing_extensions import Literal
7
+
8
+ from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
9
+ from ..errors.error_occurrence import ErrorOccurrence
10
+
11
+ if TYPE_CHECKING:
12
+ from ..execution import TaskHandler, RunControlHandler
13
+
14
+
15
+ CreateTimerCommandType = Literal["createTimer"]
16
+
17
+
18
+ class CreateTimerParams(BaseModel):
19
+ """Payload required to annotate execution with a CreateTimer."""
20
+
21
+ time: float = Field(
22
+ ...,
23
+ description="The time before the timer should elapse in seconds. This is the minimum time before the timer elapses; it may in practice take longer than this.",
24
+ )
25
+ task_id: str | None = Field(
26
+ None,
27
+ description="The id of the timer task",
28
+ )
29
+
30
+
31
+ class CreateTimerResult(BaseModel):
32
+ """Result data from the execution of a CreateTimer command."""
33
+
34
+ task_id: str = Field(..., description="The id of the timer task")
35
+ time: float = Field(..., description="The same time as the parameter.")
36
+
37
+
38
+ class CreateTimerImplementation(
39
+ AbstractCommandImpl[CreateTimerParams, SuccessData[CreateTimerResult]]
40
+ ):
41
+ """CreateTimer command implementation."""
42
+
43
+ def __init__(
44
+ self,
45
+ task_handler: TaskHandler,
46
+ run_control: RunControlHandler,
47
+ **kwargs: object,
48
+ ) -> None:
49
+ self._task_handler = task_handler
50
+ self._run_control = run_control
51
+
52
+ async def execute(
53
+ self, params: CreateTimerParams
54
+ ) -> SuccessData[CreateTimerResult]:
55
+ """No operation taken other than capturing message in command."""
56
+
57
+ async def timer(task_handler: TaskHandler) -> None:
58
+ async with task_handler.synchronize_concurrent("createTimer"):
59
+ await self._run_control.wait_for_duration(params.time)
60
+
61
+ task = await self._task_handler.create_task(timer, params.task_id)
62
+ return SuccessData(
63
+ public=CreateTimerResult(task_id=task.id, time=params.time),
64
+ )
65
+
66
+
67
+ class CreateTimer(BaseCommand[CreateTimerParams, CreateTimerResult, ErrorOccurrence]):
68
+ """CreateTimer command model."""
69
+
70
+ commandType: CreateTimerCommandType = "createTimer"
71
+ params: CreateTimerParams
72
+ result: Optional[CreateTimerResult] = None
73
+
74
+ _ImplementationCls: Type[CreateTimerImplementation] = CreateTimerImplementation
75
+
76
+
77
+ class CreateTimerCreate(BaseCommandCreate[CreateTimerParams]):
78
+ """CreateTimer command request model."""
79
+
80
+ commandType: CreateTimerCommandType = "createTimer"
81
+ params: CreateTimerParams
82
+
83
+ _CommandCls: Type[CreateTimer] = CreateTimer
@@ -101,6 +101,7 @@ class DispenseImplementation(AbstractCommandImpl[DispenseParams, _ExecuteReturn]
101
101
  well_name=well_name,
102
102
  well_location=well_location,
103
103
  operation_volume=volume,
104
+ offset_pipette_for_reservoir_subwells=False,
104
105
  )
105
106
  if isinstance(move_result, DefinedErrorData):
106
107
  return move_result
@@ -12,7 +12,7 @@ from opentrons.protocol_engine.errors.exceptions import TipAttachedError
12
12
  from opentrons.protocol_engine.resources.model_utils import ModelUtils
13
13
 
14
14
  from ..state.update_types import StateUpdate
15
- from ..types import DropTipWellLocation
15
+ from ..types import DropTipWellLocation, TipRackWellState
16
16
  from .pipetting_common import (
17
17
  PipetteIdMixin,
18
18
  TipPhysicallyAttachedError,
@@ -140,6 +140,25 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
140
140
  partially_configured=is_partially_configured,
141
141
  )
142
142
 
143
+ is_tip_rack = self._state_view.labware.get_definition(
144
+ labware_id
145
+ ).parameters.isTiprack
146
+
147
+ # It's possible that we are dropping tips into a labware trash for pre API v2.14 OT-2 protocols
148
+ # (or something else unexpected), so if it is not a tip rack mark no wells as used
149
+ if is_tip_rack:
150
+ tips_to_mark_as_used = (
151
+ self._state_view.tips.compute_tips_to_mark_as_used_or_empty(
152
+ labware_id=labware_id,
153
+ well_name=well_name,
154
+ nozzle_map=self._state_view.pipettes.get_nozzle_configuration(
155
+ pipette_id
156
+ ),
157
+ )
158
+ )
159
+ else:
160
+ tips_to_mark_as_used = []
161
+
143
162
  move_result = await move_to_well(
144
163
  movement=self._movement_handler,
145
164
  model_utils=self._model_utils,
@@ -152,12 +171,7 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
152
171
  return move_result
153
172
 
154
173
  scrape_type = TipScrapeType.NONE
155
- if (
156
- params.scrape_tips
157
- and self._state_view.geometry._labware.get_definition(
158
- labware_id
159
- ).parameters.isTiprack
160
- ):
174
+ if params.scrape_tips and is_tip_rack:
161
175
  if int("".join(filter(str.isdigit, well_name))) <= 6:
162
176
  scrape_type = TipScrapeType.RIGHT_ONE_COL
163
177
  else:
@@ -194,6 +208,10 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
194
208
  pipette_id=params.pipetteId,
195
209
  tip_geometry=None,
196
210
  tip_source=None,
211
+ ).update_tip_rack_well_state(
212
+ tip_state=TipRackWellState.USED,
213
+ labware_id=labware_id,
214
+ well_names=tips_to_mark_as_used,
197
215
  ),
198
216
  )
199
217
  else:
@@ -201,10 +219,16 @@ class DropTipImplementation(AbstractCommandImpl[DropTipParams, _ExecuteReturn]):
201
219
  public=DropTipResult(position=move_result.public.position),
202
220
  state_update=move_result.state_update.set_fluid_unknown(
203
221
  pipette_id=pipette_id
204
- ).update_pipette_tip_state(
222
+ )
223
+ .update_pipette_tip_state(
205
224
  pipette_id=params.pipetteId,
206
225
  tip_geometry=None,
207
226
  tip_source=None,
227
+ )
228
+ .update_tip_rack_well_state(
229
+ tip_state=TipRackWellState.USED,
230
+ labware_id=labware_id,
231
+ well_names=tips_to_mark_as_used,
208
232
  ),
209
233
  )
210
234
 
@@ -152,6 +152,7 @@ async def move_to_well(
152
152
  minimum_z_height: Optional[float] = None,
153
153
  speed: Optional[float] = None,
154
154
  operation_volume: Optional[float] = None,
155
+ offset_pipette_for_reservoir_subwells: bool = False,
155
156
  ) -> MoveToWellOperationReturn:
156
157
  """Execute a move to well microoperation."""
157
158
  try:
@@ -165,6 +166,7 @@ async def move_to_well(
165
166
  minimum_z_height=minimum_z_height,
166
167
  speed=speed,
167
168
  operation_volume=operation_volume,
169
+ offset_pipette_for_reservoir_subwells=offset_pipette_for_reservoir_subwells,
168
170
  )
169
171
  except StallOrCollisionDetectedError as e:
170
172
  return DefinedErrorData(
@@ -10,7 +10,7 @@ from typing_extensions import Literal
10
10
  from ..errors import ErrorOccurrence, PickUpTipTipNotAttachedError
11
11
  from ..resources import ModelUtils
12
12
  from ..state import update_types
13
- from ..types import PickUpTipWellLocation, LabwareWellId
13
+ from ..types import PickUpTipWellLocation, LabwareWellId, TipRackWellState
14
14
  from .pipetting_common import (
15
15
  PipetteIdMixin,
16
16
  )
@@ -121,10 +121,14 @@ class PickUpTipImplementation(AbstractCommandImpl[PickUpTipParams, _ExecuteRetur
121
121
  labware_id = params.labwareId
122
122
  well_name = params.wellName
123
123
 
124
- tips_to_mark_as_used = self._state_view.tips.compute_tips_to_mark_as_used(
125
- labware_id=labware_id,
126
- well_name=well_name,
127
- nozzle_map=self._state_view.pipettes.get_nozzle_configuration(pipette_id),
124
+ tips_to_mark_as_empty = (
125
+ self._state_view.tips.compute_tips_to_mark_as_used_or_empty(
126
+ labware_id=labware_id,
127
+ well_name=well_name,
128
+ nozzle_map=self._state_view.pipettes.get_nozzle_configuration(
129
+ pipette_id
130
+ ),
131
+ )
128
132
  )
129
133
 
130
134
  well_location = self._state_view.geometry.convert_pick_up_tip_well_location(
@@ -160,16 +164,20 @@ class PickUpTipImplementation(AbstractCommandImpl[PickUpTipParams, _ExecuteRetur
160
164
  ),
161
165
  )
162
166
  .set_fluid_empty(pipette_id=pipette_id, clean_tip=True)
163
- .mark_tips_as_used(
164
- labware_id=labware_id, well_names=tips_to_mark_as_used
167
+ .update_tip_rack_well_state(
168
+ tip_state=TipRackWellState.EMPTY,
169
+ labware_id=labware_id,
170
+ well_names=tips_to_mark_as_empty,
165
171
  )
166
172
  )
167
173
  state_update = (
168
174
  update_types.StateUpdate.reduce(
169
175
  update_types.StateUpdate(), move_result.state_update
170
176
  )
171
- .mark_tips_as_used(
172
- labware_id=labware_id, well_names=tips_to_mark_as_used
177
+ .update_tip_rack_well_state(
178
+ tip_state=TipRackWellState.EMPTY,
179
+ labware_id=labware_id,
180
+ well_names=tips_to_mark_as_empty,
173
181
  )
174
182
  .set_fluid_unknown(pipette_id=pipette_id)
175
183
  )
@@ -197,8 +205,10 @@ class PickUpTipImplementation(AbstractCommandImpl[PickUpTipParams, _ExecuteRetur
197
205
  labware_id=labware_id, well_name=well_name
198
206
  ),
199
207
  )
200
- .mark_tips_as_used(
201
- labware_id=labware_id, well_names=tips_to_mark_as_used
208
+ .update_tip_rack_well_state(
209
+ tip_state=TipRackWellState.EMPTY,
210
+ labware_id=labware_id,
211
+ well_names=tips_to_mark_as_empty,
202
212
  )
203
213
  .set_fluid_empty(pipette_id=pipette_id, clean_tip=True)
204
214
  .set_pipette_ready_to_aspirate(
@@ -0,0 +1,97 @@
1
+ """Set tip state command request, result, and implementation models."""
2
+
3
+ from __future__ import annotations
4
+ from pydantic import BaseModel, Field
5
+ from typing import TYPE_CHECKING, Optional, Type, List
6
+ from typing_extensions import Literal
7
+
8
+ from ..errors.error_occurrence import ErrorOccurrence
9
+ from ..state.update_types import StateUpdate
10
+ from ..types import TipRackWellState
11
+
12
+
13
+ from .command import (
14
+ AbstractCommandImpl,
15
+ BaseCommand,
16
+ BaseCommandCreate,
17
+ SuccessData,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from ..state.state import StateView
22
+
23
+
24
+ SetTipStateCommandType = Literal["setTipState"]
25
+
26
+
27
+ class SetTipStateParams(BaseModel):
28
+ """Payload needed to set tip wells of a tip rack to the requested state."""
29
+
30
+ labwareId: str = Field(
31
+ ..., description="Identifier of tip rack labware to set tip wells in."
32
+ )
33
+ wellNames: List[str] = Field(
34
+ ..., description="Names of the well to set tip well state for."
35
+ )
36
+ tipWellState: TipRackWellState = Field(
37
+ ..., description="State to set tip wells to."
38
+ )
39
+
40
+
41
+ class SetTipStateResult(BaseModel):
42
+ """Result data from the execution of a setTipState command."""
43
+
44
+ pass
45
+
46
+
47
+ class SetTipStateImplementation(
48
+ AbstractCommandImpl[SetTipStateParams, SuccessData[SetTipStateResult]]
49
+ ):
50
+ """Set tip state command implementation."""
51
+
52
+ def __init__(
53
+ self,
54
+ state_view: StateView,
55
+ **kwargs: object,
56
+ ) -> None:
57
+ self._state_view = state_view
58
+
59
+ async def execute(
60
+ self, params: SetTipStateParams
61
+ ) -> SuccessData[SetTipStateResult]:
62
+ """Set the tip rack wells to the requested state."""
63
+ labware_id = params.labwareId
64
+ well_names = params.wellNames
65
+
66
+ self._state_view.labware.raise_if_not_tip_rack(labware_id=labware_id)
67
+ self._state_view.labware.raise_if_wells_are_invalid(
68
+ labware_id=labware_id, well_names=well_names
69
+ )
70
+
71
+ return SuccessData(
72
+ public=SetTipStateResult(),
73
+ state_update=StateUpdate().update_tip_rack_well_state(
74
+ tip_state=params.tipWellState,
75
+ labware_id=labware_id,
76
+ well_names=well_names,
77
+ ),
78
+ )
79
+
80
+
81
+ class SetTipState(BaseCommand[SetTipStateParams, SetTipStateResult, ErrorOccurrence]):
82
+ """Set tip state command model."""
83
+
84
+ commandType: SetTipStateCommandType = "setTipState"
85
+ params: SetTipStateParams
86
+ result: Optional[SetTipStateResult] = None
87
+
88
+ _ImplementationCls: Type[SetTipStateImplementation] = SetTipStateImplementation
89
+
90
+
91
+ class SetTipStateCreate(BaseCommandCreate[SetTipStateParams]):
92
+ """Set tip state command creation request model."""
93
+
94
+ commandType: SetTipStateCommandType = "setTipState"
95
+ params: SetTipStateParams
96
+
97
+ _CommandCls: Type[SetTipState] = SetTipState
@@ -33,6 +33,11 @@ class ProfileStep(BaseModel):
33
33
  holdSeconds: float = Field(
34
34
  ..., description="Time to hold target temperature in seconds."
35
35
  )
36
+ rampRate: float | SkipJsonSchema[None] = Field(
37
+ None,
38
+ description="How quickly to change temperature in °C/second.",
39
+ json_schema_extra=_remove_default,
40
+ )
36
41
 
37
42
 
38
43
  class ProfileCycle(BaseModel):
@@ -68,6 +73,7 @@ def _transform_profile_step(
68
73
  return ThermocyclerStep(
69
74
  temperature=thermocycler_state.validate_target_block_temperature(step.celsius),
70
75
  hold_time_seconds=step.holdSeconds,
76
+ ramp_rate=thermocycler_state.validate_ramp_rate(step.rampRate, step.celsius),
71
77
  )
72
78
 
73
79
 
@@ -30,6 +30,11 @@ class RunProfileStepParams(BaseModel):
30
30
  holdSeconds: float = Field(
31
31
  ..., description="Time to hold target temperature at in seconds."
32
32
  )
33
+ rampRate: float | SkipJsonSchema[None] = Field(
34
+ None,
35
+ description="How quickly to change temperature in °C/second.",
36
+ json_schema_extra=_remove_default,
37
+ )
33
38
 
34
39
 
35
40
  class RunProfileParams(BaseModel):
@@ -81,6 +86,9 @@ class RunProfileImpl(
81
86
  profile_step.celsius
82
87
  ),
83
88
  hold_time_seconds=profile_step.holdSeconds,
89
+ ramp_rate=thermocycler_state.validate_ramp_rate(
90
+ profile_step.rampRate, profile_step.celsius
91
+ ),
84
92
  )
85
93
  for profile_step in params.profile
86
94
  ]