def test_tip_tracking_init(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert tiprack.is_tiprack for well in tiprack.wells(): assert well.has_tip labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert not lw.is_tiprack for well in lw.wells(): assert not well.has_tip
def test_no_labware_loc(): labware_def = labware.get_labware_definition(labware_name) deck = Deck() lw1 = labware.load(labware_name, deck.position_for(1)) lw2 = labware.load(labware_name, deck.position_for(2)) # Various flavors of locations without labware should work no_lw = lw1.wells()[0].top()._replace(labware=None) no_from = plan_moves(no_lw, lw2.wells()[0].bottom(), deck, 7.0, 15.0) check_arc_basic(no_from, no_lw, lw2.wells()[0].bottom()) assert no_from[0][0].z == deck.highest_z + 15.0 no_to = plan_moves(lw1.wells()[0].bottom(), no_lw, deck, 7.0, 15.0) check_arc_basic(no_to, lw1.wells()[0].bottom(), no_lw) assert no_from[0][0].z == deck.highest_z + 15.0 no_well = lw1.wells()[0].top()._replace(labware=lw1) no_from_well = plan_moves(no_well, lw1.wells()[1].top(), deck, 7.0, 15.0) check_arc_basic(no_from_well, no_well, lw1.wells()[1].top()) assert no_from_well[0][0].z\ == labware_def['dimensions']['zDimension'] + 7.0 no_to_well = plan_moves(lw1.wells()[1].top(), no_well, deck, 7.0, 15.0) check_arc_basic(no_to_well, lw1.wells()[1].top(), no_well) assert no_to_well[0][0].z\ == labware_def['dimensions']['zDimension'] + 7.0
def test_add_index_file(labware_name, index_file_dir): deck = Deck() parent = deck.position_for(1) definition = labware.get_labware_definition(labware_name) lw = labware.Labware(definition, parent) labware_hash = labware._hash_labware_def(lw._definition) labware._add_to_index_offset_file(lw, labware_hash) lw_uri = labware.uri_from_definition(definition) str_parent = labware._get_parent_identifier(lw.parent) slot = '1' if str_parent: mod_dict = {str_parent: f'{slot}-{str_parent}'} else: mod_dict = {} blob = { "id": f'{labware_hash}', "slot": f'{labware_hash}{str_parent}', "module": mod_dict } lw_path = index_file_dir / 'index.json' info = labware._read_file(lw_path) assert info[lw_uri] == blob
def load_new_labware(container_name): """ Load a labware in the new schema into a placeable, by name :raises KeyError: If the labware name is not found """ defn = new_labware.get_labware_definition(load_name=container_name) return load_new_labware_def(defn)
def _determine_required_labware(self) -> typing.Dict[UUID, LabwareInfo]: """ A function that inserts tiprack information into two dataclasses :py:class:`.LabwareInfo` and :py:class:`.LabwareDefinition` based on the current pipettes attached. """ lw: typing.Dict[UUID, LabwareInfo] = {} _prev_lw_uuid: typing.Optional[UUID] = None for mount, pip_info in self._pip_info_by_mount.items(): load_name: str = self._load_name_for_mount(mount) prev_lw = lw.get(_prev_lw_uuid, None) if _prev_lw_uuid else None if _prev_lw_uuid and prev_lw and prev_lw.loadName == load_name: # pipette uses same tiprack as previous, use existing lw[_prev_lw_uuid].forMounts.append(mount) self._pip_info_by_mount[mount].tiprack_id = _prev_lw_uuid else: lw_def = labware.get_labware_definition(load_name) new_uuid: UUID = uuid4() _prev_lw_uuid = new_uuid slot = self._get_tip_rack_slot_for_mount(mount) lw[new_uuid] = LabwareInfo( alternatives=self._alt_load_names_for_mount(mount), forMounts=[mount], loadName=load_name, slot=slot, namespace=lw_def['namespace'], version=lw_def['version'], id=new_uuid, definition=lw_def) self._pip_info_by_mount[mount].tiprack_id = new_uuid return lw
def test_add_index_file(labware_name, labware_offset_tempdir): deck = Deck() parent = deck.position_for(1) definition = labware.get_labware_definition(labware_name) lw = labware.Labware(definition, parent) labware_hash = helpers.hash_labware_def(definition) labware.save_calibration(lw, Point(0, 0, 0)) lw_uri = helpers.uri_from_definition(definition) str_parent = labware._get_parent_identifier(lw) slot = '1' if str_parent: mod_dict = {str_parent: f'{slot}-{str_parent}'} else: mod_dict = {} full_id = f'{labware_hash}{str_parent}' blob = { "uri": f'{lw_uri}', "slot": full_id, "module": mod_dict } lw_path = labware_offset_tempdir / 'index.json' info = file_operators.read_cal_file(lw_path) assert info['data'][full_id] == blob
def test_tiprack_list(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) tiprack_2 = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert labware.select_tiprack_from_list( [tiprack], 1) == (tiprack, tiprack['A1']) assert labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[1]) == (tiprack, tiprack['B1']) tiprack['C1'].has_tip = False assert labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[2]) == (tiprack, tiprack['D1']) tiprack['H12'].has_tip = False tiprack_2['A1'].has_tip = False assert labware.select_tiprack_from_list( [tiprack, tiprack_2], 1, tiprack.wells()[95]) == ( tiprack_2, tiprack_2['B1']) with pytest.raises(labware.OutOfTipsError): labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[95])
def test_build_edges(): lw_def = get_labware_definition('corning_96_wellplate_360ul_flat') test_lw = Labware(lw_def, Location(Point(0, 0, 0), None)) off = Point(0, 0, 1.0) deck = Deck() old_correct_edges = [ test_lw['A1']._from_center_cartesian(x=1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=-1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=1.0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=-1.0, z=1) + off, ] res = build_edges( test_lw['A1'], 1.0, Mount.RIGHT, deck, version=APIVersion(2, 2)) assert res == old_correct_edges new_correct_edges = [ test_lw['A1']._from_center_cartesian(x=1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=-1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=1.0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=-1.0, z=1) + off, ] res2 = build_edges( test_lw['A1'], 1.0, Mount.RIGHT, deck, version=APIVersion(2, 4)) assert res2 == new_correct_edges
def test_select_next_tip(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) well_list = tiprack.wells() next_one = tiprack.next_tip() assert next_one == well_list[0] next_five = tiprack.next_tip(5) assert next_five == well_list[0] next_eight = tiprack.next_tip(8) assert next_eight == well_list[0] next_nine = tiprack.next_tip(9) assert next_nine is None # A1 tip only has been used tiprack.use_tips(well_list[0]) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[8] # 2nd column has also been used tiprack.use_tips(well_list[8], num_channels=8) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16] # Bottom 4 tips of 1rd column are also used tiprack.use_tips(well_list[4], num_channels=4) next_one = tiprack.next_tip() assert next_one == well_list[1] next_three = tiprack.next_tip(3) assert next_three == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[16] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16] # you can reuse tips infinitely on api level 2.2 tiprack.use_tips(well_list[0]) tiprack.use_tips(well_list[0]) # you can't on api level 2.1 or previous early_tr = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot'), api_level=APIVersion(2, 1)) early_tr.use_tips(well_list[0]) with pytest.raises(AssertionError): early_tr.use_tips(well_list[0])
def test_uris(): details = ('opentrons', 'opentrons_96_tiprack_300ul', '1') uri = 'opentrons/opentrons_96_tiprack_300ul/1' assert labware.uri_from_details(*details) == uri defn = labware.get_labware_definition(details[1], details[0], details[2]) assert labware.uri_from_definition(defn) == uri lw = labware.Labware(defn, Location(Point(0, 0, 0), 'Test Slot')) assert lw.uri == uri
def mock_user_flow(mock_hw, request): has_calibration_block = request.param mount = next(k for k, v in mock_hw._attached_instruments.items() if v) pip_model = mock_hw._attached_instruments[mount].model tip_rack = get_labware_definition(pipette_map[pip_model], 'opentrons', '1') m = TipCalibrationUserFlow(hardware=mock_hw, mount=mount, has_calibration_block=has_calibration_block, tip_rack=tip_rack) yield m
def load_new_labware(container_name, version=None): """ Load a labware in the new schema into a placeable, by name and version :param container_name: The load name of the container :param version: the version to load. :raises KeyError: If the labware name is not found """ defn = new_labware.get_labware_definition(load_name=container_name, version=version) return load_new_labware_def(defn)
def set_up_index_file_temporary_directory(server_temp_directory): delete.clear_calibrations() deck = Deck() labware_list = [ 'nest_96_wellplate_2ml_deep', 'corning_384_wellplate_112ul_flat', 'geb_96_tiprack_1000ul', 'nest_12_reservoir_15ml', 'opentrons_96_tiprack_10ul' ] for idx, name in enumerate(labware_list): parent = deck.position_for(idx + 1) definition = labware.get_labware_definition(name) lw = labware.Labware(definition, parent) labware.save_calibration(lw, Point(0, 0, 0))
def set_up_index_file(labware_offset_tempdir): deck = Deck() labware_list = [ 'nest_96_wellplate_2ml_deep', 'corning_384_wellplate_112ul_flat', 'geb_96_tiprack_1000ul', 'nest_12_reservoir_15ml'] for idx, name in enumerate(labware_list): parent = deck.position_for(idx+1) definition = labware.get_labware_definition(name) lw = labware.Labware(definition, parent) labware.save_calibration(lw, Point(0, 0, 0)) return labware_list
def test_well_parent(): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) parent = Location(Point(7, 8, 9), lw) well_name = 'circular_well_json' has_tip = True well = labware.Well(test_data[well_name], parent, well_name, has_tip) assert well.parent is lw assert well.top().labware is well assert well.top().labware.parent is lw assert well.bottom().labware is well assert well.bottom().labware.parent is lw assert well.center().labware is well assert well.center().labware.parent is lw
def test_get_parent_identifier(): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) # slots have no parent identifier assert labware._get_parent_identifier(lw) == '' # modules do mmg = ModuleGeometry('my magdeck', MagneticModuleModel.MAGNETIC_V1, ModuleType.MAGNETIC, Point(0, 0, 0), 10, 10, Location(Point(1, 2, 3), '3'), APIVersion(2, 4)) lw = labware.Labware(labware_def, mmg.location) assert labware._get_parent_identifier(lw)\ == MagneticModuleModel.MAGNETIC_V1.value
def test_select_next_tip(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) well_list = tiprack.wells() next_one = tiprack.next_tip() assert next_one == well_list[0] next_five = tiprack.next_tip(5) assert next_five == well_list[0] next_eight = tiprack.next_tip(8) assert next_eight == well_list[0] next_nine = tiprack.next_tip(9) assert next_nine is None # A1 tip only has been used tiprack.use_tips(well_list[0]) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[8] # 2nd column has also been used tiprack.use_tips(well_list[8], num_channels=8) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16] # Bottom 4 tips of 1rd column are also used tiprack.use_tips(well_list[4], num_channels=4) next_one = tiprack.next_tip() assert next_one == well_list[1] next_three = tiprack.next_tip(3) assert next_three == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[16] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16]
def test_module_load_labware(module_name): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) model = module_geometry.resolve_module_model(module_name) mod = module_geometry.load_module(model, Location(Point(0, 0, 0), 'test')) old_z = mod.highest_z lw = labware.load_from_definition(labware_def, mod.location) mod.add_labware(lw) assert mod.labware == lw assert mod.highest_z ==\ (mod.location.point.z + labware_def['dimensions']['zDimension'] + mod._over_labware) with pytest.raises(AssertionError): mod.add_labware(lw) mod.reset_labware() assert mod.labware is None assert mod.highest_z == old_z
def test_previous_tip(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) # If all wells are used, we can't get a previous tip assert tiprack.previous_tip() is None # If one well is empty, wherever it is, we can get a slot tiprack.wells()[5].has_tip = False assert tiprack.previous_tip() is tiprack.wells()[5] # But not if we ask for more slots than are available assert tiprack.previous_tip(2) is None tiprack.wells()[7].has_tip = False # And those available wells have to be contiguous assert tiprack.previous_tip(2) is None # But if they are, we're good tiprack.wells()[6].has_tip = False assert tiprack.previous_tip(3) is tiprack.wells()[5]
def test_back_compat(): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) # Note that this test uses the display name of wells to test for equality, # because dimensional parameters could be subject to modification through # calibration, whereas here we are testing for "identity" in a way that is # related to the combination of well name, labware name, and slot name well_a1_name = repr(lw.wells_by_name()['A1']) well_b2_name = repr(lw.wells_by_name()['B2']) well_c3_name = repr(lw.wells_by_name()['C3']) w2 = lw.well(0) assert repr(w2) == well_a1_name w3 = lw.well('A1') assert repr(w3) == well_a1_name w4 = lw.wells('B2') assert repr(w4[0]) == well_b2_name w5 = lw.wells(9, 21, 25, 27) assert len(w5) == 4 assert repr(w5[0]) == well_b2_name w6 = lw.wells('A1', 'B2', 'C3') assert all([ repr(well[0]) == well[1] for well in zip(w6, [well_a1_name, well_b2_name, well_c3_name]) ]) w7 = lw.rows('A') assert len(w7) == 1 assert repr(w7[0][0]) == well_a1_name w8 = lw.rows('A', 'C') assert len(w8) == 2 assert repr(w8[0][0]) == well_a1_name assert repr(w8[1][2]) == well_c3_name w11 = lw.columns('2', '3', '6') assert len(w11) == 3 assert repr(w11[1][2]) == well_c3_name
def test_module_load_labware(): module_names = ['tempdeck', 'magdeck'] labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) for name in module_names: mod = labware.load_module(name, Location(Point(0, 0, 0), 'test')) old_z = mod.highest_z lw = labware.load_from_definition(labware_def, mod.location) mod.add_labware(lw) assert mod.labware == lw assert mod.highest_z ==\ (mod.location.point.z + labware_def['dimensions']['zDimension'] + mod._over_labware) with pytest.raises(AssertionError): mod.add_labware(lw) mod.reset_labware() assert mod.labware is None assert mod.highest_z == old_z
def test_no_labware_loc(labware_offset_tempdir): labware_def = labware.get_labware_definition(labware_name) deck = Deck() lw1 = labware.load(labware_name, deck.position_for(1)) lw2 = labware.load(labware_name, deck.position_for(2)) deck[1] = lw1 deck[2] = lw2 # Various flavors of locations without labware should work no_lw = lw1.wells()[0].top()._replace(labware=None) no_from = plan_moves(no_lw, lw2.wells()[0].bottom(), deck, P300M_GEN2_MAX_HEIGHT, 7.0, 15.0) check_arc_basic(no_from, no_lw, lw2.wells()[0].bottom()) assert no_from[0][0].z == deck.highest_z + 15.0 no_to = plan_moves(lw1.wells()[0].bottom(), no_lw, deck, P300M_GEN2_MAX_HEIGHT, 7.0, 15.0) check_arc_basic(no_to, lw1.wells()[0].bottom(), no_lw) assert no_from[0][0].z == deck.highest_z + 15.0 no_well = lw1.wells()[0].top()._replace(labware=lw1) no_from_well = plan_moves(no_well, lw1.wells()[1].top(), deck, P300M_GEN2_MAX_HEIGHT, 7.0, 15.0) check_arc_basic(no_from_well, no_well, lw1.wells()[1].top()) no_from_well_height = no_from_well[0][0].z lw_height_expected = labware_def['dimensions']['zDimension'] + 7 assert no_from_well_height == lw_height_expected no_to_well = plan_moves(lw1.wells()[1].top(), no_well, deck, P300M_GEN2_MAX_HEIGHT, 7.0, 15.0) check_arc_basic(no_to_well, lw1.wells()[1].top(), no_well) no_to_well_height = no_to_well[0][0].z assert no_to_well_height == lw_height_expected
def _determine_required_labware(self) -> typing.Dict[UUID, LabwareInfo]: """ A function that inserts tiprack information into two dataclasses :py:class:`.LabwareInfo` and :py:class:`.LabwareDefinition` based on the current pipettes attached. """ lw: typing.Dict[UUID, LabwareInfo] = {} _uuid: typing.Optional[UUID] = None for pipette_id in self._relate_mount.keys(): mount = self._get_mount(pipette_id) pip_vol = self.get_pipette(mount)['max_volume'] _lookup = LOOKUP_LABWARE[str(pip_vol)] load_name: str = _lookup.load_name if_labware = None if _uuid: if_labware = lw.get(_uuid) if _uuid and if_labware and if_labware.loadName == load_name: lw[_uuid].forPipettes.append(pipette_id) self._relate_mount[pipette_id]['tiprack_id'] = _uuid else: lw_def = labware.get_labware_definition(load_name) new_uuid: UUID = uuid4() _uuid = new_uuid slot = self._available_slot_options() lw[new_uuid] = LabwareInfo( alternatives=list(_lookup.alternatives), forPipettes=[pipette_id], loadName=load_name, slot=slot, namespace=lw_def['namespace'], version=lw_def['version'], id=new_uuid, definition=lw_def) self._relate_mount[pipette_id]['tiprack_id'] = new_uuid return lw
def test_return_tips(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) # If all wells are used, we get an error if we try to return with pytest.raises(AssertionError): tiprack.return_tips(tiprack.wells()[0]) # If we have space where we specify, everything is OK tiprack.wells()[0].has_tip = False tiprack.return_tips(tiprack.wells()[0]) assert tiprack.wells()[0].has_tip # We have to have enough space tiprack.wells()[0].has_tip = False with pytest.raises(AssertionError): tiprack.return_tips(tiprack.wells()[0], 2) # But we can drop stuff off the end of a column tiprack.wells()[7].has_tip = False tiprack.wells()[8].has_tip = False tiprack.return_tips(tiprack.wells()[7], 2) assert tiprack.wells()[7].has_tip # But we won't wrap around assert not tiprack.wells()[8].has_tip
def test_use_tips(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) well_list = tiprack.wells() # Test only using one tip tiprack.use_tips(well_list[0]) assert not well_list[0].has_tip for well in well_list[1:]: assert well.has_tip # Test using a whole column tiprack.use_tips(well_list[8], num_channels=8) for well in well_list[8:16]: assert not well.has_tip assert well_list[7].has_tip assert well_list[16].has_tip # Test using a partial column from the top tiprack.use_tips(well_list[16], num_channels=4) for well in well_list[16:20]: assert not well.has_tip for well in well_list[20:24]: assert well.has_tip # Test using a partial column where the number of tips that get picked up # is less than the number of channels (e.g.: an 8-channel pipette picking # up 4 tips from the bottom half of a column) tiprack.use_tips(well_list[28], num_channels=4) for well in well_list[24:28]: assert well.has_tip for well in well_list[28:32]: assert not well.has_tip for well in well_list[32:]: assert well.has_tip