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
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from abc import abstractmethod, ABC
6
- from typing import Generic, List, Optional, Union, Tuple, Dict, TYPE_CHECKING, Sequence
6
+ from typing import Generic, List, Optional, Union, Tuple, Dict, TYPE_CHECKING
7
7
 
8
8
  from opentrons_shared_data.deck.types import DeckDefinitionV5, SlotDefV3
9
9
  from opentrons_shared_data.pipette.types import PipetteNameType
@@ -24,7 +24,6 @@ from opentrons.protocols.api_support.util import AxisMaxSpeeds
24
24
  from .instrument import InstrumentCoreType
25
25
  from .labware import LabwareCoreType, LabwareLoadParams
26
26
  from .module import ModuleCoreType
27
- from .tasks import TaskCoreType
28
27
  from .._liquid import Liquid, LiquidClass
29
28
  from .robot import AbstractRobot
30
29
  from .._types import OffDeckType
@@ -35,7 +34,7 @@ if TYPE_CHECKING:
35
34
 
36
35
 
37
36
  class AbstractProtocol(
38
- ABC, Generic[InstrumentCoreType, LabwareCoreType, ModuleCoreType, TaskCoreType]
37
+ ABC, Generic[InstrumentCoreType, LabwareCoreType, ModuleCoreType]
39
38
  ):
40
39
  @property
41
40
  @abstractmethod
@@ -193,14 +192,6 @@ class AbstractProtocol(
193
192
  def delay(self, seconds: float, msg: Optional[str]) -> None:
194
193
  ...
195
194
 
196
- @abstractmethod
197
- def wait_for_tasks(self, task_cores: Sequence[TaskCoreType]) -> None:
198
- ...
199
-
200
- @abstractmethod
201
- def create_timer(self, seconds: float) -> TaskCoreType:
202
- ...
203
-
204
195
  @abstractmethod
205
196
  def home(self) -> None:
206
197
  ...
@@ -112,9 +112,5 @@ class AbstractWellCore(ABC):
112
112
  def volume_from_height(self, height: LiquidTrackingType) -> LiquidTrackingType:
113
113
  """Return the volume contained in a well at any height."""
114
114
 
115
- @abstractmethod
116
- def has_tracked_liquid(self) -> bool:
117
- """Return true if liquid has been loaded or probed."""
118
-
119
115
 
120
116
  WellCoreType = TypeVar("WellCoreType", bound=AbstractWellCore)
@@ -347,11 +347,6 @@ class Well:
347
347
  """Get the current liquid volume in a well."""
348
348
  return self._core.get_liquid_volume()
349
349
 
350
- @requires_version(2, 27)
351
- def has_tracked_liquid(self) -> bool:
352
- """Get the current liquid volume in a well."""
353
- return self._core.has_tracked_liquid()
354
-
355
350
  @requires_version(2, 24)
356
351
  def volume_from_height(self, height: LiquidTrackingType) -> LiquidTrackingType:
357
352
  """Return the volume contained in a well at any height."""
@@ -43,7 +43,6 @@ from .module_validation_and_errors import (
43
43
  )
44
44
  from .labware import Labware
45
45
  from . import validation
46
- from . import Task
47
46
 
48
47
 
49
48
  _MAGNETIC_MODULE_HEIGHT_PARAM_REMOVED_IN = APIVersion(2, 14)
@@ -448,28 +447,18 @@ class TemperatureModuleContext(ModuleContext):
448
447
  No other protocol commands will execute while waiting for the temperature.
449
448
 
450
449
  :param celsius: A value between 4 and 95, representing the target temperature in °C.
451
-
452
450
  """
453
451
  self._core.set_target_temperature(celsius)
454
452
  self._core.wait_for_target_temperature()
455
453
 
456
454
  @publish(command=cmds.tempdeck_set_temp)
457
455
  @requires_version(2, 3)
458
- def start_set_temperature(self, celsius: float) -> Task:
456
+ def start_set_temperature(self, celsius: float) -> None:
459
457
  """Set the target temperature without waiting for the target to be hit.
460
458
 
461
- .. versionchanged:: 2.27
462
- Returns a task object that represents concurrent preheating.
463
- Pass the task object to :py:meth:`ProtocolContext.wait_for_tasks` to wait for the preheat to complete.
464
-
465
- On version 2.26 or below, this function returns ``None``.
466
459
  :param celsius: A value between 4 and 95, representing the target temperature in °C.
467
460
  """
468
- task = self._core.set_target_temperature(celsius)
469
- if self._api_version >= APIVersion(2, 27):
470
- return Task(api_version=self._api_version, core=task)
471
- else:
472
- return cast(Task, None)
461
+ self._core.set_target_temperature(celsius)
473
462
 
474
463
  @publish(command=cmds.tempdeck_await_temp)
475
464
  @requires_version(2, 3)
@@ -667,16 +656,9 @@ class ThermocyclerContext(ModuleContext):
667
656
  hold_time_minutes: Optional[float] = None,
668
657
  ramp_rate: Optional[float] = None,
669
658
  block_max_volume: Optional[float] = None,
670
- ) -> Task:
659
+ ) -> None:
671
660
  """Set the target temperature for the well block, in °C.
672
661
 
673
- .. versionchanged::2.27
674
- Returns a task object that represents concurrent preheating.
675
- Pass the task object to :py:meth:`ProtocolContext.wait_for_tasks` to wait for
676
- the preheat to complete.
677
-
678
- On version 2.26 or below, this function returns ``None``.
679
-
680
662
  :param temperature: A value between 4 and 99, representing the target
681
663
  temperature in °C.
682
664
  :param hold_time_minutes: The number of minutes to hold, after reaching
@@ -690,10 +672,6 @@ class ThermocyclerContext(ModuleContext):
690
672
  :param block_max_volume: The greatest volume of liquid contained in any
691
673
  individual well of the loaded labware, in µL.
692
674
  If not specified, the default is 25 µL.
693
- After API version 2.27 it will attempt to use
694
- the liquid tracking of the labware first and
695
- then fall back to the 25 if there is no probed
696
- or loaded liquid.
697
675
 
698
676
  .. note::
699
677
 
@@ -704,31 +682,18 @@ class ThermocyclerContext(ModuleContext):
704
682
  seconds = validation.ensure_hold_time_seconds(
705
683
  seconds=hold_time_seconds, minutes=hold_time_minutes
706
684
  )
707
- if self._api_version >= APIVersion(2, 27) and block_max_volume is None:
708
- block_max_volume = self._get_current_labware_max_vol()
709
- task = self._core.set_target_block_temperature(
685
+ self._core.set_target_block_temperature(
710
686
  celsius=temperature,
711
687
  hold_time_seconds=seconds,
712
688
  block_max_volume=block_max_volume,
713
- ramp_rate=ramp_rate,
714
689
  )
715
- if self._api_version >= APIVersion(2, 27):
716
- return Task(api_version=self._api_version, core=task)
717
- else:
718
- return cast(Task, None)
690
+ self._core.wait_for_block_temperature()
719
691
 
720
692
  @publish(command=cmds.thermocycler_set_lid_temperature)
721
693
  @requires_version(2, 0)
722
- def set_lid_temperature(self, temperature: float) -> Task:
694
+ def set_lid_temperature(self, temperature: float) -> None:
723
695
  """Set the target temperature for the heated lid, in °C.
724
696
 
725
- .. versionchanged::2.27
726
- Returns a task object that represents concurrent preheating.
727
- Pass the task object to :py:meth:`ProtocolContext.wait_for_tasks` to wait for
728
- the preheat to complete.
729
-
730
- On version 2.26 or below, this function returns ``None``.
731
-
732
697
  :param temperature: A value between 37 and 110, representing the target
733
698
  temperature in °C.
734
699
 
@@ -738,11 +703,8 @@ class ThermocyclerContext(ModuleContext):
738
703
  ``temperature`` is reached.
739
704
 
740
705
  """
741
- task = self._core.set_target_lid_temperature(celsius=temperature)
742
- if self._api_version >= APIVersion(2, 27):
743
- return Task(api_version=self._api_version, core=task)
744
- else:
745
- return cast(Task, None)
706
+ self._core.set_target_lid_temperature(celsius=temperature)
707
+ self._core.wait_for_lid_temperature()
746
708
 
747
709
  @publish(command=cmds.thermocycler_execute_profile)
748
710
  @requires_version(2, 0)
@@ -777,39 +739,6 @@ class ThermocyclerContext(ModuleContext):
777
739
  block_max_volume=block_max_volume,
778
740
  )
779
741
 
780
- @publish(command=cmds.thermocycler_start_execute_profile)
781
- @requires_version(2, 27)
782
- def start_execute_profile(
783
- self,
784
- steps: List[ThermocyclerStep],
785
- repetitions: int,
786
- block_max_volume: Optional[float] = None,
787
- ) -> Task:
788
- """Start a Thermocycler profile and return a :py:class:`Task` representing its execution.
789
- Profile is defined as a cycle of ``steps``, for a given number of ``repetitions``.
790
-
791
- Returns a task object that represents concurrent execution of the profile.
792
- Pass the task object to :py:meth:`ProtocolContext.wait_for_tasks` to wait for the preheat to complete.
793
-
794
- :param steps: List of steps that make up a single cycle.
795
- Each list item should be a dictionary that maps to the parameters
796
- of the :py:meth:`set_block_temperature` method. The dictionary's
797
- keys must be ``temperature`` and one or both of
798
- ``hold_time_seconds`` and ``hold_time_minutes``.
799
- :param repetitions: The number of times to repeat the cycled steps.
800
- :param block_max_volume: The greatest volume of liquid contained in any
801
- individual well of the loaded labware, in µL.
802
- If not specified, the default is 25 µL.
803
- """
804
- repetitions = validation.ensure_thermocycler_repetition_count(repetitions)
805
- validated_steps = validation.ensure_thermocycler_profile_steps(steps)
806
- task = self._core.start_execute_profile(
807
- steps=validated_steps,
808
- repetitions=repetitions,
809
- block_max_volume=block_max_volume,
810
- )
811
- return Task(api_version=self._api_version, core=task)
812
-
813
742
  @publish(command=cmds.thermocycler_deactivate_lid)
814
743
  @requires_version(2, 0)
815
744
  def deactivate_lid(self) -> None:
@@ -931,19 +860,6 @@ class ThermocyclerContext(ModuleContext):
931
860
  """Index of the current step within the current cycle"""
932
861
  return self._core.get_current_step_index()
933
862
 
934
- def _get_current_labware_max_vol(self) -> Optional[float]:
935
- max_vol: Optional[float] = None
936
- if self.labware is not None:
937
- for well in self.labware.wells():
938
- if well.has_tracked_liquid():
939
- # make sure that max vol is a float first if we have liquid
940
- max_vol = 0.0 if max_vol is None else max_vol
941
- well_vol = well.current_liquid_volume()
942
- # ignore simulated probe results
943
- if isinstance(well_vol, float):
944
- max_vol = max(max_vol, well_vol)
945
- return max_vol
946
-
947
863
 
948
864
  class HeaterShakerContext(ModuleContext):
949
865
  """An object representing a connected Heater-Shaker Module.
@@ -1057,21 +973,18 @@ class HeaterShakerContext(ModuleContext):
1057
973
 
1058
974
  @requires_version(2, 13)
1059
975
  @publish(command=cmds.heater_shaker_set_target_temperature)
1060
- def set_target_temperature(self, celsius: float) -> Task:
976
+ def set_target_temperature(self, celsius: float) -> None:
1061
977
  """Set target temperature and return immediately.
1062
978
 
1063
979
  Sets the Heater-Shaker's target temperature and returns immediately without
1064
980
  waiting for the target to be reached. Does not delay the protocol until
1065
981
  target temperature has reached.
1066
982
  Use :py:meth:`~.HeaterShakerContext.wait_for_temperature` to delay
1067
- protocol execution for api levels below 2.27.
983
+ protocol execution.
1068
984
 
1069
985
  .. versionchanged:: 2.25
1070
986
  Removed the minimum temperature limit of 37 °C. Note that temperatures under ambient are
1071
987
  not achievable.
1072
- .. versionchanged:: 2.27
1073
- Returns a task object that represents concurrent preheating.
1074
- Pass the task object to :py:meth:`ProtocolContext.wait_for_tasks` to wait for the preheat to complete.
1075
988
 
1076
989
  :param celsius: A value under 95, representing the target temperature in °C.
1077
990
  Values are automatically truncated to two decimal places,
@@ -1080,11 +993,7 @@ class HeaterShakerContext(ModuleContext):
1080
993
  validated_temp = validate_heater_shaker_temperature(
1081
994
  celsius=celsius, api_version=self.api_version
1082
995
  )
1083
- task = self._core.set_target_temperature(celsius=validated_temp)
1084
- if self._api_version >= APIVersion(2, 27):
1085
- return Task(api_version=self._api_version, core=task)
1086
- else:
1087
- return cast(Task, None)
996
+ self._core.set_target_temperature(celsius=validated_temp)
1088
997
 
1089
998
  @requires_version(2, 13)
1090
999
  @publish(command=cmds.heater_shaker_wait_for_temperature)
@@ -1112,21 +1021,6 @@ class HeaterShakerContext(ModuleContext):
1112
1021
  validated_speed = validate_heater_shaker_speed(rpm=rpm)
1113
1022
  self._core.set_and_wait_for_shake_speed(rpm=validated_speed)
1114
1023
 
1115
- @requires_version(2, 27)
1116
- @publish(command=cmds.heater_shaker_set_shake_speed)
1117
- def set_shake_speed(self, rpm: int) -> Task:
1118
- """Set a shake speed in rpm to run in the background.
1119
-
1120
- .. note::
1121
-
1122
- Before shaking, this command will retract the pipettes upward if they are parked adjacent to the Heater-Shaker.
1123
-
1124
- :param rpm: A value between 200 and 3000, representing the target shake speed in revolutions per minute.
1125
- """
1126
- validated_speed = validate_heater_shaker_speed(rpm=rpm)
1127
- task = self._core.set_shake_speed(rpm=validated_speed)
1128
- return Task(api_version=self._api_version, core=task)
1129
-
1130
1024
  @requires_version(2, 13)
1131
1025
  @publish(command=cmds.heater_shaker_open_labware_latch)
1132
1026
  def open_labware_latch(self) -> None:
@@ -1444,7 +1338,7 @@ class FlexStackerContext(ModuleContext):
1444
1338
  def set_stored_labware_items(
1445
1339
  self,
1446
1340
  labware: list[Labware],
1447
- stacking_offset_z: float | None,
1341
+ stacking_offset_z: float | None = None,
1448
1342
  ) -> None:
1449
1343
  """Configure the labware the Flex Stacker will store during a protocol by providing an initial list of stored labware objects. The start of the list represents the bottom of the Stacker,
1450
1344
  and the end of the list represents the top of the Stacker.
@@ -1573,16 +1467,61 @@ class FlexStackerContext(ModuleContext):
1573
1467
  - Labware with lid and adapter: the adapter (bottom side) of the upper labware unit overlaps with the lid (top side) of the unit below.
1574
1468
  """
1575
1469
 
1470
+ if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
1471
+ if adapter_namespace is not None:
1472
+ raise APIVersionError(
1473
+ api_element="The `adapter_namespace` parameter",
1474
+ until_version=str(
1475
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1476
+ ),
1477
+ current_version=str(self._api_version),
1478
+ )
1479
+ if adapter_version is not None:
1480
+ raise APIVersionError(
1481
+ api_element="The `adapter_version` parameter",
1482
+ until_version=str(
1483
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1484
+ ),
1485
+ current_version=str(self._api_version),
1486
+ )
1487
+ if lid_namespace is not None:
1488
+ raise APIVersionError(
1489
+ api_element="The `lid_namespace` parameter",
1490
+ until_version=str(
1491
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1492
+ ),
1493
+ current_version=str(self._api_version),
1494
+ )
1495
+ if lid_version is not None:
1496
+ raise APIVersionError(
1497
+ api_element="The `lid_version` parameter",
1498
+ until_version=str(
1499
+ validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE
1500
+ ),
1501
+ current_version=str(self._api_version),
1502
+ )
1503
+
1504
+ if self._api_version < validation.NAMESPACE_VERSION_ADAPTER_LID_VERSION_GATE:
1505
+ checked_adapter_namespace = namespace
1506
+ checked_adapter_version = version
1507
+ checked_lid_namespace = namespace
1508
+ checked_lid_version = version
1509
+ else:
1510
+ checked_adapter_namespace = adapter_namespace
1511
+ checked_adapter_version = adapter_version
1512
+ checked_lid_namespace = lid_namespace
1513
+ checked_lid_version = lid_version
1514
+
1576
1515
  self._core.set_stored_labware(
1577
1516
  main_load_name=load_name,
1578
1517
  main_namespace=namespace,
1579
1518
  main_version=version,
1580
1519
  lid_load_name=lid,
1581
- lid_namespace=lid_namespace,
1582
- lid_version=lid_version,
1520
+ lid_namespace=checked_lid_namespace,
1521
+ lid_version=checked_lid_version,
1583
1522
  adapter_load_name=adapter,
1584
- adapter_namespace=adapter_namespace,
1585
- adapter_version=adapter_version,
1523
+ adapter_namespace=checked_adapter_namespace,
1524
+ adapter_version=checked_adapter_version,
1586
1525
  count=count,
1587
1526
  stacking_offset_z=stacking_offset_z,
1588
1527
  )
@@ -89,7 +89,6 @@ from .module_contexts import (
89
89
  FlexStackerContext,
90
90
  ModuleContext,
91
91
  )
92
- from .tasks import Task
93
92
  from ._parameters import Parameters
94
93
 
95
94
 
@@ -235,7 +234,10 @@ class ProtocolContext(CommandPublisher):
235
234
  @property
236
235
  @requires_version(2, 22)
237
236
  def robot(self) -> RobotContext:
238
- """The :py:class:`.RobotContext` for the protocol."""
237
+ """The :py:class:`.RobotContext` for the protocol.
238
+
239
+ :meta private:
240
+ """
239
241
  if self._core.robot_type != "OT-3 Standard" or not self._robot:
240
242
  raise RobotTypeError("The RobotContext is only available on Flex robots.")
241
243
  return self._robot
@@ -1287,30 +1289,6 @@ class ProtocolContext(CommandPublisher):
1287
1289
  delay_time = seconds + minutes * 60
1288
1290
  self._core.delay(seconds=delay_time, msg=msg)
1289
1291
 
1290
- @publish(command=cmds.wait_for_tasks)
1291
- @requires_version(2, 27)
1292
- def wait_for_tasks(self, tasks: list[Task]) -> None:
1293
- """Wait for a list of tasks to complete before executing subsequent commands.
1294
-
1295
- :param list Task: tasks: A list of Task objects to wait for.
1296
-
1297
- Task objects can be commands that are allowed to run concurrently.
1298
- """
1299
- task_cores = [task._core for task in tasks]
1300
- self._core.wait_for_tasks(task_cores)
1301
-
1302
- @publish(command=cmds.create_timer)
1303
- @requires_version(2, 27)
1304
- def create_timer(self, seconds: float) -> Task:
1305
- """Create a timer task that runs in the background.
1306
-
1307
- :param float seconds: The time to delay in seconds.
1308
-
1309
- This timer will continue to run until it is complete and will not block subsequent commands.
1310
- """
1311
- task_core = self._core.create_timer(seconds=seconds)
1312
- return Task(core=task_core, api_version=self._api_version)
1313
-
1314
1292
  @requires_version(2, 0)
1315
1293
  def home(self) -> None:
1316
1294
  """Home the movement system of the robot."""
@@ -46,7 +46,7 @@ class RobotContext(publisher.CommandPublisher):
46
46
  Objects in this class should not be instantiated directly. Instead, instances are
47
47
  returned by :py:meth:`ProtocolContext.robot`.
48
48
 
49
- .. versionadded:: 2.22
49
+ .. versionadded:: 2.20
50
50
 
51
51
  """
52
52
 
@@ -83,19 +83,15 @@ class RobotContext(publisher.CommandPublisher):
83
83
  speed: Optional[float] = None,
84
84
  ) -> None:
85
85
  """
86
- Move a specified mount to a location on the deck.
86
+ Move a specified mount to a destination location on the deck.
87
87
 
88
88
  :param mount: The mount of the instrument you wish to move.
89
89
  This can either be an instance of :py:class:`.types.Mount` or one
90
90
  of the strings ``"left"``, ``"right"``, ``"extension"``, ``"gripper"``. Note
91
91
  that the gripper mount can be referred to either as ``"extension"`` or ``"gripper"``.
92
92
  :type mount: types.Mount or str
93
- :param destination: Any location on the deck, specified as:
94
-
95
- - a slot, like ``"A1"``
96
- - a defined location, like labware in a deck slot
97
- - an absolute location, like a point {x=10 , y=10, z=10} or a deck location and point ("A1" + point {x=10 , y=10, z=10})
98
- :param speed: The absolute speed in mm/s.
93
+ :param Location destination:
94
+ :param speed:
99
95
  """
100
96
  mount = validation.ensure_instrument_mount(mount)
101
97
  with publisher.publish_context(
@@ -120,9 +116,10 @@ class RobotContext(publisher.CommandPublisher):
120
116
  Move a set of axes to an absolute position on the deck.
121
117
 
122
118
  :param axis_map: A dictionary mapping axes to an absolute position on the deck in mm.
123
- :param critical_point: The critical point, or specific point on the object being moved, to move the axes with. It should only specify the gantry axes (i.e. `x`, `y`, `z`). When you specify a critical point, you're specifying the object on the gantry to be moved. If not specified, the critical point defaults to the center of the carriage attached to the gantry.
124
- :param float speed: The maximum speed with which to move all axes in mm/s.
125
-
119
+ :param critical_point: The critical point to move the axes with. It should only
120
+ specify the gantry axes (i.e. `x`, `y`, `z`).
121
+ :param float speed: The maximum speed with which you want to move all the axes
122
+ in the axis map.
126
123
  """
127
124
  instrument_on_left = self._core.get_pipette_type_from_engine(Mount.LEFT)
128
125
  is_96_channel = instrument_on_left == PipetteNameType.P1000_96
@@ -157,9 +154,11 @@ class RobotContext(publisher.CommandPublisher):
157
154
  """
158
155
  Move a set of axes to a relative position on the deck.
159
156
 
160
- :param axis_map: A dictionary mapping axes to relative movements from the current position in mm.
157
+ :param axis_map: A dictionary mapping axes to relative movements in mm.
158
+ :type mount: types.Mount or str
161
159
 
162
- :param float speed: The maximum speed with which to move all axes in mm/s.
160
+ :param float speed: The maximum speed with which you want to move all the axes
161
+ in the axis map.
163
162
  """
164
163
  instrument_on_left = self._core.get_pipette_type_from_engine(Mount.LEFT)
165
164
  is_96_channel = instrument_on_left == PipetteNameType.P1000_96
@@ -178,10 +177,7 @@ class RobotContext(publisher.CommandPublisher):
178
177
  self._core.move_axes_relative(axis_map, speed)
179
178
 
180
179
  def close_gripper_jaw(self, force: Optional[float] = None) -> None:
181
- """Closes the Flex Gripper jaws with a specified force.
182
-
183
- :param force: Force with which to close the gripper jaws in newtons.
184
- """
180
+ """Command the gripper closed with some force."""
185
181
  with publisher.publish_context(
186
182
  broker=self.broker,
187
183
  command=cmds.close_gripper(
@@ -191,10 +187,7 @@ class RobotContext(publisher.CommandPublisher):
191
187
  self._core.close_gripper(force)
192
188
 
193
189
  def open_gripper_jaw(self) -> None:
194
- """Opens the Flex Gripper jaws with a specified force.
195
-
196
- :param force: Force with which to open the gripper jaws in newtons.
197
- """
190
+ """Command the gripper open."""
198
191
  with publisher.publish_context(
199
192
  broker=self.broker,
200
193
  command=cmds.open_gripper(),
@@ -207,9 +200,9 @@ class RobotContext(publisher.CommandPublisher):
207
200
  location: Union[Location, ModuleContext, DeckLocation],
208
201
  ) -> AxisMapType:
209
202
  """
210
- Build an axis map from a location to provide to
203
+ Build a :py:class:`.types.AxisMapType` from a location to be compatible with
211
204
  either :py:meth:`.RobotContext.move_axes_to` or :py:meth:`.RobotContext.move_axes_relative`.
212
- You must provide only one of either a `location`, `slot`, or `module` to build
205
+ You must provide only one of `location`, `slot`, or `module` to build
213
206
  the axis map.
214
207
 
215
208
  :param mount: The mount of the instrument you wish create an axis map for.
@@ -217,10 +210,7 @@ class RobotContext(publisher.CommandPublisher):
217
210
  of the strings ``"left"``, ``"right"``, ``"extension"``, ``"gripper"``. Note
218
211
  that the gripper mount can be referred to either as ``"extension"`` or ``"gripper"``.
219
212
  :type mount: types.Mount or str
220
- :param location: Any location on the deck, specified as:
221
-
222
- - a deck location, like slot ``"A1"``.
223
- - a defined location, like a module on the deck.
213
+ :param location: The location to format an axis map for.
224
214
  :type location: `Well`, `ModuleContext`, `DeckLocation` or `OffDeckType`
225
215
  """
226
216
  mount = validation.ensure_instrument_mount(mount)
@@ -258,11 +248,7 @@ class RobotContext(publisher.CommandPublisher):
258
248
  self, mount: Union[Mount, str], volume: float, action: PipetteActionTypes
259
249
  ) -> AxisMapType:
260
250
  """
261
- Build an axis map to move a pipette plunger motor to complete liquid handling actions.
262
-
263
- :mount: The left or right instrument mount the pipette is attached to.
264
- :param volume: A volume to convert to an axis map for linear plunger displacement.
265
- :param action: Choose to ``aspirate`` or ``dispense``.
251
+ Build a :py:class:`.types.AxisMapType` for a pipette plunger motor from volume.
266
252
 
267
253
  """
268
254
  pipette_name = self._core.get_pipette_type_from_engine(mount)
@@ -282,9 +268,7 @@ class RobotContext(publisher.CommandPublisher):
282
268
  self, mount: Union[Mount, str], position_name: PlungerPositionTypes
283
269
  ) -> AxisMapType:
284
270
  """
285
- Build an axis map to move a pipette plunger motor to a named position.
286
-
287
- :param position_name: A named position to move the pipette plunger to. Choose from ``top``, ``bottom``, ``blowout``, or ``drop`` plunger positions.
271
+ Build a :py:class:`.types.AxisMapType` for a pipette plunger motor from position_name.
288
272
 
289
273
  """
290
274
  pipette_name = self._core.get_pipette_type_from_engine(mount)
@@ -300,9 +284,8 @@ class RobotContext(publisher.CommandPublisher):
300
284
  return {pipette_axis: pipette_position}
301
285
 
302
286
  def build_axis_map(self, axis_map: StringAxisMap) -> AxisMapType:
303
- """Take in a :py:class:`.types.StringAxisMap` and output an axis map.
304
-
305
- The :py:class:`.types.StringAxisMap` is allowed to contain any of the following strings:
287
+ """Take in a :py:class:`.types.StringAxisMap` and output a :py:class:`.types.AxisMapType`.
288
+ A :py:class:`.types.StringAxisMap` is allowed to contain any of the following strings:
306
289
  ``"x"``, ``"y"``, "``z_l"``, "``z_r"``, "``z_g"``, ``"q"``.
307
290
 
308
291
  An example of a valid axis map could be:
@@ -489,7 +489,6 @@ def ensure_thermocycler_profile_steps(
489
489
  temperature = step.get("temperature")
490
490
  hold_mins = step.get("hold_time_minutes")
491
491
  hold_secs = step.get("hold_time_seconds")
492
- ramp_rate = step.get("ramp_rate")
493
492
  if temperature is None:
494
493
  raise ValueError("temperature must be defined for each step in cycle")
495
494
  if hold_mins is None and hold_secs is None:
@@ -497,14 +496,10 @@ def ensure_thermocycler_profile_steps(
497
496
  "either hold_time_minutes or hold_time_seconds must be"
498
497
  "defined for each step in cycle"
499
498
  )
500
- if ramp_rate is not None and ramp_rate <= 0:
501
- raise ValueError("Ramp rate must be greater than 0.")
502
499
  validated_seconds = ensure_hold_time_seconds(hold_secs, hold_mins)
503
500
  validated_steps.append(
504
501
  ThermocyclerStep(
505
- temperature=temperature,
506
- hold_time_seconds=validated_seconds,
507
- ramp_rate=ramp_rate,
502
+ temperature=temperature, hold_time_seconds=validated_seconds
508
503
  )
509
504
  )
510
505
  return validated_steps
@@ -26,9 +26,8 @@ from .actions import (
26
26
  AddModuleAction,
27
27
  FinishErrorDetails,
28
28
  DoorChangeAction,
29
+ ResetTipsAction,
29
30
  SetPipetteMovementSpeedAction,
30
- StartTaskAction,
31
- FinishTaskAction,
32
31
  )
33
32
  from .get_state_update import get_state_updates
34
33
 
@@ -56,9 +55,8 @@ __all__ = [
56
55
  "AddAddressableAreaAction",
57
56
  "AddModuleAction",
58
57
  "DoorChangeAction",
58
+ "ResetTipsAction",
59
59
  "SetPipetteMovementSpeedAction",
60
- "StartTaskAction",
61
- "FinishTaskAction",
62
60
  # action payload values
63
61
  "PauseSource",
64
62
  "FinishErrorDetails",