Skip to content

Commit

Permalink
Merge branch 'chore_merge_back-7.3.1-to_edge' into edge
Browse files Browse the repository at this point in the history
  • Loading branch information
y3rsh committed Jun 25, 2024
2 parents 4247d54 + 0f8b3cd commit aa72ce2
Show file tree
Hide file tree
Showing 167 changed files with 1,566 additions and 6,835 deletions.
1 change: 1 addition & 0 deletions api/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ opentrons-shared-data = { editable = true, path = "../shared-data/python" }
opentrons = { editable = true, path = "." }
opentrons-hardware = { editable = true, path = "./../hardware", extras=["FLEX"] }
numpy = "==1.22.3"
packaging = "==21.3"
pyusb = "==1.2.1"

[dev-packages]
Expand Down
209 changes: 110 additions & 99 deletions api/Pipfile.lock

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions api/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ log][]. For a list of currently known issues, please see the [Opentrons issue tr

---

## Opentrons Robot Software Changes in 7.3.1

Welcome to the v7.3.1 release of the Opentrons robot software!

### Improved Features

- Updated values for how much a tip overlaps with the pipette nozzle when the pipette picks up tips, in order to make protocols more reliable. These new values only apply to JSON protocols and Python protocols specifying API version 2.19.

---

## Opentrons Robot Software Changes in 7.3.0

Welcome to the v7.3.0 release of the Opentrons robot software!
Expand Down
1 change: 1 addition & 0 deletions api/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def get_version():
"typing-extensions>=4.0.0,<5",
"click>=8.0.0,<9",
'importlib-metadata >= 1.0 ; python_version < "3.8"',
"packaging>=21.0",
]

EXTRAS = {
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/hardware_control/dev_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class PipetteDict(InstrumentDict):
tip_length: float
working_volume: float
tip_overlap: Dict[str, float]
versioned_tip_overlap: Dict[str, Dict[str, float]]
available_volume: float
return_tip_height: float
default_aspirate_flow_rates: Dict[str, float]
Expand Down
5 changes: 2 additions & 3 deletions api/src/opentrons/hardware_control/instruments/ot2/pipette.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,8 @@ def as_dict(self) -> "Pipette.DictType":
"default_dispense_flow_rates": self.dispense_flow_rates_lookup,
"tip_length": self.current_tip_length,
"return_tip_height": self.active_tip_settings.default_return_tip_height,
"tip_overlap": self.tip_overlap[
"v0"
], # TODO(cb, 2024-06-11): hard coded to "v0" - when versioned tip overlaps are fully integrated this must change
"tip_overlap": self.tip_overlap["v0"],
"versioned_tip_overlap": self.tip_overlap,
"back_compat_names": self._config.pipette_backcompat_names,
"supported_tips": self.liquid_class.supported_tips,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def get_attached_instrument(self, mount: MountType) -> PipetteDict:
"blow_out_flow_rate",
"working_volume",
"tip_overlap",
"versioned_tip_overlap",
"available_volume",
"return_tip_height",
"default_aspirate_flow_rates",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ def as_dict(self) -> "Pipette.DictType":
"tip_length": self.current_tip_length,
"return_tip_height": self.active_tip_settings.default_return_tip_height,
"tip_overlap": self.tip_overlap["v0"],
"versioned_tip_overlap": self.tip_overlap,
"back_compat_names": self._config.pipette_backcompat_names,
"supported_tips": self.liquid_class.supported_tips,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ def get_attached_instrument(self, mount: OT3Mount) -> PipetteDict:
"blow_out_flow_rate",
"working_volume",
"tip_overlap",
"versioned_tip_overlap",
"available_volume",
"return_tip_height",
"default_aspirate_flow_rates",
Expand Down
9 changes: 7 additions & 2 deletions api/src/opentrons/hardware_control/modules/mod_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import asyncio
import logging
import re
from typing import ClassVar, Mapping, Optional, TypeVar
from typing import ClassVar, Mapping, Optional, TypeVar, cast
from packaging.version import InvalidVersion, parse, Version
from opentrons.config import IS_ROBOT, ROBOT_FIRMWARE_DIR
from opentrons.drivers.rpi_drivers.types import USBPort
Expand All @@ -18,9 +18,14 @@
def parse_fw_version(version: str) -> Version:
try:
device_version = parse(version)
# This is a patch for older versions of packaging - they would try and parse old
# kidns of versions and return a LegacyVersion object. We can't check for that
# explicitly because they removed it in modern versions of packaging.
if not isinstance(device_version, Version):
raise InvalidVersion()
except InvalidVersion:
device_version = parse("v0.0.0")
return device_version
return cast(Version, device_version)


class AbstractModule(abc.ABC):
Expand Down
10 changes: 8 additions & 2 deletions api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from opentrons.protocol_api._nozzle_layout import NozzleLayout
from opentrons.hardware_control.nozzle_manager import NozzleConfigurationType
from opentrons.hardware_control.nozzle_manager import NozzleMap
from . import deck_conflict
from . import deck_conflict, overlap_versions

from ..instrument import AbstractInstrument
from .well import WellCore
Expand Down Expand Up @@ -782,7 +782,13 @@ def set_flow_rate(

def configure_for_volume(self, volume: float) -> None:
self._engine_client.execute_command(
cmd.ConfigureForVolumeParams(pipetteId=self._pipette_id, volume=volume)
cmd.ConfigureForVolumeParams(
pipetteId=self._pipette_id,
volume=volume,
tipOverlapNotAfterVersion=overlap_versions.overlap_for_api_version(
self._protocol_core.api_version
),
)
)

def prepare_to_aspirate(self) -> None:
Expand Down
16 changes: 16 additions & 0 deletions api/src/opentrons/protocol_api/core/engine/overlap_versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Mappings between API versions and overlap versions."""
from functools import lru_cache
from typing_extensions import Final
from opentrons.protocols.api_support.types import APIVersion

_OVERLAP_VERSION_MAP: Final = {APIVersion(2, 0): "v0", APIVersion(2, 19): "v1"}


@lru_cache(1)
def overlap_for_api_version(api_version: APIVersion) -> str:
"""Get the overlap version for a specific API version."""
defined = list(reversed(sorted(_OVERLAP_VERSION_MAP.keys())))
for version in defined:
if version <= api_version:
return _OVERLAP_VERSION_MAP[version]
return _OVERLAP_VERSION_MAP[APIVersion(2, 0)]
11 changes: 8 additions & 3 deletions api/src/opentrons/protocol_api/core/engine/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@
AbsorbanceReaderCore,
)
from .exceptions import InvalidModuleLocationError
from . import load_labware_params
from . import deck_conflict
from . import load_labware_params, deck_conflict, overlap_versions

if TYPE_CHECKING:
from ...labware import Labware
Expand Down Expand Up @@ -510,7 +509,13 @@ def load_instrument(
"""
engine_mount = MountType[mount.name]
load_result = self._engine_client.execute_command_without_recovery(
cmd.LoadPipetteParams(pipetteName=instrument_name, mount=engine_mount)
cmd.LoadPipetteParams(
pipetteName=instrument_name,
mount=engine_mount,
tipOverlapNotAfterVersion=overlap_versions.overlap_for_api_version(
self._api_version
),
)
)

return InstrumentCore(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class ConfigureForVolumeParams(PipetteIdMixin):
"than a pipette-specific maximum volume.",
ge=0,
)
tipOverlapNotAfterVersion: Optional[str] = Field(
None,
description="A version of tip overlap data to not exceed. The highest-versioned "
"tip overlap data that does not exceed this version will be used. Versions are "
"expressed as vN where N is an integer, counting up from v0. If None, the current "
"highest version will be used.",
)


class ConfigureForVolumePrivateResult(PipetteConfigUpdateResultMixin):
Expand Down Expand Up @@ -57,6 +64,7 @@ async def execute(
pipette_result = await self._equipment.configure_for_volume(
pipette_id=params.pipetteId,
volume=params.volume,
tip_overlap_version=params.tipOverlapNotAfterVersion,
)

return SuccessData(
Expand Down
8 changes: 8 additions & 0 deletions api/src/opentrons/protocol_engine/commands/load_pipette.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ class LoadPipetteParams(BaseModel):
description="An optional ID to assign to this pipette. If None, an ID "
"will be generated.",
)
tipOverlapNotAfterVersion: Optional[str] = Field(
None,
description="A version of tip overlap data to not exceed. The highest-versioned "
"tip overlap data that does not exceed this version will be used. Versions are "
"expressed as vN where N is an integer, counting up from v0. If None, the current "
"highest version will be used.",
)


class LoadPipetteResult(BaseModel):
Expand Down Expand Up @@ -109,6 +116,7 @@ async def execute(
pipette_name=params.pipetteName,
mount=params.mount,
pipette_id=params.pipetteId,
tip_overlap_version=params.tipOverlapNotAfterVersion,
)

return SuccessData(
Expand Down
29 changes: 22 additions & 7 deletions api/src/opentrons/protocol_engine/execution/equipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ async def load_pipette(
pipette_name: PipetteNameType,
mount: MountType,
pipette_id: Optional[str],
tip_overlap_version: Optional[str],
) -> LoadedPipetteData:
"""Ensure the requested pipette is attached.
Expand All @@ -213,6 +214,8 @@ async def load_pipette(
mount: The mount on which pipette must be attached.
pipette_id: An optional identifier to assign the pipette. If None, an
identifier will be generated.
tip_overlap_version: An optional specifier for the version of tip overlap data to use.
If None, defaults to v0. Does not need to be format checked - this function does it.
Returns:
A LoadedPipetteData object.
Expand All @@ -227,6 +230,11 @@ async def load_pipette(
if isinstance(pipette_name, PipetteNameType)
else pipette_name
)
sanitized_overlap_version = (
pipette_data_provider.validate_and_default_tip_overlap_version(
tip_overlap_version
)
)

pipette_id = pipette_id or self._model_utils.generate_id()
if not use_virtual_pipettes:
Expand Down Expand Up @@ -259,14 +267,16 @@ async def load_pipette(

serial_number = pipette_dict["pipette_id"]
static_pipette_config = pipette_data_provider.get_pipette_static_config(
pipette_dict
pipette_dict=pipette_dict, tip_overlap_version=sanitized_overlap_version
)

else:
serial_number = self._model_utils.generate_id(prefix="fake-serial-number-")
static_pipette_config = (
self._virtual_pipette_data_provider.get_virtual_pipette_static_config(
pipette_name_value, pipette_id
pipette_name=pipette_name_value,
pipette_id=pipette_id,
tip_overlap_version=sanitized_overlap_version,
)
)
serial = serial_number or ""
Expand Down Expand Up @@ -369,9 +379,7 @@ async def load_module(
)

async def configure_for_volume(
self,
pipette_id: str,
volume: float,
self, pipette_id: str, volume: float, tip_overlap_version: Optional[str]
) -> LoadedConfigureForVolumeData:
"""Ensure the requested volume can be configured for the given pipette.
Expand All @@ -383,6 +391,11 @@ async def configure_for_volume(
A LoadedConfiguredVolumeData object.
"""
use_virtual_pipettes = self._state_store.config.use_virtual_pipettes
sanitized_overlap_version = (
pipette_data_provider.validate_and_default_tip_overlap_version(
tip_overlap_version
)
)

if not use_virtual_pipettes:
mount = self._state_store.pipettes.get_mount(pipette_id).to_hw_mount()
Expand All @@ -392,7 +405,7 @@ async def configure_for_volume(

serial_number = pipette_dict["pipette_id"]
static_pipette_config = pipette_data_provider.get_pipette_static_config(
pipette_dict
pipette_dict=pipette_dict, tip_overlap_version=sanitized_overlap_version
)

else:
Expand All @@ -403,7 +416,9 @@ async def configure_for_volume(

serial_number = self._model_utils.generate_id(prefix="fake-serial-number-")
static_pipette_config = self._virtual_pipette_data_provider.get_virtual_pipette_static_config_by_model_string(
model, pipette_id
pipette_model_string=model,
pipette_id=pipette_id,
tip_overlap_version=sanitized_overlap_version,
)

return LoadedConfigureForVolumeData(
Expand Down
Loading

0 comments on commit aa72ce2

Please sign in to comment.