Skip to content

refactor(api, shared-data): liquid class tiprack schema change #18958

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

Draft
wants to merge 2 commits into
base: edge
Choose a base branch
from
Draft
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
6 changes: 5 additions & 1 deletion api/src/opentrons/protocol_api/_liquid.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ def create(cls, liquid_class_definition: LiquidClassSchemaV1) -> "LiquidClass":
for by_pipette in liquid_class_definition.byPipette:
tip_settings: Dict[str, TransferProperties] = {}
for tip_type in by_pipette.byTipType:
tip_settings[tip_type.tiprack] = build_transfer_properties(tip_type)
# TODO having these refer to the same transfer property object
# but this may change IDK
transfer_props = build_transfer_properties(tip_type)
for tiprack in tip_type.tiprack:
tip_settings[tiprack] = transfer_props
Comment on lines +57 to +61
Copy link
Member

@sanni-t sanni-t Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya I think we should copy the transfer props instead of using the same, because otherwise multiple tipracks will have reference to the same transfer props object. This will cause problems like this-

props_for_v1_tiprack = water.get_for(pipette_load_name, "opentrons/opentrons_flex_96_tiprack_50ul/1")
props_for_v2_tiprack = water.get_for(pipette_load_name, "opentrons/opentrons_flex_96_tiprack_50ul/2")

assert props_for_v1_tiprack == props_for_v2_tiprack            # passes
assert props_for_v1_tiprack.aspirate.submerge.speed == 100  # passes

props_for_v1_tiprack.aspirate.submerge.speed = 231
assert props_for_v2_tiprack.aspirate.submerge.speed == 231  # passes, not desirable

by_pipette_settings[by_pipette.pipetteModel] = tip_settings

return cls(
Expand Down
11 changes: 8 additions & 3 deletions api/src/opentrons/protocol_engine/types/liquid_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from pydantic import Field

from opentrons_shared_data.liquid_classes.liquid_class_definition import (
ByTipTypeSetting,
TransferProperties,
)


class LiquidClassRecord(ByTipTypeSetting, frozen=True):
class LiquidClassRecord(TransferProperties, frozen=True):
"""LiquidClassRecord is our internal representation of an (immutable) liquid class.

Conceptually, a liquid class record is the tuple (name, pipette, tip, transfer properties).
Expand All @@ -17,6 +17,11 @@ class LiquidClassRecord(ByTipTypeSetting, frozen=True):
This class defines the tuple via inheritance so that we can reuse the definitions from shared_data.
"""

tiprack: str = Field(
...,
description="The name of tiprack whose tip will be used"
" when handling this specific liquid class with this pipette",
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Move this down so that the entries here are ordered as liquidClassName, pipetteModel, tiprack; and update the comment below.

liquidClassName: str = Field(
...,
description="Identifier for the liquid of this liquid class, e.g. glycerol50.",
Expand All @@ -25,7 +30,7 @@ class LiquidClassRecord(ByTipTypeSetting, frozen=True):
...,
description="Identifier for the pipette of this liquid class.",
)
# The other fields like tiprack ID, aspirate properties, etc. are pulled in from ByTipTypeSetting.
# The other liquid class properties are pulled in from TransferProperties.

def __hash__(self) -> int:
"""Hash function for LiquidClassRecord."""
Expand Down
4 changes: 2 additions & 2 deletions api/tests/opentrons/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ def minimal_liquid_class_def2() -> LiquidClassSchemaV1:
pipetteModel="flex_1channel_50",
byTipType=[
ByTipTypeSetting(
tiprack="opentrons_flex_96_tiprack_50ul",
tiprack=["opentrons_flex_96_tiprack_50ul"],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder how much more would break if you changed the name to tipracks to reflect its new type.

aspirate=AspirateProperties(
submerge=Submerge(
startPosition=TipPosition(
Expand Down Expand Up @@ -912,7 +912,7 @@ def maximal_liquid_class_def() -> LiquidClassSchemaV1:
pipetteModel="flex_1channel_50",
byTipType=[
ByTipTypeSetting(
tiprack="opentrons_flex_96_tiprack_50ul",
tiprack=["opentrons_flex_96_tiprack_50ul"],
aspirate=AspirateProperties(
submerge=Submerge(
startPosition=TipPosition(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def liquid_class_record(
return LiquidClassRecord(
liquidClassName=minimal_liquid_class_def2.liquidClassName,
pipetteModel=pipette_0.pipetteModel,
tiprack=by_tip_type_0.tiprack,
tiprack=by_tip_type_0.tiprack[0],
aspirate=by_tip_type_0.aspirate,
singleDispense=by_tip_type_0.singleDispense,
multiDispense=by_tip_type_0.multiDispense,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_handles_add_liquid_class(
liquid_class_record = LiquidClassRecord(
liquidClassName=minimal_liquid_class_def2.liquidClassName,
pipetteModel=pipette_0.pipetteModel,
tiprack=by_tip_type_0.tiprack,
tiprack=by_tip_type_0.tiprack[0],
aspirate=by_tip_type_0.aspirate,
singleDispense=by_tip_type_0.singleDispense,
multiDispense=by_tip_type_0.multiDispense,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def liquid_class_record(
return LiquidClassRecord(
liquidClassName=minimal_liquid_class_def2.liquidClassName,
pipetteModel=pipette_0.pipetteModel,
tiprack=by_tip_type_0.tiprack,
tiprack=by_tip_type_0.tiprack[0],
aspirate=by_tip_type_0.aspirate,
singleDispense=by_tip_type_0.singleDispense,
multiDispense=by_tip_type_0.multiDispense,
Expand Down
110 changes: 88 additions & 22 deletions shared-data/liquid-class/definitions/1/ethanol_80/1.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
"pipetteModel": "flex_1channel_50",
"byTipType": [
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_50ul/1",
"opentrons/opentrons_flex_96_tiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -269,7 +272,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"opentrons/opentrons_flex_96_filtertiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -533,7 +539,10 @@
"pipetteModel": "flex_8channel_50",
"byTipType": [
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_50ul/1",
"opentrons/opentrons_flex_96_tiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -792,7 +801,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"opentrons/opentrons_flex_96_filtertiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -1056,7 +1068,10 @@
"pipetteModel": "flex_1channel_1000",
"byTipType": [
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_50ul/1",
"opentrons/opentrons_flex_96_tiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -1320,7 +1335,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"opentrons/opentrons_flex_96_filtertiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -1584,7 +1602,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_200ul/1",
"opentrons/opentrons_flex_96_tiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -1847,7 +1868,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"opentrons/opentrons_flex_96_filtertiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -2110,7 +2134,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_1000ul/1",
"opentrons/opentrons_flex_96_tiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -2373,7 +2400,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"opentrons/opentrons_flex_96_filtertiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -2641,7 +2671,10 @@
"pipetteModel": "flex_8channel_1000",
"byTipType": [
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_50ul/1",
"opentrons/opentrons_flex_96_tiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -2905,7 +2938,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"opentrons/opentrons_flex_96_filtertiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -3169,7 +3205,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_200ul/1",
"opentrons/opentrons_flex_96_tiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -3432,7 +3471,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"opentrons/opentrons_flex_96_filtertiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -3695,7 +3737,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_1000ul/1",
"opentrons/opentrons_flex_96_tiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -3958,7 +4003,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"opentrons/opentrons_flex_96_filtertiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -4226,7 +4274,10 @@
"pipetteModel": "flex_96channel_1000",
"byTipType": [
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_50ul/1",
"opentrons/opentrons_flex_96_tiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -4490,7 +4541,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_50ul/1",
"opentrons/opentrons_flex_96_filtertiprack_50ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -4754,7 +4808,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_200ul/1",
"opentrons/opentrons_flex_96_tiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -5017,7 +5074,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_200ul/1",
"opentrons/opentrons_flex_96_filtertiprack_200ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -5280,7 +5340,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_tiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_tiprack_1000ul/1",
"opentrons/opentrons_flex_96_tiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down Expand Up @@ -5543,7 +5606,10 @@
}
},
{
"tiprack": "opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"tiprack": [
"opentrons/opentrons_flex_96_filtertiprack_1000ul/1",
"opentrons/opentrons_flex_96_filtertiprack_1000ul/2"
],
"aspirate": {
"submerge": {
"startPosition": {
Expand Down
Loading
Loading