-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api): implement labware.set_offset in 2.18 (#14940)
The python protocol api's labware.set_offset() command lets you set a labware position check offset programmatically. This is useful in protocols run outside the app (i.e. through Jupyter, through opentrons_execute). When we moved to the protocol engine, we didn't support running those protocols outside the app, and therefore we didn't implement this method on those new API versions. Now, we allow that again, so implement that method again. This relies on dispatching AddLabwareOffset actions at arbitrary times, because it will set an offset for the location in which the labware is _currently_ present. This allows the user to set offsets without having to wrangle with the engine's internal definitions of where something is, at the cost of the user having to spread their offset calls around their protocol if they have protocols that load things in one place and later move them to another. ## Warning ~This won't work the way you think it will right now. Labware offsets are applied to labware instances by the `LoadLabware` and `MoveLabware` commands. So if you do an `AddLabwareOffsetAction` after a `LoadLabware`, the offset will never apply to the labware. We need to add a new `ReloadLabware` command, but I'm going to do that in a separate PR and then put this PR on top of that one.~ Fully implemented yay Closes RSQ-29
- Loading branch information
1 parent
e321c49
commit 913ecdd
Showing
9 changed files
with
1,101 additions
and
433 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,131 @@ | ||
"""Tests for opentrons.protocol_api.""" | ||
from typing import List, overload, Optional | ||
|
||
from opentrons.protocols.api_support.types import APIVersion | ||
from opentrons.protocol_api import ( | ||
MAX_SUPPORTED_VERSION, | ||
MIN_SUPPORTED_VERSION, | ||
MIN_SUPPORTED_VERSION_FOR_FLEX, | ||
) | ||
|
||
|
||
def versions_at_or_above(from_version: APIVersion) -> List[APIVersion]: | ||
"""Get a list of versions >= the specified one.""" | ||
return versions_between( | ||
low_inclusive_bound=from_version, high_inclusive_bound=MAX_SUPPORTED_VERSION | ||
) | ||
|
||
|
||
def versions_at_or_below( | ||
from_version: APIVersion, flex_only: bool = False | ||
) -> List[APIVersion]: | ||
"""Get a list of versions <= the specified one. | ||
Since there are different minimum supported versions for Flex and OT-2, specify which you care about | ||
with the second argument. | ||
""" | ||
if flex_only: | ||
return versions_between( | ||
low_inclusive_bound=MIN_SUPPORTED_VERSION_FOR_FLEX, | ||
high_inclusive_bound=from_version, | ||
) | ||
else: | ||
return versions_between( | ||
low_inclusive_bound=MIN_SUPPORTED_VERSION, high_inclusive_bound=from_version | ||
) | ||
|
||
|
||
def versions_above(from_version: APIVersion) -> List[APIVersion]: | ||
"""Get a list of versions > the specified one.""" | ||
return versions_between( | ||
low_exclusive_bound=from_version, high_inclusive_bound=MAX_SUPPORTED_VERSION | ||
) | ||
|
||
|
||
def versions_below(from_version: APIVersion, flex_only: bool) -> List[APIVersion]: | ||
"""Get a list of versions < the specified one. | ||
Since there are different minimum supported versions for Flex and OT-2, specify which you care about | ||
with the second argument. | ||
""" | ||
if flex_only: | ||
return versions_between( | ||
low_inclusive_bound=MIN_SUPPORTED_VERSION_FOR_FLEX, | ||
high_exclusive_bound=from_version, | ||
) | ||
else: | ||
return versions_between( | ||
low_inclusive_bound=MIN_SUPPORTED_VERSION, high_exclusive_bound=from_version | ||
) | ||
|
||
|
||
@overload | ||
def versions_between( | ||
*, | ||
low_inclusive_bound: APIVersion, | ||
high_inclusive_bound: APIVersion, | ||
) -> List[APIVersion]: | ||
... | ||
|
||
|
||
@overload | ||
def versions_between( | ||
*, low_inclusive_bound: APIVersion, high_exclusive_bound: APIVersion | ||
) -> List[APIVersion]: | ||
... | ||
|
||
|
||
@overload | ||
def versions_between( | ||
*, | ||
high_inclusive_bound: APIVersion, | ||
low_exclusive_bound: APIVersion, | ||
) -> List[APIVersion]: | ||
... | ||
|
||
|
||
@overload | ||
def versions_between( | ||
*, low_exclusive_bound: APIVersion, high_exclusive_bound: APIVersion | ||
) -> List[APIVersion]: | ||
... | ||
|
||
|
||
def versions_between( | ||
low_inclusive_bound: Optional[APIVersion] = None, | ||
high_inclusive_bound: Optional[APIVersion] = None, | ||
low_exclusive_bound: Optional[APIVersion] = None, | ||
high_exclusive_bound: Optional[APIVersion] = None, | ||
) -> List[APIVersion]: | ||
"""Build a list of versions based on exclusive and inclusive constraints.""" | ||
if low_inclusive_bound and high_inclusive_bound: | ||
assert ( | ||
low_inclusive_bound.major == high_inclusive_bound.major | ||
), "You need to change this test when you add a new major version" | ||
major = low_inclusive_bound.major | ||
start = low_inclusive_bound.minor | ||
stop = high_inclusive_bound.minor + 1 | ||
elif low_inclusive_bound and high_exclusive_bound: | ||
assert ( | ||
low_inclusive_bound.major == high_exclusive_bound.major | ||
), "You need to change this test when you add a new major version" | ||
major = low_inclusive_bound.major | ||
start = low_inclusive_bound.minor | ||
stop = high_exclusive_bound.minor | ||
elif low_exclusive_bound and high_inclusive_bound: | ||
assert ( | ||
low_exclusive_bound.major == high_inclusive_bound.major | ||
), "You need to change this test when you add a new major version" | ||
major = low_exclusive_bound.major | ||
start = low_exclusive_bound.minor + 1 | ||
stop = high_inclusive_bound.minor + 1 | ||
elif low_exclusive_bound and high_exclusive_bound: | ||
assert ( | ||
low_exclusive_bound.major == high_exclusive_bound.major | ||
), "You need to change this test when you add a new major version" | ||
major = low_exclusive_bound.major | ||
start = low_exclusive_bound.minor + 1 | ||
stop = high_exclusive_bound.minor | ||
else: | ||
raise ValueError("You must specify one low bound and one high bound") | ||
return [APIVersion(major, minor) for minor in range(start, stop)] |
Oops, something went wrong.