Skip to content

fix(api): Ensure Configure Nozzle Layout and Configure For Volume commands publish notifications #18631

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

Merged
merged 3 commits into from
Jun 16, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@
"errorInfo": {
"args": "(\"Partial column configurations require the 'end' parameter.\",)",
"class": "ValueError",
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_eight_partial_column_no_end.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n validated_end = _check_valid_end_nozzle(validated_start, end)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _check_valid_end_nozzle\n raise ValueError(\"Partial column configurations require the 'end' parameter.\")\n"
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_eight_partial_column_no_end.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line N, in _decorated\n return func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n validated_end = _check_valid_end_nozzle(validated_start, end)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _check_valid_end_nozzle\n raise ValueError(\"Partial column configurations require the 'end' parameter.\")\n"
},
"errorType": "PythonException",
"id": "UUID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2388,7 +2388,7 @@
"errorInfo": {
"args": "(\"Partial column configurations require the 'end' parameter.\",)",
"class": "ValueError",
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"OT2_X_v2_20_8_Overrides_InvalidConfigs_Override_eight_partial_column_no_end.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n validated_end = _check_valid_end_nozzle(validated_start, end)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _check_valid_end_nozzle\n raise ValueError(\"Partial column configurations require the 'end' parameter.\")\n"
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"OT2_X_v2_20_8_Overrides_InvalidConfigs_Override_eight_partial_column_no_end.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line N, in _decorated\n return func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n validated_end = _check_valid_end_nozzle(validated_start, end)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _check_valid_end_nozzle\n raise ValueError(\"Partial column configurations require the 'end' parameter.\")\n"
},
"errorType": "PythonException",
"id": "UUID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@
"errorInfo": {
"args": "('Partial column configuration is only supported on 8-Channel pipettes.',)",
"class": "ValueError",
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_2.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_2.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line N, in _decorated\n return func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
},
"errorType": "PythonException",
"id": "UUID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@
"errorInfo": {
"args": "('Partial column configuration is only supported on 8-Channel pipettes.',)",
"class": "ValueError",
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_1.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_1.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line N, in _decorated\n return func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
},
"errorType": "PythonException",
"id": "UUID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@
"errorInfo": {
"args": "('Partial column configuration is only supported on 8-Channel pipettes.',)",
"class": "ValueError",
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_3.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
"traceback": " File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/execution/execute_python.py\", line N, in exec_run\n exec(\"run(__context)\", new_globs)\n\n File \"<string>\", line N, in <module>\n\n File \"Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs_Override_ninety_six_partial_column_3.py\", line N, in run\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/legacy_commands/publisher.py\", line N, in _decorated\n return func(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocols/api_support/util.py\", line N, in _check_version_wrapper\n return decorated_obj(*args, **kwargs)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in configure_nozzle_layout\n self._raise_if_configuration_not_supported_by_pipette(style)\n\n File \"/usr/local/lib/python3.10/site-packages/opentrons/protocol_api/instrument_context.py\", line N, in _raise_if_configuration_not_supported_by_pipette\n raise ValueError(\n"
},
"errorType": "PythonException",
"id": "UUID",
Expand Down
36 changes: 36 additions & 0 deletions api/src/opentrons/legacy_commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from opentrons.types import Location
from opentrons.protocol_api.disposal_locations import TrashBin, WasteChute
from opentrons.protocol_api._liquid import LiquidClass
from opentrons.protocol_api._nozzle_layout import NozzleLayout

if TYPE_CHECKING:
from opentrons.protocol_api import InstrumentContext
Expand Down Expand Up @@ -445,3 +446,38 @@ def resin_tip_dispense(
"name": command_types.PRESSURIZE,
"payload": {"instrument": instrument, "text": text},
}


def configure_for_volume(
instrument: InstrumentContext,
volume: float,
) -> command_types.ConfigureForVolumeCommand:
text = f"Configure pipette on {instrument.mount} mount to handle {volume} µL."
return {
"name": command_types.CONFIGURE_FOR_VOLUME,
"payload": {"instrument": instrument, "volume": volume, "text": text},
}


def configure_nozzle_layout(
instrument: InstrumentContext,
style: NozzleLayout,
start: str | None,
end: str | None,
) -> command_types.ConfigureNozzleLayoutCommand:
text = f"Configure pipette on {instrument.mount} mount to use {style} layout"
if start:
text += f" starting at nozzle {start}"
if end:
text += f" ending at nozzle {end}"
text += "."
return {
"name": command_types.CONFIGURE_NOZZLE_LAYOUT,
"payload": {
"instrument": instrument,
"style": style,
"start": start,
"end": end,
"text": text,
},
}
29 changes: 29 additions & 0 deletions api/src/opentrons/legacy_commands/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from opentrons.protocol_api.labware import Well
from opentrons.protocol_api.disposal_locations import TrashBin, WasteChute
from opentrons.protocol_api._liquid import LiquidClass
from opentrons.protocol_api._nozzle_layout import NozzleLayout

from opentrons.types import Location, Mount, AxisMapType

Expand Down Expand Up @@ -50,6 +51,8 @@
SEAL: Final = "command.SEAL"
UNSEAL: Final = "command.UNSEAL"
PRESSURIZE: Final = "command.PRESSURIZE"
CONFIGURE_FOR_VOLUME: Final = "command.CONFIGURE_FOR_VOLUME"
CONFIGURE_NOZZLE_LAYOUT: Final = "command.CONFIGURE_NOZZLE_LAYOUT"


# Modules #
Expand Down Expand Up @@ -589,6 +592,18 @@ class PressurizeCommandPayload(TextOnlyPayload):
instrument: InstrumentContext


class ConfigureForVolumePayload(TypedDict, TextOnlyPayload):
instrument: InstrumentContext
volume: float


class ConfigureNozzleLayoutPayload(TypedDict, TextOnlyPayload):
instrument: InstrumentContext
style: NozzleLayout
start: Union[str, None]
end: Union[str, None]


class MoveLabwareCommand(TypedDict):
name: Literal["command.MOVE_LABWARE"]
payload: MoveLabwareCommandPayload
Expand All @@ -609,6 +624,16 @@ class PressurizeCommand(TypedDict):
payload: PressurizeCommandPayload


class ConfigureForVolumeCommand(TypedDict):
name: Literal["command.CONFIGURE_FOR_VOLUME"]
payload: ConfigureForVolumePayload


class ConfigureNozzleLayoutCommand(TypedDict):
name: Literal["command.CONFIGURE_NOZZLE_LAYOUT"]
payload: ConfigureNozzleLayoutPayload


# Robot Commands and Payloads
class GripperCommandPayload(TextOnlyPayload):
pass
Expand Down Expand Up @@ -706,6 +731,8 @@ class RobotCloseGripperJawCommand(TypedDict):
SealCommand,
UnsealCommand,
PressurizeCommand,
ConfigureForVolumeCommand,
ConfigureNozzleLayoutCommand,
# Robot commands
RobotMoveToCommand,
RobotMoveAxisToCommand,
Expand Down Expand Up @@ -765,6 +792,8 @@ class RobotCloseGripperJawCommand(TypedDict):
SealCommandPayload,
UnsealCommandPayload,
PressurizeCommandPayload,
ConfigureForVolumePayload,
ConfigureNozzleLayoutPayload,
# Robot payloads
RobotMoveToCommandPayload,
RobotMoveAxisRelativeCommandPayload,
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/protocol_api/instrument_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2730,6 +2730,7 @@ def __repr__(self) -> str:
def __str__(self) -> str:
return "{} on {} mount".format(self._core.get_display_name(), self.mount)

@publisher.publish(command=cmds.configure_for_volume)
@requires_version(2, 15)
def configure_for_volume(self, volume: float) -> None:
"""Configure a pipette to handle a specific volume of liquid, measured in µL.
Expand Down Expand Up @@ -2824,6 +2825,7 @@ def prepare_to_aspirate(self) -> None:
)
self._core.prepare_to_aspirate()

@publisher.publish(command=cmds.configure_nozzle_layout)
@requires_version(2, 16)
def configure_nozzle_layout(
self,
Expand Down
Loading