Skip to content

Commit

Permalink
Merge branch 'chore_resolve-630-conflicts' into edge
Browse files Browse the repository at this point in the history
  • Loading branch information
b-cooper committed Apr 4, 2023
2 parents 64af608 + b747594 commit 15e8a6f
Show file tree
Hide file tree
Showing 197 changed files with 5,163 additions and 3,303 deletions.
1 change: 1 addition & 0 deletions api-client/src/runs/commands/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface RunCommandSummary {
commandType: RunTimeCommand['commandType']
status: 'queued' | 'running' | 'succeeded' | 'failed'
createdAt: string
intent?: 'protocol' | 'setup'
params?: any
// TODO(mc, 2022-02-02): `result` does not exist on RunCommandSummary
result?: RunTimeCommand['result']
Expand Down
1 change: 1 addition & 0 deletions api/buildroot.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ot_api_name := python-opentrons-api
define PYTHON_OPENTRONS_API_INSTALL_RELEASE_NOTES
$(INSTALL) -D -m 0644 $(BR2_EXTERNAL_OPENTRONS_MONOREPO_PATH)/api/release-notes.md $(BINARIES_DIR)/release-notes.md
endef
export OPENTRONS_GIT_DIR=$(BR2_EXTERNAL_OPENTRONS_MONOREPO_PATH)

# Calling inner-python-package directly instead of using python-package macro
# because our directory layout doesn’t conform to buildroot’s expectation of
Expand Down
6 changes: 3 additions & 3 deletions api/docs/v2/versioning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ If you specify an API version of ``2.13`` or lower, your protocols will continue
- Motion planning has been improved to avoid certain erroneous downward movements,
especially when using :py:meth:`.InstrumentContext.aspirate`.

- :py:attr:`.Labware.tip_length` will raise a useful error if called on labware that is not a tip rack.
- :py:meth:`.Labware.reset` and :py:attr:`.Labware.tip_length` will raise useful errors if called on labware that is not a tip rack.

- Removals

Expand All @@ -295,8 +295,8 @@ If you specify an API version of ``2.13`` or lower, your protocols will continue

- The ``height`` parameter of :py:meth:`.MagneticModuleContext.engage` was removed.
Use ``offset`` or ``height_from_base`` instead.

- ``Labware.separate_calibration`` and ``ModuleContext.separate_calibration`` were removed,
- ``Labware.separate_calibration`` and :py:meth:`.Labware.set_calibration` were removed,
since they were holdovers from a calibration system that no longer exists.

- Various methods and setters were removed that could modify tip state outside of
Expand Down
21 changes: 21 additions & 0 deletions api/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ log][]. For a list of currently known issues, please see the [Opentrons issue tr

---

## OT-2 Software Changes in 6.3.0

Welcome to the v6.3.0 release of the OT-2 software!

### Improved Features

- The `/calibrations` endpoint now accepts `DELETE` requests.

### Bug Fixes

- Fixed a problem where labware offsets would sometimes be ignored for labware atop a Temperature Module.
- Calls to the `/commands` endpoint with `waitUntilComplete=true` no longer time out after 30 seconds if you don't specify a timeout interval.
- Fixed improper pagination and cursor placement for the `/commands` endpoint.

### Known Issues

- Some protocols can't be simulated with the `opentrons_simulate` command-line tool:
- JSON protocols created or modified with Protocol Designer v6.0.0 or higher
- Python protocols specifying an `apiLevel` of 2.14

---
## OT-2 Software Changes in 6.2.1

Welcome to the v6.2.1 release of the OT-2 software! This hotfix release addresses a few problems.
Expand Down
3 changes: 2 additions & 1 deletion api/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
def get_version():
buildno = os.getenv("BUILD_NUMBER")
project = os.getenv("OPENTRONS_PROJECT", "robot-stack")
git_dir = os.getenv("OPENTRONS_GIT_DIR", None)
if buildno:
normalize_opts = {"extra_tag": buildno}
else:
normalize_opts = {}
return normalize_version("api", project, **normalize_opts)
return normalize_version("api", project, git_dir=git_dir, **normalize_opts)


VERSION = get_version()
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/protocol_api/_liquid.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Liquid:
name: A human-readable name for the liquid.
description: An optional description.
display_color: An optional display color for the liquid.
.. versionadded:: 2.14
"""

_id: str
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def _map_module(
engine_state: StateView,
module_id: str,
) -> Optional[Tuple[int, wrapped_deck_conflict.DeckItem]]:
module_model = engine_state.modules.get_model(module_id=module_id)
module_model = engine_state.modules.get_connected_model(module_id=module_id)
module_type = module_model.as_type()
mapped_location = _deck_slot_to_int(
engine_state.modules.get_location(module_id=module_id)
Expand Down
3 changes: 3 additions & 0 deletions api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,9 @@ def get_min_volume(self) -> float:
def get_max_volume(self) -> float:
return self._engine_client.state.pipettes.get_maximum_volume(self._pipette_id)

def get_working_volume(self) -> float:
return self._engine_client.state.pipettes.get_working_volume(self._pipette_id)

def get_current_volume(self) -> float:
try:
current_volume = self._engine_client.state.pipettes.get_aspirated_volume(
Expand Down
5 changes: 4 additions & 1 deletion api/src/opentrons/protocol_api/core/engine/labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ def get_tip_length(self) -> float:
return self._engine_client.state.labware.get_tip_length(self._labware_id)

def reset_tips(self) -> None:
self._engine_client.reset_tips(labware_id=self.labware_id)
if self.is_tip_rack():
self._engine_client.reset_tips(labware_id=self.labware_id)
else:
raise TypeError(f"{self.get_display_name()} is not a tip rack.")

def get_next_tip(
self, num_tips: int, starting_tip: Optional[WellCore]
Expand Down
43 changes: 37 additions & 6 deletions api/src/opentrons/protocol_api/core/engine/load_labware_params.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
from typing import Tuple, List, Optional
from typing import Dict, Tuple, List, Optional

from opentrons.protocols.api_support.constants import OPENTRONS_NAMESPACE
from opentrons.protocol_engine.state.labware import LabwareLoadParams


# Default versions of Opentrons standard labware definitions in Python Protocol API
# v2.14 and above. Labware not explicitly listed here default to 1.
#
# This will need to be extended t
_APILEVEL_2_14_OT_DEFAULT_VERSIONS: Dict[str, int] = {
# v1 of many labware definitions have wrong `zDimension`s. (Jira RSS-202.)
# For "opentrons_96_aluminumblock_generic_pcr_strip_200ul" and
# "opentrons_24_aluminumblock_generic_2ml_screwcap", they're wrong enough to
# easily cause collisions. (Jira RSS-197.)
"opentrons_24_aluminumblock_generic_2ml_screwcap": 2,
"opentrons_96_aluminumblock_generic_pcr_strip_200ul": 2,
}


class AmbiguousLoadLabwareParamsError(RuntimeError):
"""Error raised when specific labware parameters cannot be found due to multiple matching labware definitions."""

Expand Down Expand Up @@ -40,18 +54,35 @@ def matches_params(custom_params: LabwareLoadParams) -> bool:
params for params in custom_load_labware_params if matches_params(params)
]

# If there is no custom labware for the load name provided earlier, default anything not chosen to
# the opentrons defaults. If the provided namespace was OPENTRONS_NAMESPACE, there will be no custom labware
# associated with that namespace, meaning `custom_labware_params` will be empty and version will always
# default to 1 here
if not filtered_custom_params:
# No custom labware matches the input, but some standard labware might.
# Use the Opentrons defaults for anything not explicitly provided.
#
# If the provided namespace was OPENTRONS_NAMESPACE, there would have been no
# custom labware matching that namespace, so we will always take this path in
# that case.
resolved_namespace = namespace if namespace is not None else OPENTRONS_NAMESPACE
resolved_version = version if version is not None else 1
resolved_version = (
version
if version is not None
else _get_default_version_for_standard_labware(load_name=load_name)
)

elif len(filtered_custom_params) > 1:
# Multiple custom labware match the input.
raise AmbiguousLoadLabwareParamsError(
f"Multiple custom labware associated with load name {load_name}."
)

else:
# Exactly one custom labware matches the input. Return it.
resolved_namespace = filtered_custom_params[0].namespace
resolved_version = filtered_custom_params[0].version

return resolved_namespace, resolved_version


def _get_default_version_for_standard_labware(load_name: str) -> int:
# We know the protocol is running at least apiLevel 2.14 by this point because
# apiLevel 2.13 and below has its own separate code path for resolving labware.
return _APILEVEL_2_14_OT_DEFAULT_VERSIONS.get(load_name, 1)
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_api/core/engine/module_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def module_id(self) -> str:
def get_model(self) -> ModuleModel:
"""Get the module's model identifier."""
return module_model_from_string(
self._engine_client.state.modules.get_model(self.module_id)
self._engine_client.state.modules.get_connected_model(self.module_id)
)

def get_serial_number(self) -> str:
Expand Down
4 changes: 4 additions & 0 deletions api/src/opentrons/protocol_api/core/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ def get_min_volume(self) -> float:
def get_max_volume(self) -> float:
...

@abstractmethod
def get_working_volume(self) -> float:
...

@abstractmethod
def get_current_volume(self) -> float:
...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ def get_max_volume(self) -> float:
"""Get the max volume."""
return self.get_hardware_state()["max_volume"]

def get_working_volume(self) -> float:
"""Get the working volume."""
return self.get_hardware_state()["working_volume"]

def get_current_volume(self) -> float:
"""Get the current volume."""
return self.get_hardware_state()["current_volume"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ def get_min_volume(self) -> float:
def get_max_volume(self) -> float:
return self._pipette_dict["max_volume"]

def get_working_volume(self) -> float:
return self._pipette_dict["working_volume"]

def get_current_volume(self) -> float:
return self._pipette_dict["current_volume"]

Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_api/instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@ def transfer(
)
max_volume = min(next_tip.max_volume, self.max_volume)
else:
max_volume = self.hw_pipette["working_volume"]
max_volume = self._core.get_working_volume()

touch_tip = None
if kwargs.get("touch_tip"):
Expand Down
24 changes: 20 additions & 4 deletions api/src/opentrons/protocol_api/labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ def load_liquid(self, liquid: Liquid, volume: float) -> None:
"""
Load a liquid into a well.
:param liquid: The type of liquid to load into the well.
:param volume: The volume of liquid to load, in µL.
:param Liquid liquid: The liquid to load into the well.
:param float volume: The volume of liquid to load, in µL.
"""
self._core.load_liquid(
liquid=liquid,
Expand Down Expand Up @@ -313,6 +313,9 @@ def __init__(

@property
def separate_calibration(self) -> bool:
if self._api_version >= ENGINE_CORE_API_VERSION:
raise APIVersionError("Labware.separate_calibration has been removed")

_log.warning(
"Labware.separate_calibrations is a deprecated internal property."
" It no longer has meaning, but will always return `False`"
Expand Down Expand Up @@ -432,8 +435,16 @@ def magdeck_engage_height(self) -> Optional[float]:

def set_calibration(self, delta: Point) -> None:
"""
Called by save calibration in order to update the offset on the object.
An internal, deprecated method used for updating the offset on the object.
.. deprecated:: 2.14
"""
if self._api_version >= ENGINE_CORE_API_VERSION:
raise APIVersionError(
"Labware.set_calibration() is not supported when apiLevel is 2.14 or higher."
" Use a lower apiLevel"
" or use the Opentrons App's Labware Position Check."
)
self._core.set_calibration(delta)

@requires_version(2, 12)
Expand Down Expand Up @@ -874,7 +885,12 @@ def return_tips(self, start_well: Well, num_channels: int = 1) -> None:

@requires_version(2, 0)
def reset(self) -> None:
"""Reset all tips in a tiprack."""
"""Reset all tips in a tip rack.
.. versionchanged:: 2.14
This method will raise an exception if you call it on a labware that isn't
a tip rack. Formerly, it would do nothing.
"""
self._core.reset_tips()


Expand Down
22 changes: 10 additions & 12 deletions api/src/opentrons/protocol_api/module_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,10 @@ def load_labware(
) -> Labware:
"""Load a labware onto the module using its load parameters.
:param name: The name of the labware object.
:param str label: An optional display name to give the labware.
If specified, this is the name the labware will use
in the run log and the calibration view in the Opentrons App.
:param str namespace: The namespace the labware definition belongs to.
If unspecified, will search 'opentrons' then 'custom_beta'
:param int version: The version of the labware definition.
If unspecified, will use version 1.
The parameters of this function behave like those of
:py:obj:`ProtocolContext.load_labware` (which loads labware directly
onto the deck). Note that the parameter ``name`` here corresponds to
``load_name`` on the ``ProtocolContext`` function.
:returns: The initialized and loaded labware object.
Expand Down Expand Up @@ -345,12 +341,14 @@ def calibrate(self) -> None:
.. deprecated:: 2.14
This method is unnecessary; remove any usage.
"""
_log.warning(
"`MagneticModuleContext.calibrate` doesn't do anything useful"
" and will no-op in Protocol API version 2.14 and higher."
)
if self._api_version < ENGINE_CORE_API_VERSION:
_log.warning(
"`MagneticModuleContext.calibrate` doesn't do anything useful"
" and will be removed in Protocol API version 2.14 and higher."
)
self._core._sync_module_hardware.calibrate() # type: ignore[attr-defined]
else:
raise APIVersionError("`MagneticModuleContext.calibrate` has been removed.")

@publish(command=cmds.magdeck_engage)
@requires_version(2, 0)
Expand Down
38 changes: 27 additions & 11 deletions api/src/opentrons/protocol_api/protocol_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,18 +298,32 @@ def load_labware(
This function returns the created and initialized labware for use
later in the protocol.
:param load_name: A string to use for looking up a labware definition
:param location: The slot into which to load the labware such as
1 or '1'
:param str load_name: A string to use for looking up a labware definition.
You can find the ``load_name`` for any standard labware on the Opentrons
`Labware Library <https://labware.opentrons.com>`_.
:param location: The slot into which to load the labware,
such as ``1`` or ``"1"``.
:type location: int or str
:param str label: An optional special name to give the labware. If
specified, this is the name the labware will appear
as in the run log and the calibration view in the
Opentrons app.
:param str namespace: The namespace the labware definition belongs to.
If unspecified, will search 'opentrons' then 'custom_beta'
:param int version: The version of the labware definition. If
unspecified, will use version 1.
:param str label: An optional special name to give the labware. If specified, this
is the name the labware will appear as in the run log and the calibration
view in the Opentrons app.
:param str namespace: The namespace that the labware definition belongs to.
If unspecified, will search both:
* ``"opentrons"``, to load standard Opentrons labware definitions.
* ``"custom_beta"``, to load custom labware definitions created with the
`Custom Labware Creator <https://labware.opentrons.com/create>`_.
You might need to specify an explicit ``namespace`` if you have a custom
definition whose ``load_name`` is the same as an Opentrons standard
definition, and you want to explicitly choose one or the other.
:param version: The version of the labware definition. You should normally
leave this unspecified to let the implementation choose a good default.
"""
load_name = validation.ensure_lowercase_name(load_name)
deck_slot = validation.ensure_deck_slot(location)
Expand Down Expand Up @@ -795,6 +809,8 @@ def define_liquid(
:param str name: A human-readable name for the liquid.
:param str description: An optional description of the liquid.
:param str display_color: An optional hex color code, with hash included, to represent the specified liquid. Standard three-value, four-value, six-value, and eight-value syntax are all acceptable.
:return: A :py:class:`~opentrons.protocol_api.Liquid` object representing the specified liquid.
"""
return self._core.define_liquid(
name=name,
Expand Down
7 changes: 7 additions & 0 deletions api/src/opentrons/protocol_engine/errors/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class PipetteNotLoadedError(ProtocolEngineError):
class ModuleNotLoadedError(ProtocolEngineError):
"""Raised when referencing a module that has not been loaded."""

def __init__(self, *, module_id: str) -> None:
super().__init__(f"Module {module_id} not found.")


class ModuleNotOnDeckError(ProtocolEngineError):
"""Raised when trying to use a module that is loaded off the deck."""
Expand Down Expand Up @@ -207,3 +210,7 @@ class FirmwareUpdateRequired(ProtocolEngineError):

class PipetteNotReadyToAspirateError(ProtocolEngineError):
"""Raised when the pipette is not ready to aspirate."""


class InvalidPipettingVolumeError(ProtocolEngineError):
"""Raised when pipetting a volume larger than the pipette volume."""
Loading

0 comments on commit 15e8a6f

Please sign in to comment.