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

test(analyses): add 8.2 features to analyses battery #17134

Open
wants to merge 2 commits into
base: edge
Choose a base branch
from
Open
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
17 changes: 17 additions & 0 deletions analyses-snapshot-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,20 @@ You have the option to specify one or many protocols to run the analyses on. Thi
### Updating the snapshots locally

- `make snapshot-test-update-local` - this target builds the base image, builds the local code into the base image, then runs the analyses battery against the image you just created, updating the snapshots by passing the `--update-snapshots` flag to the test

### Add some protocols to the analyses battery
Comment on lines +89 to +90
Copy link
Contributor

Choose a reason for hiding this comment

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

TY for the docs!


> The below instructions avoid needing docker and executing snapshot tests locally.

1. create new protocol file(s) in the [files/protocols](./files/protocols) directory following the naming convention in [files/README.md](./files/README.md)
1. add the protocol(s) to the [protocols.py](./automation/data/protocols.py)
1. `make format` (make sure you have followed setup instructions)
1. commit and push your branch
1. open a PR and add the label `gen-analyses-snapshot-pr`
1. when the snapshot fails because your new protocols don't have snapshots a PR will be created that heals.
1. merge the healing PR if the snapshots are as expected
1. get a review and merge! 🎉 now your protocols are a part of the test

### Add a protocol with overrides to the analyses battery

> TODO when we have a more straight forward example
42 changes: 42 additions & 0 deletions analyses-snapshot-testing/automation/data/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,48 @@ class Protocols:
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_plate_reader_no_trash.py
Flex_X_v2_21_plate_reader_no_trash: Protocol = Protocol(
file_stem="Flex_X_v2_21_plate_reader_no_trash",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_plate_reader_wrong_plate.py
Flex_X_v2_21_plate_reader_wrong_plate: Protocol = Protocol(
file_stem="Flex_X_v2_21_plate_reader_wrong_plate",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_plate_reader_wrong_plate2.py
Flex_X_v2_21_plate_reader_wrong_plate2: Protocol = Protocol(
file_stem="Flex_X_v2_21_plate_reader_wrong_plate2",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_plate_reader_bad_slot.py
Flex_X_v2_21_plate_reader_bad_slot: Protocol = Protocol(
file_stem="Flex_X_v2_21_plate_reader_bad_slot",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_plate_reader_no_close_lid.py
Flex_X_v2_21_plate_reader_no_close_lid: Protocol = Protocol(
file_stem="Flex_X_v2_21_plate_reader_no_close_lid",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_S_v2_21_tc_lids_happy_path.py
Flex_S_v2_21_tc_lids_happy_path: Protocol = Protocol(
file_stem="Flex_S_v2_21_tc_lids_happy_path",
file_extension="py",
robot="Flex",
)
# analyses-snapshot-testing/files/protocols/Flex_X_v2_21_tc_lids_wrong_target.py
Flex_X_v2_21_tc_lids_wrong_target: Protocol = Protocol(
file_stem="Flex_X_v2_21_tc_lids_wrong_target",
file_extension="py",
robot="Flex",
)

OT2_X_v2_18_None_None_duplicateRTPVariableName: Protocol = Protocol(
file_stem="OT2_X_v2_18_None_None_duplicateRTPVariableName",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from typing import List, Dict, Any, Optional
from opentrons.protocol_api import ProtocolContext, Labware

metadata = {"protocolName": "Opentrons Flex Deck Riser with TC Lids Test"}
requirements = {"robotType": "Flex", "apiLevel": "2.21"}


"""
Setup:
- 1-5x lids are stacked in deck D2
- Thermocycler installed

Run:
- For each lid in the stack (1-5x)
- Move lid in D2 to Thermocycler
- Remove top-most lid
- PAUSE, wait for tester to press continue
- Move lid from Thermocycler to new slot C2
- Stacked onto any previously placed lids
"""

LID_STARTING_SLOT = "B2"
LID_ENDING_SLOT = "C2"
LID_COUNT = 3
LID_DEFINITION = "opentrons_tough_pcr_auto_sealing_lid"
LID_BOTTOM_DEFINITION = "opentrons_tough_pcr_auto_sealing_lid"
DECK_RISER_NAME = "opentrons_flex_deck_riser"
USING_THERMOCYCLER = True

OFFSET_DECK = {
"pick-up": {"x": 0, "y": 0, "z": 0},
"drop": {"x": 0, "y": 0, "z": 0},
}
OFFSET_THERMOCYCLER = {
"pick-up": {"x": 0, "y": 0, "z": 0},
"drop": {"x": 0, "y": 0, "z": 0},
}


def _move_labware_with_offset_and_pause(
protocol: ProtocolContext,
labware: Labware,
destination: Any,
pick_up_offset: Optional[Dict[str, float]] = None,
drop_offset: Optional[Dict[str, float]] = None,
) -> None:
protocol.move_labware(
labware,
destination,
use_gripper=True,
pick_up_offset=pick_up_offset,
drop_offset=drop_offset,
)


def run(protocol: ProtocolContext):
# SETUP
deck_riser_adapter = protocol.load_adapter(DECK_RISER_NAME, "B2")

lids: List[Labware] = [deck_riser_adapter.load_labware(LID_BOTTOM_DEFINITION)]
for i in range(LID_COUNT - 1):
lids.append(lids[-1].load_labware(LID_DEFINITION))
lids.reverse() # NOTE: reversing to more easily loop through lids from top-to-bottom
if USING_THERMOCYCLER:
# TODO: confirm if we need to load 96-well adapter onto Thermocycler
thermocycler = protocol.load_module("thermocyclerModuleV2")
thermocycler.open_lid()
plate_in_cycler = thermocycler.load_labware("armadillo_96_wellplate_200ul_pcr_full_skirt")
else:
plate_in_cycler = None

# RUN
prev_moved_lid: Optional[Labware] = None
for lid in lids:

if USING_THERMOCYCLER:
_move_labware_with_offset_and_pause(
protocol,
lid,
plate_in_cycler,
pick_up_offset=OFFSET_DECK["pick-up"],
drop_offset=OFFSET_THERMOCYCLER["drop"],
)
_move_labware_with_offset_and_pause(
protocol,
lid,
prev_moved_lid if prev_moved_lid else LID_ENDING_SLOT,
pick_up_offset=OFFSET_THERMOCYCLER["pick-up"],
drop_offset=OFFSET_DECK["drop"],
)
else:
_move_labware_with_offset_and_pause(
protocol,
lid,
prev_moved_lid if prev_moved_lid else LID_ENDING_SLOT,
pick_up_offset=OFFSET_DECK["pick-up"],
drop_offset=OFFSET_DECK["drop"],
)
prev_moved_lid = lid
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import cast
from opentrons import protocol_api
from opentrons.protocol_api.module_contexts import AbsorbanceReaderContext

from opentrons import protocol_api
from opentrons.protocol_api import SINGLE, ALL

requirements = {"robotType": "Flex", "apiLevel": "2.21"}
metadata = {"protocolName": "plate_reader bad slot"}


def run(protocol: protocol_api.ProtocolContext):
partial_rack = protocol.load_labware(load_name="opentrons_flex_96_tiprack_1000ul", location="D3")
trash = protocol.load_trash_bin("A3")
instrument = protocol.load_instrument(instrument_name="flex_8channel_1000", mount="right")
instrument.configure_nozzle_layout(style=SINGLE, start="H1", tip_racks=[partial_rack])

plate_1 = protocol.load_labware("nest_96_wellplate_200ul_flat", "D1")
mod = protocol.load_module("absorbanceReaderV1", "C1")
mod.open_lid()
protocol.move_labware(plate_1, mod, use_gripper=True)
mod.close_lid()
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from typing import cast
from opentrons import protocol_api
from opentrons.protocol_api.module_contexts import AbsorbanceReaderContext

# metadata
metadata = {
"protocolName": "Absorbance Reader no close lid",
"author": "Platform Expansion",
}

requirements = {
"robotType": "Flex",
"apiLevel": "2.21",
}


# protocol run function
def run(protocol: protocol_api.ProtocolContext):
mod = cast(AbsorbanceReaderContext, protocol.load_module("absorbanceReaderV1", "D3"))
plate = protocol.load_labware("nest_96_wellplate_200ul_flat", "C2")
tiprack_1000 = protocol.load_labware(load_name="opentrons_flex_96_tiprack_50ul", location="B2")
trash_labware = protocol.load_trash_bin("B3")
instrument = protocol.load_instrument("flex_8channel_50", "right", tip_racks=[tiprack_1000])

# pick up tip and perform action
instrument.pick_up_tip(tiprack_1000.wells_by_name()["A1"])
instrument.aspirate(30, plate.wells_by_name()["A1"])
instrument.dispense(30, plate.wells_by_name()["B1"])
instrument.return_tip()

# Initialize to a single wavelength with reference wavelength
# Issue: Make sure there is no labware here or youll get an error
# mod.close_lid()
mod.initialize("single", [600], 450)

# NOTE: CANNOT INITIALIZE WITH THE LID OPEN

# Remove the Plate Reader lid using the Gripper.
mod.open_lid()
protocol.move_labware(plate, mod, use_gripper=True)
mod.close_lid()

# Take a reading and show the resulting absorbance values.
# Issue: cant read before you initialize or you an get an error
result = mod.read()
msg = f"single: {result}"
protocol.comment(msg=msg)
protocol.pause(msg=msg)

# Initialize to multiple wavelengths
protocol.pause(msg="Perform Multi Read")
mod.open_lid()
protocol.move_labware(plate, "C2", use_gripper=True)

mod.close_lid()

# mod.initialize('multi', [450, 570, 600])
mod.initialize("multi", [450, 600])
# Open the lid and move the labware into the reader
mod.open_lid()
protocol.move_labware(plate, mod, use_gripper=True)

# pick up tip and perform action on labware inside plate reader
instrument.pick_up_tip(tiprack_1000.wells_by_name()["A1"])
instrument.aspirate(30, plate.wells_by_name()["A1"])
instrument.dispense(30, plate.wells_by_name()["B1"])
instrument.return_tip()

mod.close_lid()

# Take reading
result = mod.read()
msg = f"multi: {result}"
protocol.comment(msg=msg)
protocol.pause(msg=msg)

# Take a reading and save to csv
protocol.pause(msg="Perform Read and Save to CSV")
result = mod.read(export_filename="plate_reader_csv.csv")
msg = f"csv: {result}"
protocol.pause(msg=msg)

# Place the Plate Reader lid back on using the Gripper.
mod.open_lid()
protocol.move_labware(plate, "C2", use_gripper=True)
mod.close_lid()

mod.read(export_filename="csv_name.csv")
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import cast
from opentrons import protocol_api
from opentrons.protocol_api.module_contexts import AbsorbanceReaderContext

from opentrons import protocol_api
from opentrons.protocol_api import SINGLE, ALL

requirements = {"robotType": "Flex", "apiLevel": "2.21"}
metadata = {"protocolName": "plate_reader no trash"}


def run(protocol: protocol_api.ProtocolContext):
partial_rack = protocol.load_labware(load_name="opentrons_flex_96_tiprack_1000ul", location="D2")
trash = protocol.load_trash_bin("A3")
instrument = protocol.load_instrument(instrument_name="flex_8channel_1000", mount="right")
instrument.configure_nozzle_layout(style=SINGLE, start="H1", tip_racks=[partial_rack])

plate_1 = protocol.load_labware("nest_96_wellplate_200ul_flat", "C1")

mod = protocol.load_module("absorbanceReaderV1", "B3")

mod.open_lid()
protocol.move_labware(plate_1, mod, use_gripper=True)
protocol.move_labware(plate_1, trash, use_gripper=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import cast
from opentrons import protocol_api
from opentrons.protocol_api.module_contexts import AbsorbanceReaderContext

from opentrons import protocol_api
from opentrons.protocol_api import SINGLE, ALL

requirements = {"robotType": "Flex", "apiLevel": "2.21"}
metadata = {"protocolName": "plate_reader wrong plate"}


def run(protocol: protocol_api.ProtocolContext):
partial_rack = protocol.load_labware(load_name="opentrons_flex_96_tiprack_1000ul", location="D2")
trash = protocol.load_trash_bin("A3")
instrument = protocol.load_instrument(instrument_name="flex_8channel_1000", mount="right")
instrument.configure_nozzle_layout(style=SINGLE, start="H1", tip_racks=[partial_rack])

plate_1 = protocol.load_labware("corning_12_wellplate_6.9ml_flat", "C2")

mod = protocol.load_module("absorbanceReaderV1", "B3")

mod.open_lid()
protocol.move_labware(plate_1, mod, use_gripper=True)
protocol.move_labware(plate_1, trash, use_gripper=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import cast
from opentrons import protocol_api
from opentrons.protocol_api.module_contexts import AbsorbanceReaderContext

from opentrons import protocol_api
from opentrons.protocol_api import SINGLE, ALL

requirements = {"robotType": "Flex", "apiLevel": "2.21"}
metadata = {"protocolName": "plate_reader wrong plate"}


def run(protocol: protocol_api.ProtocolContext):
partial_rack = protocol.load_labware(load_name="opentrons_flex_96_tiprack_1000ul", location="D2")
trash = protocol.load_trash_bin("A3")
instrument = protocol.load_instrument(instrument_name="flex_8channel_1000", mount="right")
instrument.configure_nozzle_layout(style=SINGLE, start="H1", tip_racks=[partial_rack])

plate_1 = protocol.load_labware("thermoscientificnunc_96_wellplate_2000ul", "C2")

mod = protocol.load_module("absorbanceReaderV1", "B3")

mod.open_lid()
protocol.move_labware(plate_1, mod, use_gripper=True)
protocol.move_labware(plate_1, trash, use_gripper=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import List, Dict, Any, Optional
from opentrons.protocol_api import ProtocolContext, Labware

metadata = {"Stacking a deep well plate on its adapter "}
requirements = {"robotType": "Flex", "apiLevel": "2.21"}


def run(protocol: ProtocolContext):
temp_mod = protocol.load_module(module_name="temperature module gen2", location="D1")
LID_COUNT = 5
LID_DEFINITION = "opentrons_tough_pcr_auto_sealing_lid"
LID_BOTTOM_DEFINITION = "opentrons_tough_pcr_auto_sealing_lid"
adapter = temp_mod.load_adapter("opentrons_96_deep_well_temp_mod_adapter")
stack = protocol.load_labware("nest_96_wellplate_2ml_deep", "A1")
deck_riser_adapter = protocol.load_adapter("opentrons_flex_deck_riser", "B2")
protocol.move_labware(stack, adapter)
lids = [deck_riser_adapter.load_labware(LID_BOTTOM_DEFINITION, "D2")]
for i in range(LID_COUNT - 1):
lids.append(lids[-1].load_labware(LID_DEFINITION))
lids.reverse() # NOTE: reversing to more easily loop through lids from top-to-bottom

protocol.move_labware(
lids[0],
stack,
use_gripper=True,
)
Loading
Loading