Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(api): add pipette misc functions to protocol_api #2713

Merged
merged 5 commits into from
Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion api/docs/source/new_protocol_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ From the example above, the "commands" section looked like:
.. code-block:: python

pipette.aspirate(100, plate.wells_by_index()['A1'])
pipette.dispense(100, plate.wells_by_index()[’B2’])
pipette.dispense(100, plate.wells_by_index()['B2'])

which does exactly what it says - aspirate 100 uL from A1 and dispense it all in B2.

Expand All @@ -160,6 +160,32 @@ Robot and Pipette
.. autoclass:: opentrons.protocol_api.contexts.InstrumentContext
:members:

.. autoclass:: opentrons.protocol_api.transfers.TransferOptions
sfoster1 marked this conversation as resolved.
Show resolved Hide resolved
:members:

.. autoclass:: opentrons.protocol_api.transfers.Transfer
:members:

.. autoclass:: opentrons.protocol_api.transfers.PickUpTipOpts
:members:

.. autoclass:: opentrons.protocol_api.transfers.MixOpts
:members:

.. autoclass:: opentrons.protocol_api.transfers.Mix
:members:

.. autoclass:: opentrons.protocol_api.transfers.BlowOutOpts
:members:

.. autoclass:: opentrons.protocol_api.transfers.TouchTipOpts
:members:

.. autoclass:: opentrons.protocol_api.transfers.AspirateOpts
:members:

.. autoclass:: opentrons.protocol_api.transfers.DispenseOpts
:members:

.. _protocol-api-labware:

Expand Down
22 changes: 14 additions & 8 deletions api/src/opentrons/api/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from opentrons.legacy_api.containers import get_container, location_to_list
from opentrons.legacy_api.containers.placeable import (
Module as ModulePlaceable, Placeable)
from opentrons.commands import tree, types
from opentrons.commands import tree, types as command_types
from opentrons.commands.commands import is_new_loc, listify
from opentrons.protocols import execute_protocol
from opentrons.config import feature_flags as ff
from opentrons.protocol_api import (ProtocolContext,
Expand Down Expand Up @@ -172,7 +173,7 @@ def on_command(message):
else:
stack.pop()

unsubscribe = subscribe(types.COMMAND, on_command)
unsubscribe = subscribe(command_types.COMMAND, on_command)

try:
# ensure actual pipettes are cached before driver is disconnected
Expand Down Expand Up @@ -276,14 +277,14 @@ def run(self): # noqa(C901)
def on_command(message):
if message['$'] == 'before':
self.log_append()
if message['name'] == types.PAUSE:
if message['name'] == command_types.PAUSE:
self.set_state('paused')
if message['name'] == types.RESUME:
if message['name'] == command_types.RESUME:
self.set_state('running')

self._reset()

_unsubscribe = subscribe(types.COMMAND, on_command)
_unsubscribe = subscribe(command_types.COMMAND, on_command)
self.startTime = now()
self.set_state('running')

Expand Down Expand Up @@ -467,9 +468,14 @@ def _get_labware(command):
containers.append(_get_new_labware(location))

if locations:
list_of_locations = location_to_list(locations)
containers.extend(
[get_container(location) for location in list_of_locations])
if is_new_loc(locations):
list_of_locations = listify(locations)
containers.extend(
[_get_new_labware(loc) for loc in list_of_locations])
else:
list_of_locations = location_to_list(locations)
containers.extend(
[get_container(location) for location in list_of_locations])

containers = [c for c in containers if c is not None]
modules = [m for m in modules if m is not None]
Expand Down
106 changes: 67 additions & 39 deletions api/src/opentrons/commands/commands.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from . import types
from . import types as command_types
from ..broker import broker
import functools
import inspect
from typing import Union
from typing import Union, Sequence, List, Any

from opentrons.legacy_api.containers import (Well as OldWell,
Container as OldContainer,
Expand All @@ -12,6 +12,19 @@
from opentrons.types import Location


def is_new_loc(location: Union[Location, Well, None,
OldWell, OldContainer,
OldSlot, Sequence]) -> bool:
return isinstance(listify(location)[0], (Location, Well))


def listify(location: Any) -> List:
if isinstance(location, list):
return sum([listify(loc) for loc in location], [])
else:
return [location]


def _stringify_new_loc(loc: Union[Location, Well]) -> str:
if isinstance(loc, Location):
if isinstance(loc.labware, str):
Expand Down Expand Up @@ -57,11 +70,14 @@ def get_slot(location):


def stringify_location(location: Union[Location, None,
OldWell, OldContainer, OldSlot]) -> str:
if isinstance(location, (Location, Well)):
return _stringify_new_loc(location)
OldWell, OldContainer,
OldSlot, Sequence]) -> str:
if is_new_loc(location):
loc_str_list = [_stringify_new_loc(loc)
for loc in listify(location)]
return ', '.join(loc_str_list)
else:
return _stringify_legacy_loc(location)
return _stringify_legacy_loc(location) # type: ignore


def make_command(name, payload):
Expand All @@ -71,7 +87,7 @@ def make_command(name, payload):
def home(mount):
text = 'Homing pipette plunger on mount {mount}'.format(mount=mount)
return make_command(
name=types.HOME,
name=command_types.HOME,
payload={
'axis': mount,
'text': text
Expand All @@ -85,7 +101,7 @@ def aspirate(instrument, volume, location, rate):
volume=volume, location=location_text, rate=rate
)
return make_command(
name=types.ASPIRATE,
name=command_types.ASPIRATE,
payload={
'instrument': instrument,
'volume': volume,
Expand All @@ -103,7 +119,7 @@ def dispense(instrument, volume, location, rate):
)

return make_command(
name=types.DISPENSE,
name=command_types.DISPENSE,
payload={
'instrument': instrument,
'volume': volume,
Expand All @@ -120,11 +136,15 @@ def consolidate(instrument, volume, source, dest):
source=stringify_location(source),
dest=stringify_location(dest)
)
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
if is_new_loc(source):
# Dest is assumed as new location too
locations = [] + listify(source) + listify(dest)
else:
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
return make_command(
name=types.CONSOLIDATE,
name=command_types.CONSOLIDATE,
payload={
'instrument': instrument,
'locations': locations,
Expand All @@ -142,11 +162,15 @@ def distribute(instrument, volume, source, dest):
source=stringify_location(source),
dest=stringify_location(dest)
)
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
if is_new_loc(source):
# Dest is assumed as new location too
locations = [] + listify(source) + listify(dest)
else:
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
return make_command(
name=types.DISTRIBUTE,
name=command_types.DISTRIBUTE,
payload={
'instrument': instrument,
'locations': locations,
Expand All @@ -164,11 +188,15 @@ def transfer(instrument, volume, source, dest):
source=stringify_location(source),
dest=stringify_location(dest)
)
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
if is_new_loc(source):
# Dest is assumed as new location too
locations = [] + listify(source) + listify(dest)
else:
# incase either source or dest is list of tuple location
# strip both down to simply lists of Placeables
locations = [] + location_to_list(source) + location_to_list(dest)
return make_command(
name=types.TRANSFER,
name=command_types.TRANSFER,
payload={
'instrument': instrument,
'locations': locations,
Expand All @@ -183,7 +211,7 @@ def transfer(instrument, volume, source, dest):
def comment(msg):
text = msg
return make_command(
name=types.COMMENT,
name=command_types.COMMENT,
payload={
'text': text
}
Expand All @@ -195,7 +223,7 @@ def mix(instrument, repetitions, volume, location):
repetitions=repetitions, volume=volume
)
return make_command(
name=types.MIX,
name=command_types.MIX,
payload={
'instrument': instrument,
'location': location,
Expand All @@ -214,7 +242,7 @@ def blow_out(instrument, location):
text += ' at {location}'.format(location=location_text)

return make_command(
name=types.BLOW_OUT,
name=command_types.BLOW_OUT,
payload={
'instrument': instrument,
'location': location,
Expand All @@ -226,7 +254,7 @@ def blow_out(instrument, location):
def touch_tip(instrument):
text = 'Touching tip'
return make_command(
name=types.TOUCH_TIP,
name=command_types.TOUCH_TIP,
payload={
'instrument': instrument,
'text': text
Expand All @@ -237,7 +265,7 @@ def touch_tip(instrument):
def air_gap():
text = 'Air gap'
return make_command(
name=types.AIR_GAP,
name=command_types.AIR_GAP,
payload={
'text': text
}
Expand All @@ -247,7 +275,7 @@ def air_gap():
def return_tip():
text = 'Returning tip'
return make_command(
name=types.RETURN_TIP,
name=command_types.RETURN_TIP,
payload={
'text': text
}
Expand All @@ -258,7 +286,7 @@ def pick_up_tip(instrument, location):
location_text = stringify_location(location)
text = 'Picking up tip {location}'.format(location=location_text)
return make_command(
name=types.PICK_UP_TIP,
name=command_types.PICK_UP_TIP,
payload={
'instrument': instrument,
'location': location,
Expand All @@ -271,7 +299,7 @@ def drop_tip(instrument, location):
location_text = stringify_location(location)
text = 'Dropping tip {location}'.format(location=location_text)
return make_command(
name=types.DROP_TIP,
name=command_types.DROP_TIP,
payload={
'instrument': instrument,
'location': location,
Expand All @@ -283,23 +311,23 @@ def drop_tip(instrument, location):
def magdeck_engage():
text = "Engaging magnetic deck module"
return make_command(
name=types.MAGDECK_ENGAGE,
name=command_types.MAGDECK_ENGAGE,
payload={'text': text}
)


def magdeck_disengage():
text = "Disengaging magnetic deck module"
return make_command(
name=types.MAGDECK_DISENGAGE,
name=command_types.MAGDECK_DISENGAGE,
payload={'text': text}
)


def magdeck_calibrate():
text = "Calibrating magnetic deck module"
return make_command(
name=types.MAGDECK_CALIBRATE,
name=command_types.MAGDECK_CALIBRATE,
payload={'text': text}
)

Expand All @@ -308,23 +336,23 @@ def tempdeck_set_temp():
text = "Setting temperature deck module temperature " \
"(rounded off to nearest integer)"
return make_command(
name=types.TEMPDECK_SET_TEMP,
name=command_types.TEMPDECK_SET_TEMP,
payload={'text': text}
)


def tempdeck_deactivate():
text = "Deactivating temperature deck module"
return make_command(
name=types.TEMPDECK_DEACTIVATE,
name=command_types.TEMPDECK_DEACTIVATE,
payload={'text': text}
)


def delay(seconds, minutes):
text = "Delaying for {minutes}m {seconds}s"
return make_command(
name=types.DELAY,
name=command_types.DELAY,
payload={
'minutes': minutes,
'seconds': seconds,
Expand All @@ -338,7 +366,7 @@ def pause(msg):
if msg:
text = text + ': {}'.format(msg)
return make_command(
name=types.PAUSE,
name=command_types.PAUSE,
payload={
'text': text
}
Expand All @@ -347,7 +375,7 @@ def pause(msg):

def resume():
return make_command(
name=types.RESUME,
name=command_types.RESUME,
payload={
'text': 'Resuming robot operation'
}
Expand All @@ -358,7 +386,7 @@ def do_publish(cmd, f, when, res, meta, *args, **kwargs):
""" Implement the publish so it can be called outside the decorator """
publish_command = functools.partial(
broker.publish,
topic=types.COMMAND)
topic=command_types.COMMAND)
call_args = _get_args(f, args, kwargs)
command_args = dict(
zip(
Expand Down Expand Up @@ -399,7 +427,7 @@ def do_publish(cmd, f, when, res, meta, *args, **kwargs):

def _publish_dec(before, after, command, meta=None):
def decorator(f):
@functools.wraps(f)
@functools.wraps(f, updated=functools.WRAPPER_UPDATES+('__globals__',))
def decorated(*args, **kwargs):
if before:
do_publish(command, f, 'before', None, meta, *args, **kwargs)
Expand Down
Loading