opentrons 8.4.0a9__py2.py3-none-any.whl → 8.4.0a11__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2283,6 +2283,13 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
2283
2283
  well_location = WellLocation(
2284
2284
  origin=WellOrigin.TOP, offset=WellOffset(x=offset.x, y=offset.y, z=offset.z)
2285
2285
  )
2286
+ pipette_movement_conflict.check_safe_for_pipette_movement(
2287
+ engine_state=self._engine_client.state,
2288
+ pipette_id=self._pipette_id,
2289
+ labware_id=labware_id,
2290
+ well_name=well_name,
2291
+ well_location=well_location,
2292
+ )
2286
2293
  self._engine_client.execute_command(
2287
2294
  cmd.LiquidProbeParams(
2288
2295
  labwareId=labware_id,
@@ -2303,6 +2310,13 @@ class InstrumentCore(AbstractInstrument[WellCore, LabwareCore]):
2303
2310
  well_location = WellLocation(
2304
2311
  origin=WellOrigin.TOP, offset=WellOffset(x=0, y=0, z=2)
2305
2312
  )
2313
+ pipette_movement_conflict.check_safe_for_pipette_movement(
2314
+ engine_state=self._engine_client.state,
2315
+ pipette_id=self._pipette_id,
2316
+ labware_id=labware_id,
2317
+ well_name=well_name,
2318
+ well_location=well_location,
2319
+ )
2306
2320
  result = self._engine_client.execute_command_without_recovery(
2307
2321
  cmd.LiquidProbeParams(
2308
2322
  labwareId=labware_id,
@@ -197,12 +197,14 @@ class WellCore(AbstractWellCore):
197
197
  raise PipetteNotAttachedError(f"No pipette present on mount {mount}")
198
198
  pipette_id = pipette_from_mount.id
199
199
  starting_liquid_height = self.current_liquid_height()
200
- projected_final_height = self._engine_client.state.geometry.get_well_height_after_liquid_handling_no_error(
201
- labware_id=labware_id,
202
- well_name=well_name,
203
- pipette_id=pipette_id,
204
- initial_height=starting_liquid_height,
205
- volume=operation_volume,
200
+ projected_final_height = (
201
+ self._engine_client.state.geometry.get_well_height_after_liquid_handling(
202
+ labware_id=labware_id,
203
+ well_name=well_name,
204
+ pipette_id=pipette_id,
205
+ initial_height=starting_liquid_height,
206
+ volume=operation_volume,
207
+ )
206
208
  )
207
209
  return projected_final_height
208
210
 
@@ -2085,12 +2085,10 @@ class InstrumentContext(publisher.CommandPublisher):
2085
2085
  to the volume of liquid that will be dispensed.
2086
2086
  :type volume: float
2087
2087
 
2088
- :param rate: How quickly the plunger moves to displace the commanded volume. The plunger speed
2089
- in µL/s is calculated as ``rate`` multiplied by
2090
- :py:attr:`flow_rate.dispense<flow_rate>`. This rate does not directly relate to
2088
+ :param rate: How quickly the plunger moves to displace the commanded volume, in µL/s. This rate does not directly relate to
2091
2089
  the flow rate of liquid out of the resin tip.
2092
2090
 
2093
- The default value of ``10.0`` is recommended.
2091
+ Defaults to ``10.0`` µL/s.
2094
2092
  :type rate: float
2095
2093
  """
2096
2094
  well: Optional[labware.Well] = None
@@ -423,7 +423,8 @@ def _find_height_in_partial_frustum(
423
423
  # if we finish looping through the whole well, bottom_section will be the well's volume
424
424
  total_well_volume = bottom_section_volume
425
425
  # if we've looked through all sections and can't find the target volume, raise an error
426
- # also this code should never be reached bc an error should be raised by find_height_at_well_volume
426
+ # also this code should never be reached bc an invalid target volume should be changed
427
+ # by find_height_at_well_volume
427
428
  raise InvalidLiquidHeightFound(
428
429
  f"Target volume {target_volume} uL exceeds the well volume {total_well_volume} uL."
429
430
  )
@@ -432,7 +433,6 @@ def _find_height_in_partial_frustum(
432
433
  def find_height_at_well_volume(
433
434
  target_volume: LiquidTrackingType,
434
435
  well_geometry: InnerWellGeometry,
435
- raise_error_if_result_invalid: bool = True,
436
436
  ) -> LiquidTrackingType:
437
437
  """Find the height within a well, at a known volume."""
438
438
  # comparisons with SimulatedProbeResult objects aren't meaningful, just
@@ -443,12 +443,10 @@ def find_height_at_well_volume(
443
443
  volumetric_capacity = get_well_volumetric_capacity(well_geometry)
444
444
  max_volume = sum(row[1] for row in volumetric_capacity)
445
445
 
446
- if raise_error_if_result_invalid:
447
- if target_volume < 0 or target_volume > max_volume:
448
- raise InvalidLiquidHeightFound(
449
- f"Invalid target volume {target_volume} uL; max volume is {max_volume} uL"
450
- )
451
-
446
+ if target_volume < 0:
447
+ target_volume = 0
448
+ elif target_volume > max_volume:
449
+ target_volume = max_volume
452
450
  sorted_well = sorted(well_geometry.sections, key=lambda section: section.topHeight)
453
451
  # find the section the target volume is in and compute the height
454
452
  return _find_height_in_partial_frustum(
@@ -7,7 +7,6 @@ from numpy.typing import NDArray
7
7
  from typing import Optional, List, Tuple, Union, cast, TypeVar, Dict, Set
8
8
  from dataclasses import dataclass
9
9
  from functools import cached_property
10
- from math import isclose
11
10
 
12
11
  from opentrons.types import (
13
12
  Point,
@@ -33,7 +32,6 @@ from ..errors import (
33
32
  LabwareNotLoadedOnLabwareError,
34
33
  LabwareNotLoadedOnModuleError,
35
34
  LabwareMovementNotAllowedError,
36
- OperationLocationNotInWellError,
37
35
  InvalidLabwarePositionError,
38
36
  LabwareNotOnDeckError,
39
37
  )
@@ -522,39 +520,23 @@ class GeometryView:
522
520
  z=origin_pos.z + cal_offset.z,
523
521
  )
524
522
 
525
- def validate_well_position(
523
+ def _validate_well_position(
526
524
  self,
527
- well_location: WellLocationType,
528
- z_offset: float,
529
- pipette_id: Optional[str] = None,
530
- ) -> None:
531
- """Raise exception if operation location is not within well.
532
-
533
- Primarily this checks if there is not enough liquid in a well to do meniscus-relative static aspiration.
534
- """
535
- if well_location.origin == WellOrigin.MENISCUS:
536
- assert pipette_id is not None, "pipette id is None"
537
- lld_min_height = self._pipettes.get_current_tip_lld_settings(
538
- pipette_id=pipette_id
539
- )
540
- if z_offset < lld_min_height:
541
- if isinstance(well_location, LiquidHandlingWellLocation):
542
- raise OperationLocationNotInWellError(
543
- f"Specifying {well_location.origin} with a height offset of {well_location.offset.z} results in a height of {z_offset} mm; the minimum allowed height for liquid tracking is {lld_min_height} mm"
544
- )
545
- else:
546
- raise OperationLocationNotInWellError(
547
- f"Specifying {well_location.origin} with an offset of {well_location.offset} results in an operation location that could be below the bottom of the well"
548
- )
549
- elif z_offset < 0 and not isclose(z_offset, 0, abs_tol=0.0000001):
550
- if isinstance(well_location, LiquidHandlingWellLocation):
551
- raise OperationLocationNotInWellError(
552
- f"Specifying {well_location.origin} with an offset of {well_location.offset} and a volume offset of {well_location.volumeOffset} results in an operation location below the bottom of the well"
553
- )
554
- else:
555
- raise OperationLocationNotInWellError(
556
- f"Specifying {well_location.origin} with an offset of {well_location.offset} results in an operation location below the bottom of the well"
557
- )
525
+ target_height: LiquidTrackingType, # height in mm inside a well relative to the bottom
526
+ well_max_height: float,
527
+ pipette_id: str,
528
+ ) -> LiquidTrackingType:
529
+ """If well offset would be outside the bounds of a well, silently bring it back to the boundary."""
530
+ if isinstance(target_height, SimulatedProbeResult):
531
+ return target_height
532
+ lld_min_height = self._pipettes.get_current_tip_lld_settings(
533
+ pipette_id=pipette_id
534
+ )
535
+ if target_height < lld_min_height:
536
+ target_height = lld_min_height
537
+ elif target_height > well_max_height:
538
+ target_height = well_max_height
539
+ return target_height
558
540
 
559
541
  def validate_probed_height(
560
542
  self,
@@ -595,7 +577,7 @@ class GeometryView:
595
577
 
596
578
  offset = WellOffset(x=0, y=0, z=well_depth)
597
579
  if well_location is not None:
598
- offset = well_location.offset
580
+ offset = well_location.offset # location of the bottom of the well
599
581
  offset_adjustment = self.get_well_offset_adjustment(
600
582
  labware_id=labware_id,
601
583
  well_name=well_name,
@@ -606,11 +588,6 @@ class GeometryView:
606
588
  )
607
589
  if not isinstance(offset_adjustment, SimulatedProbeResult):
608
590
  offset = offset.model_copy(update={"z": offset.z + offset_adjustment})
609
- self.validate_well_position(
610
- well_location=well_location,
611
- z_offset=offset.z,
612
- pipette_id=pipette_id,
613
- )
614
591
  return Point(
615
592
  x=labware_pos.x + offset.x + well_def.x,
616
593
  y=labware_pos.y + offset.y + well_def.y,
@@ -2107,6 +2084,8 @@ class GeometryView:
2107
2084
 
2108
2085
  This is given an initial handling height, with reference to the well bottom.
2109
2086
  """
2087
+ well_def = self._labware.get_well_definition(labware_id, well_name)
2088
+ well_depth = well_def.depth
2110
2089
  well_geometry = self._labware.get_well_geometry(
2111
2090
  labware_id=labware_id, well_name=well_name
2112
2091
  )
@@ -2122,49 +2101,17 @@ class GeometryView:
2122
2101
  pipette_id=pipette_id,
2123
2102
  )
2124
2103
  )
2125
- return find_height_at_well_volume(
2104
+ # NOTE(cm): if final_volume is outside the bounds of the well, it will get
2105
+ # adjusted inside find_height_at_well_volume to accomodate well the height
2106
+ # calculation.
2107
+ height_inside_well = find_height_at_well_volume(
2126
2108
  target_volume=final_volume, well_geometry=well_geometry
2127
2109
  )
2128
- except InvalidLiquidHeightFound as _exception:
2129
- raise InvalidLiquidHeightFound(
2130
- message=_exception.message
2131
- + f"for well {well_name} of {self._labware.get_display_name(labware_id)} on slot {self.get_ancestor_slot_name(labware_id)}"
2132
- )
2133
-
2134
- def get_well_height_after_liquid_handling_no_error(
2135
- self,
2136
- labware_id: str,
2137
- well_name: str,
2138
- pipette_id: str,
2139
- initial_height: LiquidTrackingType,
2140
- volume: float,
2141
- ) -> LiquidTrackingType:
2142
- """Return what the height of liquid in a labware well after liquid handling will be.
2143
-
2144
- This raises no error if the value returned is an invalid physical location, so it should never be
2145
- used for navigation, only for a pre-emptive estimate.
2146
- """
2147
- well_geometry = self._labware.get_well_geometry(
2148
- labware_id=labware_id, well_name=well_name
2149
- )
2150
- try:
2151
- initial_volume = find_volume_at_well_height(
2152
- target_height=initial_height, well_geometry=well_geometry
2153
- )
2154
- final_volume = initial_volume + (
2155
- volume
2156
- * self.get_nozzles_per_well(
2157
- labware_id=labware_id,
2158
- target_well_name=well_name,
2159
- pipette_id=pipette_id,
2160
- )
2161
- )
2162
- well_volume = find_height_at_well_volume(
2163
- target_volume=final_volume,
2164
- well_geometry=well_geometry,
2165
- raise_error_if_result_invalid=False,
2110
+ return self._validate_well_position(
2111
+ target_height=height_inside_well,
2112
+ well_max_height=well_depth,
2113
+ pipette_id=pipette_id,
2166
2114
  )
2167
- return well_volume
2168
2115
  except InvalidLiquidHeightFound as _exception:
2169
2116
  raise InvalidLiquidHeightFound(
2170
2117
  message=_exception.message
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: opentrons
3
- Version: 8.4.0a9
3
+ Version: 8.4.0a11
4
4
  Summary: The Opentrons API is a simple framework designed to make writing automated biology lab protocols easy.
5
5
  Author: Opentrons
6
6
  Author-email: engineering@opentrons.com
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.10
21
21
  Classifier: Topic :: Scientific/Engineering
22
22
  Requires-Python: >=3.10
23
23
  License-File: ../LICENSE
24
- Requires-Dist: opentrons-shared-data (==8.4.0a9)
24
+ Requires-Dist: opentrons-shared-data (==8.4.0a11)
25
25
  Requires-Dist: aionotify (==0.3.1)
26
26
  Requires-Dist: anyio (<4.0.0,>=3.6.1)
27
27
  Requires-Dist: jsonschema (<4.18.0,>=3.0.1)
@@ -35,9 +35,9 @@ Requires-Dist: pyusb (==1.2.1)
35
35
  Requires-Dist: packaging (>=21.0)
36
36
  Requires-Dist: importlib-metadata (>=1.0) ; python_version < "3.8"
37
37
  Provides-Extra: flex-hardware
38
- Requires-Dist: opentrons-hardware[flex] (==8.4.0a9) ; extra == 'flex-hardware'
38
+ Requires-Dist: opentrons-hardware[flex] (==8.4.0a11) ; extra == 'flex-hardware'
39
39
  Provides-Extra: ot2-hardware
40
- Requires-Dist: opentrons-hardware (==8.4.0a9) ; extra == 'ot2-hardware'
40
+ Requires-Dist: opentrons-hardware (==8.4.0a11) ; extra == 'ot2-hardware'
41
41
 
42
42
  .. _Full API Documentation: http://docs.opentrons.com
43
43
 
@@ -228,7 +228,7 @@ opentrons/protocol_api/config.py,sha256=r9lyvXjagTX_g3q5FGURPpcz2IA9sSF7Oa_1mKx-
228
228
  opentrons/protocol_api/create_protocol_context.py,sha256=wwsZje0L__oDnu1Yrihau320_f-ASloR9eL1QCtkOh8,7612
229
229
  opentrons/protocol_api/deck.py,sha256=94vFceg1SC1bAGd7TvC1ZpYwnJR-VlzurEZ6jkacYeg,8910
230
230
  opentrons/protocol_api/disposal_locations.py,sha256=NRiSGmDR0LnbyEkWSOM-o64uR2fUoB1NWJG7Y7SsJSs,7920
231
- opentrons/protocol_api/instrument_context.py,sha256=wqQ_un5E_sLjhwwNsp2qF_GTD0lajlrBG68JE7WgbPY,120913
231
+ opentrons/protocol_api/instrument_context.py,sha256=6KW5cQ-G0HOrYTMH7835dEqMJZ2F2yPH48sl0Eu9eW8,120754
232
232
  opentrons/protocol_api/labware.py,sha256=KRt91dOzmCX6l8LQ5Wny7kIk_L0Y69Uzpolp-geE0MY,60458
233
233
  opentrons/protocol_api/module_contexts.py,sha256=3tVXj6Q7n-WuTJPU_dvIQLzzGv1P-jsMuDtMVpuhAf8,48291
234
234
  opentrons/protocol_api/module_validation_and_errors.py,sha256=XL_m72P8rcvGO2fynY7UzXLcpGuI6X4s0V6Xf735Iyc,1464
@@ -248,7 +248,7 @@ opentrons/protocol_api/core/well_grid.py,sha256=BU28DKaBgEU_JdZ6pEzrwNxmuh6TkO4z
248
248
  opentrons/protocol_api/core/engine/__init__.py,sha256=B_5T7zgkWDb1mXPg4NbT-wBkQaK-WVokMMnJRNu7xiM,582
249
249
  opentrons/protocol_api/core/engine/deck_conflict.py,sha256=q3JViIAHDthIqq6ce7h2gxw3CHRfYsm5kkwzuXB-Gnc,12334
250
250
  opentrons/protocol_api/core/engine/exceptions.py,sha256=aZgNrmYEeuPZm21nX_KZYtvyjv5h_zPjxxgPkEV7_bw,725
251
- opentrons/protocol_api/core/engine/instrument.py,sha256=jh3QIqGYDFMoJIrgZLq-IR2liqEhq5aCQgh5xomW3P8,95884
251
+ opentrons/protocol_api/core/engine/instrument.py,sha256=A6ku8gzJBUGpi9qcLSsuJxZavtzUVhWxw8RHCasY5a8,96442
252
252
  opentrons/protocol_api/core/engine/labware.py,sha256=1xvzguNnK7aecFLiJK0gtRrZ5kpwtzLS73HnKvdJ5lc,8413
253
253
  opentrons/protocol_api/core/engine/load_labware_params.py,sha256=I4Cb8rqpBhmykQuZE8QRG802APrdCy_TYS88rm_9oGA,7159
254
254
  opentrons/protocol_api/core/engine/module_core.py,sha256=MLPgYSRJHUZPZ9rTLvsg3GlpL5b6-Pjk5UBgXCGrL6U,30994
@@ -259,7 +259,7 @@ opentrons/protocol_api/core/engine/protocol.py,sha256=_1gdg4lq2B21LWV9Tqb924E39H
259
259
  opentrons/protocol_api/core/engine/robot.py,sha256=o252HrC11tmZ5LRKT6NwXCoTeqcQFXHeNjszfxbJHjo,5366
260
260
  opentrons/protocol_api/core/engine/stringify.py,sha256=GwFgEhFMk-uPfFQhQG_2mkaf4cxaItiY8RW7rZwiooQ,2794
261
261
  opentrons/protocol_api/core/engine/transfer_components_executor.py,sha256=96SsftBRPB5WCeChLokXkdPJcmjP8FqlXEZXhNAlZKA,37582
262
- opentrons/protocol_api/core/engine/well.py,sha256=o4Qm25AvZwd4ytR3IpK4wH-BwAmzt_7fVIKQsbHMsgg,8122
262
+ opentrons/protocol_api/core/engine/well.py,sha256=9_BgB8O7gE4Y3XgoyJMNtcZasgxSPqDEyAzrQjI60qU,8161
263
263
  opentrons/protocol_api/core/legacy/__init__.py,sha256=_9jCJNKG3SlS_vljVu8HHkZmtLf4F-f-JHALLF5d5go,401
264
264
  opentrons/protocol_api/core/legacy/deck.py,sha256=qHqcGo-Kdkl9L1aOE0pwrm9tsAnwkXbt4rIOr_VEP-s,13955
265
265
  opentrons/protocol_api/core/legacy/labware_offset_provider.py,sha256=2DLIby9xmUrwLb2ht8hZbvNTxqPhNzWijd7yCb2cqP8,3783
@@ -449,8 +449,8 @@ opentrons/protocol_engine/state/commands.py,sha256=aoON_C5DbiIEPxOGATvwCsSG9eHsF
449
449
  opentrons/protocol_engine/state/config.py,sha256=7jSGxC6Vqj1eA8fqZ2I3zjlxVXg8pxvcBYMztRIx9Mg,1515
450
450
  opentrons/protocol_engine/state/files.py,sha256=w8xxxg8HY0RqKKEGSfHWfrjV54Gb02O3dwtisJ-9j8E,1753
451
451
  opentrons/protocol_engine/state/fluid_stack.py,sha256=uwkf0qYk1UX5iU52xmk-e3yLPK8OG-TtMCcBqrkVFpM,5932
452
- opentrons/protocol_engine/state/frustum_helpers.py,sha256=uRBLLR75Z_PnfVd-U7gPF3NeOALR3TgLNCojgxB4z0o,17343
453
- opentrons/protocol_engine/state/geometry.py,sha256=v5saIiG6nwMSq_bWXcZUsmOabmHJjG80s7RdxaX-DUg,101235
452
+ opentrons/protocol_engine/state/frustum_helpers.py,sha256=0xWDgYV_FyGKRmae3_5dKY6OJbRgvjC-veEFuZj_0-4,17194
453
+ opentrons/protocol_engine/state/geometry.py,sha256=dDCrhiyYUn-0KxEVHrIoN0V_jBDV1DFJ5f3XIjp_ZLk,98690
454
454
  opentrons/protocol_engine/state/labware.py,sha256=rehy7R1HIhxx3DTtTHIKxqHoBQJ_1tDhhiculMJeIy8,57556
455
455
  opentrons/protocol_engine/state/liquid_classes.py,sha256=u_z75UYdiFAKG0yB3mr1il4T3qaS0Sotq8sL7KLODP8,2990
456
456
  opentrons/protocol_engine/state/liquids.py,sha256=NoesktcQdJUjIVmet1uqqJPf-rzbo4SGemXwQC295W0,2338
@@ -583,9 +583,9 @@ opentrons/util/linal.py,sha256=IlKAP9HkNBBgULeSf4YVwSKHdx9jnCjSr7nvDvlRALg,5753
583
583
  opentrons/util/logging_config.py,sha256=7et4YYuQdWdq_e50U-8vFS_QyNBRgdnqPGAQJm8qrIo,9954
584
584
  opentrons/util/logging_queue_handler.py,sha256=ZsSJwy-oV8DXwpYiZisQ1PbYwmK2cOslD46AcyJ1E4I,2484
585
585
  opentrons/util/performance_helpers.py,sha256=ew7H8XD20iS6-2TJAzbQeyzStZkkE6PzHt_Adx3wbZQ,5172
586
- opentrons-8.4.0a9.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
587
- opentrons-8.4.0a9.dist-info/METADATA,sha256=q9nO7VyTyS_ehqIVeJ9SkKhqiDo32Qgai3bDc7n2nxw,5084
588
- opentrons-8.4.0a9.dist-info/WHEEL,sha256=qUzzGenXXuJTzyjFah76kDVqDvnk-YDzY00svnrl84w,109
589
- opentrons-8.4.0a9.dist-info/entry_points.txt,sha256=fTa6eGCYkvOtv0ov-KVE8LLGetgb35LQLF9x85OWPVw,106
590
- opentrons-8.4.0a9.dist-info/top_level.txt,sha256=wk6whpbMZdBQpcK0Fg0YVfUGrAgVOFON7oQAhOMGMW8,10
591
- opentrons-8.4.0a9.dist-info/RECORD,,
586
+ opentrons-8.4.0a11.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
587
+ opentrons-8.4.0a11.dist-info/METADATA,sha256=GLuvrxBIEKihFmoBZK_O5IRINPswDRTAhdzM0IJcuFg,5088
588
+ opentrons-8.4.0a11.dist-info/WHEEL,sha256=qUzzGenXXuJTzyjFah76kDVqDvnk-YDzY00svnrl84w,109
589
+ opentrons-8.4.0a11.dist-info/entry_points.txt,sha256=fTa6eGCYkvOtv0ov-KVE8LLGetgb35LQLF9x85OWPVw,106
590
+ opentrons-8.4.0a11.dist-info/top_level.txt,sha256=wk6whpbMZdBQpcK0Fg0YVfUGrAgVOFON7oQAhOMGMW8,10
591
+ opentrons-8.4.0a11.dist-info/RECORD,,