opentrons 8.4.0a5__py2.py3-none-any.whl → 8.4.0a6__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -2654,7 +2654,7 @@ class InstrumentContext(publisher.CommandPublisher):
2654
2654
  def measure_liquid_height(self, well: labware.Well) -> LiquidTrackingType:
2655
2655
  """Check the height of the liquid within a well.
2656
2656
 
2657
- :returns: The height, in mm, of the liquid from the deck.
2657
+ :returns: The height, in mm, of the liquid from the bottom of the well.
2658
2658
  """
2659
2659
  self._raise_if_pressure_not_supported_by_pipette()
2660
2660
  loc = well.top()
@@ -1,6 +1,6 @@
1
1
  """Tip pickup and drop procedures."""
2
2
 
3
- from typing import Optional, Dict
3
+ from typing import Optional, Dict, Tuple
4
4
  from typing_extensions import Protocol as TypingProtocol
5
5
 
6
6
  from opentrons.hardware_control import HardwareControlAPI
@@ -201,6 +201,18 @@ async def _available_for_nozzle_layout( # noqa: C901
201
201
  }
202
202
 
203
203
 
204
+ def tip_on_left_side_96(back_left_nozzle: str) -> bool:
205
+ """Return if there is a tip on the left edge of the 96 channel."""
206
+ left_most_column = int(back_left_nozzle[1:])
207
+ return left_most_column == 1
208
+
209
+
210
+ def tip_on_right_side_96(front_right_nozzle: str) -> bool:
211
+ """Return if there is a tip on the left edge of the 96 channel."""
212
+ right_most_column = int(front_right_nozzle[1:])
213
+ return right_most_column == 12
214
+
215
+
204
216
  class HardwareTipHandler(TipHandler):
205
217
  """Pick up and drop tips, using the Hardware API."""
206
218
 
@@ -237,6 +249,50 @@ class HardwareTipHandler(TipHandler):
237
249
  channels, style, primary_nozzle, front_right_nozzle, back_left_nozzle
238
250
  )
239
251
 
252
+ def get_tip_presence_config(
253
+ self, pipette_id: str
254
+ ) -> Tuple[bool, Optional[InstrumentProbeType]]:
255
+ """Return the supported settings for tip presence on a given pipette depending on it's current nozzle map."""
256
+ follow_singular_sensor = None
257
+
258
+ unsupported_layout_types_96 = [NozzleConfigurationType.SINGLE]
259
+ # NOTE: (09-20-2024) Current on multi-channel pipettes, utilizing less than 4 nozzles risks false positives on the tip presence sensor
260
+ supported_partial_nozzle_minimum = 4
261
+
262
+ nozzle_configuration = self._state_view.pipettes.get_nozzle_configuration(
263
+ pipette_id=pipette_id
264
+ )
265
+
266
+ match self._state_view.pipettes.get_channels(pipette_id):
267
+ case 1:
268
+ tip_presence_supported = True
269
+ case 8:
270
+ tip_presence_supported = (
271
+ nozzle_configuration.tip_count >= supported_partial_nozzle_minimum
272
+ )
273
+ case 96:
274
+ tip_presence_supported = (
275
+ nozzle_configuration.configuration
276
+ not in unsupported_layout_types_96
277
+ and nozzle_configuration.tip_count
278
+ >= supported_partial_nozzle_minimum
279
+ )
280
+ if (
281
+ nozzle_configuration.configuration != NozzleConfigurationType.FULL
282
+ and tip_presence_supported
283
+ ):
284
+ use_left = tip_on_left_side_96(nozzle_configuration.back_left)
285
+ use_right = tip_on_right_side_96(nozzle_configuration.front_right)
286
+ if not (use_left and use_right):
287
+ if use_left:
288
+ follow_singular_sensor = InstrumentProbeType.PRIMARY
289
+ else:
290
+ follow_singular_sensor = InstrumentProbeType.SECONDARY
291
+ case _:
292
+ raise ValueError("Unknown pipette type.")
293
+
294
+ return (tip_presence_supported, follow_singular_sensor)
295
+
240
296
  async def pick_up_tip(
241
297
  self,
242
298
  pipette_id: str,
@@ -266,9 +322,18 @@ class HardwareTipHandler(TipHandler):
266
322
  await self._hardware_api.tip_pickup_moves(
267
323
  mount=hw_mount, presses=None, increment=None
268
324
  )
269
- if do_not_ignore_tip_presence:
325
+
326
+ tip_presence_supported, follow_singular_sensor = self.get_tip_presence_config(
327
+ pipette_id
328
+ )
329
+
330
+ if do_not_ignore_tip_presence and tip_presence_supported:
270
331
  try:
271
- await self.verify_tip_presence(pipette_id, TipPresenceStatus.PRESENT)
332
+ await self.verify_tip_presence(
333
+ pipette_id,
334
+ TipPresenceStatus.PRESENT,
335
+ follow_singular_sensor=follow_singular_sensor,
336
+ )
272
337
  except TipNotAttachedError as e:
273
338
  raise PickUpTipTipNotAttachedError(tip_geometry=tip_geometry) from e
274
339
 
@@ -350,30 +415,6 @@ class HardwareTipHandler(TipHandler):
350
415
  follow_singular_sensor: Optional[InstrumentProbeType] = None,
351
416
  ) -> None:
352
417
  """See documentation on abstract base class."""
353
- nozzle_configuration = self._state_view.pipettes.get_nozzle_configuration(
354
- pipette_id=pipette_id
355
- )
356
-
357
- # Configuration metrics by which tip presence checking is ignored
358
- unsupported_pipette_types = [8, 96]
359
- unsupported_layout_types = [
360
- NozzleConfigurationType.SINGLE,
361
- NozzleConfigurationType.COLUMN,
362
- ]
363
- # NOTE: (09-20-2024) Current on multi-channel pipettes, utilizing less than 4 nozzles risks false positives on the tip presence sensor
364
- supported_partial_nozzle_minimum = 4
365
-
366
- if (
367
- nozzle_configuration is not None
368
- and self._state_view.pipettes.get_channels(pipette_id)
369
- in unsupported_pipette_types
370
- and nozzle_configuration.configuration in unsupported_layout_types
371
- and len(nozzle_configuration.map_store) < supported_partial_nozzle_minimum
372
- ):
373
- # Tip presence sensing is not supported for single tip pick up on the 96ch Flex Pipette, nor with single and some partial layous of the 8ch Flex Pipette.
374
- # This is due in part to a press distance tolerance which creates a risk case for false positives. In the case of single tip, the mechanical tolerance
375
- # for presses with 100% success is below the minimum average achieved press distance for a given multi channel pipette in that configuration.
376
- return
377
418
  try:
378
419
  ot3api = ensure_ot3_hardware(hardware_api=self._hardware_api)
379
420
  hw_mount = self._get_hw_mount(pipette_id)
@@ -371,7 +371,7 @@ def find_volume_at_well_height(
371
371
  max_height = volumetric_capacity[-1][0]
372
372
  if target_height < 0 or target_height > max_height:
373
373
  raise InvalidLiquidHeightFound(
374
- "Invalid target height {target_height} mm; max well height is {max_height} mm."
374
+ f"Invalid target height {target_height} mm; max well height is {max_height} mm."
375
375
  )
376
376
  # volumes in volumetric_capacity are relative to each frustum,
377
377
  # so we have to find the volume of all the full sections enclosed
@@ -7,6 +7,7 @@ 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
10
11
 
11
12
  from opentrons.types import (
12
13
  Point,
@@ -487,7 +488,7 @@ class GeometryView:
487
488
  raise OperationLocationNotInWellError(
488
489
  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"
489
490
  )
490
- elif z_offset < 0:
491
+ elif z_offset < 0 and not isclose(z_offset, 0, abs_tol=0.0000001):
491
492
  if isinstance(well_location, LiquidHandlingWellLocation):
492
493
  raise OperationLocationNotInWellError(
493
494
  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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: opentrons
3
- Version: 8.4.0a5
3
+ Version: 8.4.0a6
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.0a5)
24
+ Requires-Dist: opentrons-shared-data (==8.4.0a6)
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.0a5) ; extra == 'flex-hardware'
38
+ Requires-Dist: opentrons-hardware[flex] (==8.4.0a6) ; extra == 'flex-hardware'
39
39
  Provides-Extra: ot2-hardware
40
- Requires-Dist: opentrons-hardware (==8.4.0a5) ; extra == 'ot2-hardware'
40
+ Requires-Dist: opentrons-hardware (==8.4.0a6) ; 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=XUVIxnylpkhviFy5jxYJv-o7Lvmb2FJIbdoEjQ_9Vro,117886
231
+ opentrons/protocol_api/instrument_context.py,sha256=ycUSiRkVbkplN54rxxPu7BtHF4xtMaGc8tdjvTDsE8A,117900
232
232
  opentrons/protocol_api/labware.py,sha256=1m1y7h70bBBqW60LjiCPQWwFfVXzY_goJrB773yUN0A,60407
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
@@ -425,7 +425,7 @@ opentrons/protocol_engine/execution/run_control.py,sha256=ksvI2zkguC4G3lR3HJgAF8
425
425
  opentrons/protocol_engine/execution/status_bar.py,sha256=tR7CHS_y1ARQxcSKDO4YFU2cqVQhePzalmzsyH8b23A,970
426
426
  opentrons/protocol_engine/execution/thermocycler_movement_flagger.py,sha256=Ouljgjtm7-sCXwDcpfbir84dAZh5y89DNiuKedYimyg,6790
427
427
  opentrons/protocol_engine/execution/thermocycler_plate_lifter.py,sha256=j33nYV8rkeAYUOau8wFIyJVWjWkjyildleYHCysez-o,3375
428
- opentrons/protocol_engine/execution/tip_handler.py,sha256=DDlI-AwdasbwLjZpN6r76pxqr1WI6R21m3tElBswg5o,18398
428
+ opentrons/protocol_engine/execution/tip_handler.py,sha256=Ouunj3KVqz-UMbkjFIbJJr2zpfgcUht_r4_60uHEx3M,19731
429
429
  opentrons/protocol_engine/notes/__init__.py,sha256=G0bIQswsov7MrJU0ArrOaWcOTxJU9BCUmNR3LRoNg-Q,311
430
430
  opentrons/protocol_engine/notes/notes.py,sha256=A5C9xHExlS9GAK7o_mYiKJgibBm6EEgHQ4PJor0IET0,1993
431
431
  opentrons/protocol_engine/resources/__init__.py,sha256=yvGFYpmLoxHYQff_IwiaEH9viZUfal5D5K91UjYLwwY,805
@@ -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=I_tVCqy-CgYBqBS7FVyDpxdz0AdDeKYyeTPmaZuUIqU,17342
453
- opentrons/protocol_engine/state/geometry.py,sha256=_4buTI8kNjCogc4zKJwhCrvlB71yXrdcYqiwen-qkcA,97628
452
+ opentrons/protocol_engine/state/frustum_helpers.py,sha256=uRBLLR75Z_PnfVd-U7gPF3NeOALR3TgLNCojgxB4z0o,17343
453
+ opentrons/protocol_engine/state/geometry.py,sha256=PoqaC_Vmw2hF_H4u5ONgbJig8J52gIyI7ExwvZgtfCg,97701
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.0a5.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
587
- opentrons-8.4.0a5.dist-info/METADATA,sha256=dVv_Zex7NX_Yf6tBwmhxcaTUWKOKDvYAmuqkq99qwEU,5084
588
- opentrons-8.4.0a5.dist-info/WHEEL,sha256=qUzzGenXXuJTzyjFah76kDVqDvnk-YDzY00svnrl84w,109
589
- opentrons-8.4.0a5.dist-info/entry_points.txt,sha256=fTa6eGCYkvOtv0ov-KVE8LLGetgb35LQLF9x85OWPVw,106
590
- opentrons-8.4.0a5.dist-info/top_level.txt,sha256=wk6whpbMZdBQpcK0Fg0YVfUGrAgVOFON7oQAhOMGMW8,10
591
- opentrons-8.4.0a5.dist-info/RECORD,,
586
+ opentrons-8.4.0a6.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
587
+ opentrons-8.4.0a6.dist-info/METADATA,sha256=aOK9mh9j_G3EODbbtkFFhGtWd-YxxGSyue8zEHQrfyM,5084
588
+ opentrons-8.4.0a6.dist-info/WHEEL,sha256=qUzzGenXXuJTzyjFah76kDVqDvnk-YDzY00svnrl84w,109
589
+ opentrons-8.4.0a6.dist-info/entry_points.txt,sha256=fTa6eGCYkvOtv0ov-KVE8LLGetgb35LQLF9x85OWPVw,106
590
+ opentrons-8.4.0a6.dist-info/top_level.txt,sha256=wk6whpbMZdBQpcK0Fg0YVfUGrAgVOFON7oQAhOMGMW8,10
591
+ opentrons-8.4.0a6.dist-info/RECORD,,