From c89519f451ef473edad712e7a0c0f03df0b145d5 Mon Sep 17 00:00:00 2001 From: Josh McVey Date: Fri, 13 Sep 2024 14:14:07 -0500 Subject: [PATCH] map --- .../automation/data/protocols.py | 55 ++++++++++++++++ .../data/protocols_with_overrides.py | 53 +++++++++++++++ ...lex_S_v2_20_96_None_SINGLE_4Corners50ul.py | 66 +++++++++++++++++++ ..._v2_20_96_None_Overrides_TooTallLabware.py | 2 +- ...v2_20_96_and_8_Overrides_InvalidConfigs.py | 64 +++++++++--------- 5 files changed, 206 insertions(+), 34 deletions(-) create mode 100644 analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py diff --git a/analyses-snapshot-testing/automation/data/protocols.py b/analyses-snapshot-testing/automation/data/protocols.py index 580c9183d9d..0e621463dd8 100644 --- a/analyses-snapshot-testing/automation/data/protocols.py +++ b/analyses-snapshot-testing/automation/data/protocols.py @@ -641,6 +641,61 @@ class Protocols: robot="Flex", ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath.py + Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath: Protocol = Protocol( + file_stem="Flex_S_v2_20_8_None_PARTIAL_COLUMN_HappyPath", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_8_None_SINGLE_HappyPath.py + Flex_S_v2_20_8_None_SINGLE_HappyPath: Protocol = Protocol( + file_stem="Flex_S_v2_20_8_None_SINGLE_HappyPath", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_AllCorners.py + Flex_S_v2_20_96_AllCorners: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_AllCorners", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_COLUMN_HappyPath.py + Flex_S_v2_20_96_None_COLUMN_HappyPath: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_COLUMN_HappyPath", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_Column3_SINGLE_.py + Flex_S_v2_20_96_None_Column3_SINGLE_: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_Column3_SINGLE_", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_ROW_HappyPath.py + Flex_S_v2_20_96_None_ROW_HappyPath: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_ROW_HappyPath", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py + Flex_S_v2_20_96_None_SINGLE_4Corners50ul: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_SINGLE_4Corners50ul", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide.py + Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_SINGLE_HappyPathNorthSide", + file_extension="py", + robot="Flex", + ) + # analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide.py + Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide: Protocol = Protocol( + file_stem="Flex_S_v2_20_96_None_SINGLE_HappyPathSouthSide", + file_extension="py", + robot="Flex", + ) + OT2_X_v2_18_None_None_duplicateRTPVariableName: Protocol = Protocol( file_stem="OT2_X_v2_18_None_None_duplicateRTPVariableName", file_extension="py", diff --git a/analyses-snapshot-testing/automation/data/protocols_with_overrides.py b/analyses-snapshot-testing/automation/data/protocols_with_overrides.py index ff4a900e58d..7685b482939 100644 --- a/analyses-snapshot-testing/automation/data/protocols_with_overrides.py +++ b/analyses-snapshot-testing/automation/data/protocols_with_overrides.py @@ -38,3 +38,56 @@ class ProtocolsWithOverrides: override_variable_name="type_to_test", overrides=["str_default_no_matching_choices", "float_default_no_matching_choices", "int_default_no_matching_choices"], ) + + # analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs.py + + Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs: ProtocolWithOverrides = ProtocolWithOverrides( + file_stem="Flex_X_v2_20_96_and_8_Overrides_InvalidConfigs", + file_extension="py", + robot="Flex", + override_variable_name="key", + overrides=[ + "ninety_six_partial_column_1", + "ninety_six_partial_column_2", + "ninety_six_partial_column_3", + "eight_partial_column_bottom_left", + "eight_partial_column_bottom_right", + "eight_partial_column_no_end", + "return_tip_error", + "drop_tip_with_location", + ], + ) + + # analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py + + Flex_X_v2_20_96_None_Overrides_TooTallLabware: ProtocolWithOverrides = ProtocolWithOverrides( + file_stem="Flex_X_v2_20_96_None_Overrides_TooTallLabware", + file_extension="py", + robot="Flex", + override_variable_name="key", + overrides=[ + "transfer_source_collision", + "transfer_destination_collision", + "c3_right_edge", + "north", + "north_west", + "west", + "south_west", + "south", + "south_east", + "east", + "east_column", + "west_column", + "north_row", + "south_row", + "top_edge", + "bottom_left_edge", + "bottom_left_edge", + "bottom_right_edge", + "mix_collision", + "consolidate_source_collision", + "consolidate_destination_collision", + "distribute_source_collision", + "distribute_destination_collision", + ], + ) diff --git a/analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py b/analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py new file mode 100644 index 00000000000..1ac96b7a7ac --- /dev/null +++ b/analyses-snapshot-testing/files/protocols/Flex_S_v2_20_96_None_SINGLE_4Corners50ul.py @@ -0,0 +1,66 @@ +from opentrons.protocol_api import SINGLE + +metadata = { + "protocolName": "96Channel SINGLE Pickup on all 4 corners 2 pickups", + "description": "96 2 tips picked up on all 4 corners of the tip rack", +} + +requirements = { + "robotType": "Flex", + "apiLevel": "2.20", +} + + +def comment_tip_rack_status(ctx, tip_rack): + """ + Print out the tip status for each row in a tip rack. + Each row (A-H) will print the well statuses for columns 1-12 in a single comment, + with a '🟢' for present tips and a '❌' for missing tips. + """ + range_A_to_H = [chr(i) for i in range(ord("A"), ord("H") + 1)] + range_1_to_12 = range(1, 13) + + ctx.comment(f"Tip rack in {tip_rack.parent}") + + for row in range_A_to_H: + status_line = f"{row}: " + for col in range_1_to_12: + well = f"{row}{col}" + has_tip = tip_rack.wells_by_name()[well].has_tip + status_emoji = "🟢" if has_tip else "❌" + status_line += f"{well} {status_emoji} " + + # Print the full status line for the row + ctx.comment(status_line) + + +def run(protocol): + + trash = protocol.load_trash_bin("A3") # must load trash bin + + four_corners = ["A1", "A12", "H1", "H12"] + + partial_tip_rack = protocol.load_labware( + load_name="opentrons_flex_96_tiprack_50ul", + label="Partial Tip Rack", + location="C2", + ) + + pipette = protocol.load_instrument(instrument_name="flex_96channel_1000") + + for corner in four_corners: + + pipette.configure_nozzle_layout( + style=SINGLE, + start=corner, + tip_racks=[partial_tip_rack], + ) + + pipette.pick_up_tip() + comment_tip_rack_status(protocol, partial_tip_rack) + protocol.pause("How was the pickup of first tip?") + pipette.drop_tip() + pipette.pick_up_tip() + comment_tip_rack_status(protocol, partial_tip_rack) + protocol.pause("How was the pickup of second tip?") + pipette.drop_tip() diff --git a/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py index 63c456f8c53..d717c497655 100644 --- a/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py +++ b/analyses-snapshot-testing/files/protocols/Flex_X_v2_20_96_None_Overrides_TooTallLabware.py @@ -450,7 +450,7 @@ def get_test_case(key: str) -> Optional[TestCase]: def run(ctx): tall_labware_loadname = "opentrons_10_tuberack_falcon_4x50ml_6x15ml_conical" - test_case = get_test_case(TEST_KEY) + test_case = get_test_case(key) if test_case.tip_rack_slot and test_case.tip_rack_slot != "C2": tip_rack = ctx.load_labware("opentrons_96_tiprack_1000ul", test_case.tip_rack_slot) 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 index acf0fa1ded7..9d275c2db84 100644 --- 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 @@ -1,6 +1,6 @@ from dataclasses import dataclass from typing import Optional -from opentrons.protocol_api import SINGLE, COLUMN, PARTIAL_COLUMN, ROW +from opentrons.protocol_api import PARTIAL_COLUMN # inspired by https://opentrons.atlassian.net/browse/PLAT-457 @@ -29,9 +29,9 @@ class PartialTipConfig: # 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", +ninety_six_partial_column_1 = PartialTipConfig( + key="ninety_six_partial_column_1", + pipette_load_name="flex_96channel_1000", description="96 2 tip pick up top left of tiprack", starting_tip="A1", starting_nozzle="H12", @@ -40,6 +40,29 @@ class PartialTipConfig: api_end="G12", ) +# https://opentrons.atlassian.net/browse/PLAT-457 +ninety_six_partial_column_2 = PartialTipConfig( + key="ninety_six_partial_column_2", + pipette_load_name="flex_96channel_1000", + description="Full row", + starting_tip="A1", + starting_nozzle="H12", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="A1", +) + +ninety_six_partial_column_3 = PartialTipConfig( + key="ninety_six_partial_column_3", + pipette_load_name="flex_96channel_1000", + description="Full Row", + starting_tip="A1", + starting_nozzle="H12", + api_tip_config=PARTIAL_COLUMN, + api_start="H1", + api_end="H12", +) + # 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." @@ -53,31 +76,7 @@ class PartialTipConfig: 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 @@ -132,7 +131,9 @@ class PartialTipConfig: ) all_partial_configs = [ - ninety_six_partial_column_top, + ninety_six_partial_column_1, + ninety_six_partial_column_2, + ninety_six_partial_column_3, eight_partial_column_bottom_left, eight_partial_column_bottom_right, eight_partial_column_no_end, @@ -148,9 +149,6 @@ def find_partial_tip_config(key: str) -> Optional[PartialTipConfig]: 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]