From 4b1d5fff6145a50ff24eaca3f7dbc8720cf9cc63 Mon Sep 17 00:00:00 2001 From: Josh McVey Date: Thu, 29 Aug 2024 15:48:38 -0500 Subject: [PATCH] mostly for pt rtp --- .../Flex_S_2_20_96_None_Column3_SINGLE_.py | 118 +++++++ ...v2_20_96_None_Overrides_TooTallLabware.py} | 22 +- ...v2_20_96_and_8_Overrides_InvalidConfigs.py | 187 +++++++++++ .../files/templates/partial_tip_rtp.py | 297 ++++++++++++++++++ 4 files changed, 613 insertions(+), 11 deletions(-) create mode 100644 analyses-snapshot-testing/files/protocols/Flex_S_2_20_96_None_Column3_SINGLE_.py rename analyses-snapshot-testing/files/protocols/{zzzzzMoveBad.py => Flex_X_v2_20_96_None_Overrides_TooTallLabware.py} (95%) create mode 100644 analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py create mode 100644 analyses-snapshot-testing/files/templates/partial_tip_rtp.py diff --git a/analyses-snapshot-testing/files/protocols/Flex_S_2_20_96_None_Column3_SINGLE_.py b/analyses-snapshot-testing/files/protocols/Flex_S_2_20_96_None_Column3_SINGLE_.py new file mode 100644 index 00000000000..e5d1427a477 --- /dev/null +++ b/analyses-snapshot-testing/files/protocols/Flex_S_2_20_96_None_Column3_SINGLE_.py @@ -0,0 +1,118 @@ +from opentrons import protocol_api +from opentrons.protocol_api import COLUMN, ALL, SINGLE, ROW + +requirements = {"robotType": "Flex", "apiLevel": "2.20"} + + +def run(protocol: protocol_api.ProtocolContext): + pipette = protocol.load_instrument(instrument_name="flex_96channel_1000") + trash = protocol.load_trash_bin("A1") + t1 = protocol.load_labware( + load_name="opentrons_flex_96_tiprack_1000ul", + label="Partial Tip Rack", + location="A2", + ) + t2 = protocol.load_labware( + load_name="opentrons_flex_96_tiprack_1000ul", + label="Partial Tip Rack", + location="B2", + ) + t3 = protocol.load_labware( + load_name="opentrons_flex_96_tiprack_1000ul", + label="Partial Tip Rack", + location="C2", + ) + t4 = protocol.load_labware( + load_name="opentrons_flex_96_tiprack_1000ul", + label="Partial Tip Rack", + location="D2", + ) + + ### Prep tipracks in B2 and D2 by removing 3 columns of tips + pipette.configure_nozzle_layout( + style=COLUMN, + start="A1", + tip_racks=[t2], + ) + for i in range(3): + pipette.pick_up_tip() + pipette.drop_tip() + + pipette.configure_nozzle_layout( + style=COLUMN, + start="A1", + tip_racks=[t4], + ) + for i in range(3): + pipette.pick_up_tip() + pipette.drop_tip() + + ### Relocate tipracks to A3 and C3 for single tip extraction at furthest extant + protocol.move_labware(t2, "A3", True) + protocol.move_labware(t4, "C3", True) + + pipette.configure_nozzle_layout( + style=SINGLE, + start="A1", + tip_racks=[t2, t4], + ) + + for i in range(72 * 2): + pipette.pick_up_tip() + pipette.drop_tip() + + ### Move tipracks out of the way to B1 and C1 + protocol.move_labware(t2, "B1", True) + protocol.move_labware(t4, "C1", True) + + ### Prepare tiprack in A2 by removing 3 columns of tips + pipette.configure_nozzle_layout( + style=COLUMN, + start="A1", + tip_racks=[t1], + ) + for i in range(3): + pipette.pick_up_tip() + pipette.drop_tip() + + ### Prepare tiprack in C2 by removing bottom 3 rows of tips, plus 15 tips (3 leftmost remaining columns) + ### This results in a tiprack of the following layout (matching the requirements for our bottom right extents): + # X X X X X X X X X - - - + # X X X X X X X X X - - - + # X X X X X X X X X - - - + # X X X X X X X X X - - - + # X X X X X X X X X - - - + # - - - - - - - - - - - - + # - - - - - - - - - - - - + # - - - - - - - - - - - - + pipette.configure_nozzle_layout( + style=ROW, + start="A1", + tip_racks=[t3], + ) + for i in range(3): + pipette.pick_up_tip() + pipette.drop_tip() + + pipette.configure_nozzle_layout( + style=SINGLE, + start="A1", + tip_racks=[t3], + ) + for i in range(15): + pipette.pick_up_tip() + pipette.drop_tip() + + ### Relocate tipracks to B3 and D3 on the deck + protocol.move_labware(t1, "B3", True) + protocol.move_labware(t3, "D3", True) + + pipette.configure_nozzle_layout( + style=SINGLE, + start="A1", + tip_racks=[t1, t3], + ) + + for i in range(72 + 45): + pipette.pick_up_tip() + pipette.drop_tip() diff --git a/analyses-snapshot-testing/files/protocols/zzzzzMoveBad.py b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py similarity index 95% rename from analyses-snapshot-testing/files/protocols/zzzzzMoveBad.py rename to analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py index 2237d207bb2..63c456f8c53 100644 --- a/analyses-snapshot-testing/files/protocols/zzzzzMoveBad.py +++ b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py @@ -28,7 +28,7 @@ class PartialTipConfig: ninety_six_single_top_left = PartialTipConfig( key="ninety_six_single_top_left", - description="96 single top left", + description="96 single picking up top left of tiprack", startingTip="A1", startingNozzle="H12", apiTipConfig=SINGLE, @@ -38,7 +38,7 @@ class PartialTipConfig: ninety_six_single_top_right = PartialTipConfig( key="ninety_six_single_top_right", - description="96 single top right", + description="96 single picking up top right of tiprack", startingTip="A12", startingNozzle="H1", apiTipConfig=SINGLE, @@ -48,7 +48,7 @@ class PartialTipConfig: ninety_six_single_bottom_left = PartialTipConfig( key="ninety_six_single_bottom_left", - description="96 single bottom left", + description="96 single picking up bottom left of tiprack", startingTip="H1", startingNozzle="A12", apiTipConfig=SINGLE, @@ -58,7 +58,7 @@ class PartialTipConfig: ninety_six_single_bottom_right = PartialTipConfig( key="ninety_six_single_bottom_right", - description="96 single bottom right", + description="96 single picking up bottom right of tiprack", startingTip="H12", startingNozzle="A1", apiTipConfig=SINGLE, @@ -70,7 +70,7 @@ class PartialTipConfig: ninety_six_column_left = PartialTipConfig( key="ninety_six_column_left", - description="96 column left", + description="96 column picking up left column of tiprack", startingTip="Column 1", startingNozzle="Column 12", apiTipConfig=COLUMN, @@ -81,7 +81,7 @@ class PartialTipConfig: ninety_six_column_right = PartialTipConfig( key="ninety_six_column_right", - description="96 column right", + description="96 column picking up right column of tiprack", startingTip="Row 12", startingNozzle="Row 1", apiTipConfig=COLUMN, @@ -93,7 +93,7 @@ class PartialTipConfig: ninety_six_row_top = PartialTipConfig( key="ninety_six_row_top", - description="96 row top", + description="96 row picking up top row of tiprack", startingTip="Row A", startingNozzle="Row H", apiTipConfig=ROW, @@ -103,7 +103,7 @@ class PartialTipConfig: ninety_six_row_bottom = PartialTipConfig( key="ninety_six_row_bottom", - description="96 row bottom", + description="96 row picking up bottom row of tiprack", startingTip="Row H", startingNozzle="Row A", apiTipConfig=ROW, @@ -112,10 +112,10 @@ class PartialTipConfig: ) # pipette = protocol.load_instrument(instrument_name="flex_8channel_50", mount="right") - +# works for all 8 channel pipettes eight_single_top = PartialTipConfig( key="eight_single_top", - description="8 single top", + description="8 channel single picking up from the top of the tiprack", startingTip="A1", startingNozzle="H1", apiTipConfig=SINGLE, @@ -125,7 +125,7 @@ class PartialTipConfig: eight_single_bottom = PartialTipConfig( key="eight_single_bottom", - description="8 single bottom", + description="8 channel single picking up from the bottom of the tiprack", startingTip="H1", startingNozzle="A1", apiTipConfig=SINGLE, diff --git a/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py new file mode 100644 index 00000000000..acf0fa1ded7 --- /dev/null +++ b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py @@ -0,0 +1,187 @@ +from dataclasses import dataclass +from typing import Optional +from opentrons.protocol_api import SINGLE, COLUMN, PARTIAL_COLUMN, ROW + +# inspired by https://opentrons.atlassian.net/browse/PLAT-457 + +metadata = { + "protocolName": "Invalid tip configs that should error", + "description": "oooo", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +@dataclass +class PartialTipConfig: + key: str + pipette_load_name: str + description: str + starting_tip: str + starting_nozzle: str + api_tip_config: str + api_start: str + api_end: Optional[str] = None + + +# Want to see +"Partial column configuration is only supported on 8-Channel pipettes" +ninety_six_partial_column_top = PartialTipConfig( + key="ninety_six_partial_column_top", + pipette_load_name="flex_96channel_1000ul", + description="96 2 tip pick up top left of tiprack", + starting_tip="A1", + starting_nozzle="H12", + api_tip_config=PARTIAL_COLUMN, + api_start="H12", + api_end="G12", +) + +# We do not allow PARTIAL_COLUMN to start on the bottom of the tip rack +# Want to see +# "IncompatibleNozzleConfiguration: Attempted Nozzle Configuration does not match any approved map layout for the current pipette." +eight_partial_column_bottom_left = PartialTipConfig( + key="eight_partial_column_bottom_left", + pipette_load_name="flex_8channel_1000", + description="8 channel 2 tip pick up bottom left of tiprack", + starting_tip="H1", + starting_nozzle="A1", + api_tip_config=PARTIAL_COLUMN, + api_start="A1", + api_end="B1", +) +# valid PARTIAL_COLUMN +# for PARTIAL_COLUMN, start must be H1 - which nozzle of the pipette to start at +# end is the nozzle to end at +# B1 = 7 tips +# C1 = 6 tips +# D1 = 5 tips +# E1 = 4 tips +# F1 = 3 tips +# G1 = 2 tips +# pipette.configure_nozzle_layout( +# style=PARTIAL_COLUMN, +# start="H1", # for partial column only H1 +# end="B1", # 2 Tips +# tip_racks=[partial_tip_rack], +# ) + +# invalid - this is the config in eight_partial_column_top +# start at A1 nozzle +# this is not permitted +# pipette.configure_nozzle_layout( +# style=PARTIAL_COLUMN, +# start="A1", +# end="G1", # 2 Tips +# tip_racks=[partial_tip_rack], +# ) + +# Want to see +# Error 4000 GENERAL_ERROR (ProtocolCommandFailedError): IncompatibleNozzleConfiguration: No entry for front right nozzle 'G12' in pipette +eight_partial_column_bottom_right = PartialTipConfig( + key="eight_partial_column_bottom_right", + pipette_load_name="flex_8channel_1000", + description="8 channel 2 tip pick up bottom left of tiprack", + starting_tip="H12", + starting_nozzle="A1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", # for partial column only H1 + api_end="G12", # the author thinks this is to specify the ending tip and wants to start at bottom right for 2 tips +) + + +# Partial column configurations require the 'end' parameter. +eight_partial_column_no_end = PartialTipConfig( + key="eight_partial_column_no_end", + pipette_load_name="flex_8channel_1000", + description="8 channel PARTIAL_COLUMN with no end", + starting_tip="H1", + starting_nozzle="A1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + # api_end="B1", sets the end to None +) + +# If you call return_tip() while using partial tip pickup, the API will raise an error. +# Error 4000 GENERAL_ERROR (UnexpectedProtocolError): Cannot return tip to a tiprack while the pipette is configured for partial tip. +return_tip_error = PartialTipConfig( + key="return_tip_error", + pipette_load_name="flex_8channel_1000", + description="8 channel 2 tip pick up top left of tiprack", + starting_tip="A1", + starting_nozzle="H1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="G1", # valid 2 tip +) + + +# pipette.drop_tip(tiprack["B1"]) # drops tip in rack location A1 +drop_tip_with_location = PartialTipConfig( + key="drop_tip_with_location", + pipette_load_name="flex_8channel_1000", + description="8 channel 2 tip pick up top left of tiprack", + starting_tip="A1", + starting_nozzle="H1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="G1", # valid 2 tip +) + +all_partial_configs = [ + ninety_six_partial_column_top, + eight_partial_column_bottom_left, + eight_partial_column_bottom_right, + eight_partial_column_no_end, + return_tip_error, + drop_tip_with_location, +] + + +def find_partial_tip_config(key: str) -> Optional[PartialTipConfig]: + for config in all_partial_configs: + if config.key == key: + return config + raise ValueError(f"Could not find partial tip config with key {key}") + + +key = "drop_tip_with_location" + + +def comment_column_has_tip(ctx, tip_rack, column): + range_A_to_H = [chr(i) for i in range(ord("A"), ord("H") + 1)] + wells = [f"{row}{column}" for row in range_A_to_H] + for well in wells: + ctx.comment(f"Tip rack in {tip_rack.parent}, well {well} has tip: {tip_rack.wells_by_name()[well].has_tip}") + + +def run(ctx): + tip_rack = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B2") + + pipette_config = find_partial_tip_config(key) + + pipette = ctx.load_instrument(pipette_config.pipette_load_name, "left") + + pipette.configure_nozzle_layout( + style=pipette_config.api_tip_config, start=pipette_config.api_start, end=pipette_config.api_end, tip_racks=[tip_rack] + ) + + target_labware_loadname = "nest_96_wellplate_100ul_pcr_full_skirt" + source = ctx.load_labware(target_labware_loadname, "D2") + destination = ctx.load_labware(target_labware_loadname, "D3") + + trash = ctx.load_trash_bin("A3") + if key == "return_tip_error": + pipette.pick_up_tip() + # this test picks up 2 tips + comment_column_has_tip(ctx, tip_rack, 1) + pipette.return_tip() # this should raise an error + elif key == "drop_tip_with_location": + pipette.pick_up_tip() + comment_column_has_tip(ctx, tip_rack, 1) + pipette.drop_tip(tip_rack["B1"]) # this should raise an error + else: + pipette.transfer(10, source["A1"], destination["A1"]) diff --git a/analyses-snapshot-testing/files/templates/partial_tip_rtp.py b/analyses-snapshot-testing/files/templates/partial_tip_rtp.py new file mode 100644 index 00000000000..6aa47d44455 --- /dev/null +++ b/analyses-snapshot-testing/files/templates/partial_tip_rtp.py @@ -0,0 +1,297 @@ +from dataclasses import dataclass +from typing import Optional +from opentrons.protocol_api import SINGLE, COLUMN, PARTIAL_COLUMN, ROW + +metadata = { + "protocolName": "RTP template for partial tip config", + "description": "These are all the viable partial tip configurations for the Flex 96 and 8 channel pipettes", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + +####### RTP DEFINITIONS ####### + + +@dataclass +class PartialTipConfig: + """Dataclass to hold a partial tip configuration descriptively.""" + + key: str + description: str + starting_tip: str + starting_nozzle: str + api_tip_config: str + api_start: str + api_end: Optional[str] + + def __str__(self): + return ( + f"🔑 Key: {self.key} | 📝 Description: {self.description} | " + f"💉 Starting Tip: {self.starting_tip} | 🔧 Starting Nozzle: {self.starting_nozzle} | " + f"📜 API Tip Config: {self.api_tip_config} | 🚀 API Start: {self.api_start} | " + f"🛑 API End: {self.api_end if self.api_end else 'None'}" + ) + + +#### Define all viable partial tip configurations. + +# flex_96channel_1000 SINGLE +# names and descriptions describe where relative to the tiprack the pipette will pick up tips + +ninety_six_single_back_left = PartialTipConfig( + key="ninety_six_single_back_left", + description="96 single picking up back left of tiprack", + starting_tip="A1", + starting_nozzle="H12", + api_tip_config=SINGLE, + api_start="H12", + api_end=None, +) + +ninety_six_single_back_right = PartialTipConfig( + key="ninety_six_single_back_right", + description="96 single picking up back right of tiprack", + starting_tip="A12", + starting_nozzle="H1", + api_tip_config=SINGLE, + api_start="H1", + api_end=None, +) + +ninety_six_single_front_left = PartialTipConfig( + key="ninety_six_single_front_left", + description="96 single picking up front left of tiprack", + starting_tip="H1", + starting_nozzle="A12", + api_tip_config=SINGLE, + api_start="A12", + api_end=None, +) + +ninety_six_single_front_right = PartialTipConfig( + key="ninety_six_single_front_right", + description="96 single picking up front right of tiprack", + starting_tip="H12", + starting_nozzle="A1", + api_tip_config=SINGLE, + api_start="A1", + api_end=None, +) + +# flex_96channel_1000 COLUMN + +ninety_six_column_left = PartialTipConfig( + key="ninety_six_column_left", + description="96 column picking up left column of tiprack", + starting_tip="Column 1", + starting_nozzle="Column 12", + api_tip_config=COLUMN, + api_start="A12", + api_end=None, +) + + +ninety_six_column_right = PartialTipConfig( + key="ninety_six_column_right", + description="96 column picking up right column of tiprack", + starting_tip="Row 12", + starting_nozzle="Row 1", + api_tip_config=COLUMN, + api_start="A1", + api_end=None, +) + +# flex_96channel_1000 ROW + +ninety_six_row_back = PartialTipConfig( + key="ninety_six_row_back", + description="96 row picking up back row of tiprack", + starting_tip="Row A", + starting_nozzle="Row H", + api_tip_config=ROW, + api_start="H1", + api_end=None, +) + +ninety_six_row_front = PartialTipConfig( + key="ninety_six_row_front", + description="96 row picking up front row of tiprack", + starting_tip="Row H", + starting_nozzle="Row A", + api_tip_config=ROW, + api_start="A1", + api_end=None, +) + +# 8 channel SINGLE +eight_single_back = PartialTipConfig( + key="eight_single_back", + description="8 channel single picking up from the back left of the tiprack", + starting_tip="A1", + starting_nozzle="H1", + api_tip_config=SINGLE, + api_start="H1", + api_end=None, +) + +eight_single_front = PartialTipConfig( + key="eight_single_front", + description="8 channel single picking up from the front left of the tiprack", + starting_tip="H1", + starting_nozzle="A1", + api_tip_config=SINGLE, + api_start="A1", + api_end=None, +) + +# PARTIAL_COLUMN +eight_partial_back_7_tips = PartialTipConfig( + key="eight_partial_back_7_tips", + description="8 channel picking up 7 tips", + starting_tip="H1", + starting_nozzle="B1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="B1", +) + +eight_partial_back_6_tips = PartialTipConfig( + key="eight_partial_back_6_tips", + description="8 channel picking up 6 tips", + starting_tip="H1", + starting_nozzle="C1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="C1", +) +eight_partial_back_5_tips = PartialTipConfig( + key="eight_partial_back_5_tips", + description="8 channel picking up 5 tips", + starting_tip="H1", + starting_nozzle="D1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="D1", +) +eight_partial_back_4_tips = PartialTipConfig( + key="eight_partial_back_4_tips", + description="8 channel picking up 4 tips", + starting_tip="H1", + starting_nozzle="E1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="E1", +) +eight_partial_back_3_tips = PartialTipConfig( + key="eight_partial_back_3_tips", + description="8 channel picking up 3 tips", + starting_tip="H1", + starting_nozzle="F1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="F1", +) + +eight_partial_back_2_tips = PartialTipConfig( + key="eight_partial_back_2_tips", + description="8 channel picking up 2 tips", + starting_tip="H1", + starting_nozzle="G1", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="G1", +) + +# make a list of all the partial tip configurations + +all_partial_configs = [ + ninety_six_single_back_left, + ninety_six_single_back_right, + ninety_six_single_front_left, + ninety_six_single_front_right, + ninety_six_column_left, + ninety_six_column_right, + ninety_six_row_back, + ninety_six_row_front, + eight_single_back, + eight_single_front, + eight_partial_back_2_tips, + eight_partial_back_3_tips, + eight_partial_back_4_tips, + eight_partial_back_5_tips, + eight_partial_back_6_tips, + eight_partial_back_7_tips, +] + + +def find_partial_tip_config(key: str) -> Optional[PartialTipConfig]: + """Find a partial tip config by key.""" + for config in all_partial_configs: + if config.key == key: + return config + raise ValueError(f"Could not find partial tip config with key {key}") + + +def add_parameters(p): + p.add_str( + display_name="Partial Tip Configuration", + variable_name="partial_tip_config_key", + default="eight_partial_back_5_tips", + description="Partial tip configurations described relative to the tiprack.", + choices=[ # value of each choice maps to the key of the partial tip config dataclass we defined + {"display_name": "96 SINGLE back left", "value": "ninety_six_single_back_left"}, + {"display_name": "96 SINGLE back right", "value": "ninety_six_single_back_right"}, + {"display_name": "96 SINGLE front left", "value": "ninety_six_single_front_left"}, + {"display_name": "96 SINGLE front right", "value": "ninety_six_single_front_right"}, + {"display_name": "96 COLUMN left", "value": "ninety_six_column_left"}, + {"display_name": "96 COLUMN right", "value": "ninety_six_column_right"}, + {"display_name": "96 ROW back", "value": "ninety_six_row_back"}, + {"display_name": "96 ROW front", "value": "ninety_six_row_front"}, + {"display_name": "8 SINGLE back left", "value": "eight_single_back"}, + {"display_name": "8 SINGLE front left", "value": "eight_single_front"}, + {"display_name": "8 PARTIAL back left - 2 tips", "value": "eight_partial_back_2_tips"}, + {"display_name": "8 PARTIAL back left - 3 tips", "value": "eight_partial_back_3_tips"}, + {"display_name": "8 PARTIAL back left - 4 tips", "value": "eight_partial_back_4_tips"}, + {"display_name": "8 PARTIAL back left - 5 tips", "value": "eight_partial_back_5_tips"}, + {"display_name": "8 PARTIAL back left - 6 tips", "value": "eight_partial_back_6_tips"}, + {"display_name": "8 PARTIAL back left - 7 tips", "value": "eight_partial_back_7_tips"}, + ], + ) + + +####### END RTP DEFINITIONS ####### + + +def set_configure_nozzle_layout(pipette, tipracks, tip_config): + """Convenience function to set the nozzle layout of a pipette + with the given tip config we have mapped to a RTP.""" + pipette.configure_nozzle_layout(style=tip_config.api_tip_config, start=tip_config.api_start, end=tip_config.api_end, tip_racks=tipracks) + + +def comment_column_has_tip(ctx, tip_rack, column): + """Print out the tip status of a column in a tip rack.""" + range_A_to_H = [chr(i) for i in range(ord("A"), ord("H") + 1)] + wells = [f"{row}{column}" for row in range_A_to_H] + for well in wells: + ctx.comment(f"Tip rack in {tip_rack.parent}, well {well} has tip: {tip_rack.wells_by_name()[well].has_tip}") + + +def run(ctx): + # get the key from the parameters + tip_config = find_partial_tip_config(ctx.params.partial_tip_config_key) + # print out the tip config + ctx.comment(f"Running with {tip_config}") + # example code on Flex for a pipette + # comment shows we picked up the tips we expected + tip_rack = ctx.load_labware("opentrons_flex_96_tiprack_1000ul", "B2") + pipette = ctx.load_instrument("flex_8channel_1000", "left") + # use this convenience function to set the nozzle layout + set_configure_nozzle_layout(pipette=pipette, tipracks=[tip_rack], tip_config=tip_config) + pipette.pick_up_tip() + # our config picked up from column 1 of the tip rack + # print out the tip status of column 1 of the tip rack + # to confirm we picked up the tip(s) we expected + comment_column_has_tip(ctx, tip_rack, "1")