def test_touch_tip_default_args(loop, monkeypatch): ctx = papi.ProtocolContext(loop) ctx.home() lw = ctx.load_labware( 'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 1) tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 3) instr = ctx.load_instrument('p300_single', Mount.RIGHT, tip_racks=[tiprack]) instr.pick_up_tip() total_hw_moves = [] async def fake_hw_move(mount, abs_position, speed=None, critical_point=None, max_speeds=None): nonlocal total_hw_moves total_hw_moves.append((abs_position, speed)) instr.aspirate(10, lw.wells()[0]) monkeypatch.setattr(ctx._hw_manager.hardware._api, 'move_to', fake_hw_move) instr.touch_tip() z_offset = Point(0, 0, 1) # default z offset of 1mm speed = 60 # default speed edges = [ lw.wells()[0]._from_center_cartesian(1, 0, 1) - z_offset, lw.wells()[0]._from_center_cartesian(-1, 0, 1) - z_offset, lw.wells()[0]._from_center_cartesian(0, 1, 1) - z_offset, lw.wells()[0]._from_center_cartesian(0, -1, 1) - z_offset ] for i in range(1, 5): assert total_hw_moves[i] == (edges[i - 1], speed)
def test_blow_out(loop, monkeypatch): ctx = papi.ProtocolContext(loop) ctx.home() lw = ctx.load_labware( 'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap', 1) tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 3) instr = ctx.load_instrument('p300_single', Mount.RIGHT, tip_racks=[tiprack]) move_location = None instr.pick_up_tip() instr.aspirate(10, lw.wells()[0]) def fake_move(loc): nonlocal move_location move_location = loc monkeypatch.setattr(instr, 'move_to', fake_move) instr.blow_out() # pipette should not move, if no location is passed assert move_location is None instr.aspirate(10) instr.blow_out(lw.wells()[0]) # pipette should blow out at the top of the well as default assert move_location == lw.wells()[0].top() instr.aspirate(10) instr.blow_out(lw.wells()[0].bottom()) # pipette should blow out at the location defined assert move_location == lw.wells()[0].bottom()
def test_location_cache(loop, monkeypatch, get_labware_def): hardware = API.build_hardware_simulator(loop=loop) ctx = papi.ProtocolContext(loop) ctx.connect(hardware) right = ctx.load_instrument('p10_single', Mount.RIGHT) lw = ctx.load_labware('corning_96_wellplate_360ul_flat', 1) ctx.home() test_args = None def fake_plan_move(from_loc, to_loc, deck, well_z_margin=None, lw_z_margin=None, force_direct=False, minimum_z_height=None): nonlocal test_args test_args = (from_loc, to_loc, deck, well_z_margin, lw_z_margin) return [(Point(0, 1, 10), None), (Point(1, 2, 10), None), (Point(1, 2, 3), None)] monkeypatch.setattr(papi.geometry, 'plan_moves', fake_plan_move) # When we move without a cache, the from location should be the gantry # position right.move_to(lw.wells()[0].top()) # The home position from hardware_control/simulator.py, taking into account # that the right pipette is a p10 single which is a different height than # the reference p300 single assert test_args[0].point == Point(418, 353, 205) assert test_args[0].labware is None # Once we have a location cache, that should be our from_loc right.move_to(lw.wells()[1].top()) assert test_args[0].labware == lw.wells()[0]
def test_return_tip(loop, get_labware_def): ctx = papi.ProtocolContext(loop) ctx.home() tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 1) mount = Mount.LEFT instr = ctx.load_instrument('p300_single', mount, tip_racks=[tiprack]) with pytest.raises(TypeError): instr.return_tip() pipette: Pipette\ = ctx._hw_manager.hardware._attached_instruments[mount] target_location = tiprack['A1'].top() instr.pick_up_tip(target_location) assert not tiprack.wells()[0].has_tip assert pipette.has_tip instr.return_tip() assert not pipette.has_tip assert not tiprack.wells()[0].has_tip instr.pick_up_tip() assert pipette.has_tip assert not tiprack.wells()[1].has_tip
def test_return_tip_old_version(loop, get_labware_def): # API version 2.2, a returned tip would be picked up by the # next pick up tip call ctx = papi.ProtocolContext(loop, api_version=APIVersion(2, 1)) ctx.home() tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 1) mount = Mount.LEFT instr = ctx.load_instrument('p300_single', mount, tip_racks=[tiprack]) with pytest.raises(TypeError): instr.return_tip() pipette: Pipette\ = ctx._hw_manager.hardware._attached_instruments[mount] target_location = tiprack['A1'].top() instr.pick_up_tip(target_location) assert not tiprack.wells()[0].has_tip assert pipette.has_tip instr.return_tip() assert not pipette.has_tip assert tiprack.wells()[0].has_tip instr.pick_up_tip() assert pipette.has_tip assert not tiprack.wells()[0].has_tip
def test_extra_labware(loop, get_labware_fixture): fixture_96_plate = get_labware_fixture('fixture_96_plate') bundled_labware = {'fixture/fixture_96_plate/1': fixture_96_plate} ctx = papi.ProtocolContext(loop, extra_labware=bundled_labware) ls1 = ctx.load_labware('fixture_96_plate', 3, namespace='fixture') assert ctx.loaded_labwares[3] == ls1 assert ctx.loaded_labwares[3]._definition == fixture_96_plate
def test_load_module(loop): ctx = papi.ProtocolContext(loop) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'tempdeck') ] ctx.home() mod = ctx.load_module('tempdeck', 1) assert isinstance(mod, papi.TemperatureModuleContext)
def test_build_edges_right_pipette(loop): ctx = papi.ProtocolContext(loop) test_lw = ctx.load_labware('corning_96_wellplate_360ul_flat', '2') test_lw2 = ctx.load_labware('corning_96_wellplate_360ul_flat', '6') mod = ctx.load_module('magnetic module', '1') mod.load_labware('corning_96_wellplate_360ul_flat') off = Point(0, 0, 1.0) right_pip_edges = [ 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, ] # Test that module in slot 1 results in modified edge list res = build_edges(test_lw['A1'], 1.0, APIVersion(2, 4), Mount.RIGHT, ctx._deck_layout) assert res == right_pip_edges right_pip_edges = [ test_lw2['A12']._from_center_cartesian(x=1.0, y=0, z=1) + off, test_lw2['A12']._from_center_cartesian(x=-1.0, y=0, z=1) + off, test_lw2['A12']._from_center_cartesian(x=0, y=0, z=1) + off, test_lw2['A12']._from_center_cartesian(x=0, y=1.0, z=1) + off, test_lw2['A12']._from_center_cartesian(x=0, y=-1.0, z=1) + off, ] # Test that labware in slot 6 results in unmodified edge list res2 = build_edges(test_lw2['A12'], 1.0, APIVersion(2, 4), Mount.RIGHT, ctx._deck_layout) assert res2 == right_pip_edges
def test_bundled_labware_missing(loop, get_labware_fixture): bundled_labware = {} with pytest.raises( RuntimeError, match='No labware found in bundle with load name opentrons_1_trash_' ): papi.ProtocolContext(loop, bundled_labware=bundled_labware)
def test_incorrect_module_error(loop): ctx = papi.ProtocolContext(loop) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'tempdeck') ] ctx.home() with pytest.raises(ValueError): assert ctx.load_module('the cool module', 1)
def test_load_simulating_module(loop): # Check that a known module will not throw an error if # in simulation mode ctx = papi.ProtocolContext(loop) ctx.home() mod = ctx.load_module('tempdeck', 1) assert isinstance(mod, papi.TemperatureModuleContext)
def test_invalid_slot_module_error(loop): ctx = papi.ProtocolContext(loop) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'tempdeck') ] ctx.home() with pytest.raises(AssertionError): assert ctx.load_module('thermocycler', 1)
def test_magdeck_labware_props(loop): ctx = papi.ProtocolContext(loop) # TODO Ian 2019-05-29 load fixtures, not real defs labware_name = 'biorad_96_wellplate_200ul_pcr' labware_def = json.loads( pkgutil.get_data( 'opentrons', f'shared_data/labware/definitions/2/{labware_name}/1.json')) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'magdeck')] mod = ctx.load_module('magdeck', 1) assert mod.labware is None mod.load_labware(labware_name) mod.engage() lw_offset = labware_def['parameters']['magneticModuleEngageHeight'] assert mod._module._driver.plate_height == lw_offset mod.disengage() mod.engage(offset=2) assert mod._module._driver.plate_height == lw_offset + 2 mod.disengage() mod.engage(height=3) assert mod._module._driver.plate_height == 3 mod._geometry.reset_labware() labware_name = 'corning_96_wellplate_360ul_flat' mod.load_labware(labware_name) with pytest.raises(ValueError): mod.engage() with pytest.raises(ValueError): mod.engage(offset=1) mod.engage(height=2) assert mod._module._driver.plate_height == 2
def test_load_module_default_slot(loop): ctx = papi.ProtocolContext(loop) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'tempdeck') ] ctx.home() mod = ctx.load_module('thermocycler') assert isinstance(mod, papi.ThermocyclerContext)
def test_thermocycler_lid(loop): ctx = papi.ProtocolContext(loop) ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'thermocycler')] mod = ctx.load_module('thermocycler') assert ctx.deck[7] == mod._geometry assert mod.lid_position == 'open' # Open should work if the lid is open (no status change) mod.open_lid() assert mod.lid_position == 'open' assert 'opening thermocycler lid' in ','.join( [cmd.lower() for cmd in ctx.commands()]) # Close should work if the lid is open mod.close_lid() assert mod.lid_position == 'closed' assert 'closing thermocycler lid' in ','.join( [cmd.lower() for cmd in ctx.commands()]) # Close should work if the lid is closed (no status change) mod.close_lid() assert mod.lid_position == 'closed' assert mod._geometry.lid_status == 'closed' assert mod._geometry.highest_z == (98.0) # ignore 37.7mm lid for now # Open should work if the lid is closed mod.open_lid() assert mod.lid_position == 'open' assert mod._geometry.lid_status == 'open' assert mod._geometry.highest_z == 98.0
def test_starting_tip_and_reset_tipracks(loop, get_labware_def, monkeypatch): ctx = papi.ProtocolContext(loop) ctx.home() tr = ctx.load_labware('opentrons_96_tiprack_300ul', 1) tr_2 = ctx.load_labware('opentrons_96_tiprack_300ul', 2) pipL = ctx.load_instrument('p300_single', Mount.LEFT, tip_racks=[tr, tr_2]) pipR = ctx.load_instrument('p300_single', Mount.RIGHT, tip_racks=[tr, tr_2]) pipL.starting_tip = tr.wells()[2] pipL.pick_up_tip() assert pipL._last_tip_picked_up_from is tr.wells()[2] pipL.drop_tip() pipR.starting_tip = tr.wells()[2] pipR.pick_up_tip() assert pipR._last_tip_picked_up_from is tr.wells()[3] pipR.drop_tip() tr.wells()[95].has_tip = False pipL.starting_tip = tr.wells()[95] pipL.pick_up_tip() assert pipL._last_tip_picked_up_from is tr_2.wells()[0] pipL.reset_tipracks() assert tr.wells()[2].has_tip assert tr.wells()[3].has_tip
def test_load_instrument(loop): ctx = papi.ProtocolContext(loop=loop) for model in config_models: loaded = ctx.load_instrument(model, Mount.LEFT, replace=True) assert loaded.model == model instr_name = name_for_model(model) loaded = ctx.load_instrument(instr_name, Mount.RIGHT, replace=True) assert loaded.name == instr_name
def test_tip_length_for(loop, monkeypatch): ctx = papi.ProtocolContext(loop) instr = ctx.load_instrument('p20_single_gen2', 'left') tiprack = ctx.load_labware('geb_96_tiprack_10ul', '1') assert instr._tip_length_for(tiprack)\ == (tiprack._definition['parameters']['tipLength'] - instr.hw_pipette['tip_overlap'] ['opentrons/geb_96_tiprack_10ul/1'])
def test_module_load_labware_with_label(loop): ctx = papi.ProtocolContext(loop) labware_name = 'corning_96_wellplate_360ul_flat' ctx._hw_manager.hardware._backend._attached_modules = [('mod0', 'tempdeck') ] mod = ctx.load_module('Temperature Module', 1) lw = mod.load_labware(labware_name, label='my cool labware') assert lw.name == 'my cool labware'
def test_loaded_modules(loop, monkeypatch): ctx = papi.ProtocolContext(loop) assert ctx.loaded_modules == {} mod1 = ctx.load_module('tempdeck', 4) mod1.load_labware('biorad_96_wellplate_200ul_pcr') mod2 = ctx.load_module('thermocycler') assert ctx.loaded_modules[4] == mod1 assert ctx.loaded_modules[7] == mod2
def test_load_instrument(loop): ctx = papi.ProtocolContext(loop=loop) for config in config_models: loaded = ctx.load_instrument(config, Mount.LEFT, replace=True) assert loaded.model == config prefix = config.split('_v')[0] loaded = ctx.load_instrument(prefix, Mount.RIGHT, replace=True) assert loaded.name.startswith(prefix)
def test_magdeck_gen2_labware_props(loop): ctx = papi.ProtocolContext(loop) mod = ctx.load_module('magnetic module gen2', 1) mod.engage(height=25) assert mod._module.current_height == 25 with pytest.raises(ValueError): mod.engage(height=25.1) # max engage height for gen2 is 25 mm mod.engage(height=0) assert mod._module.current_height == 0
def test_load_instrument(loop, name): ctx = papi.ProtocolContext(loop=loop) assert ctx.loaded_instruments == {} loaded = ctx.load_instrument(name, Mount.LEFT, replace=True) assert ctx.loaded_instruments[Mount.LEFT.name.lower()] == loaded assert loaded.name == name loaded = ctx.load_instrument(name, Mount.RIGHT, replace=True) assert ctx.loaded_instruments[Mount.RIGHT.name.lower()] == loaded assert loaded.name == name
def test_load_simulating_module(loop, loadname, klass, model): # Check that a known module will not throw an error if # in simulation mode ctx = papi.ProtocolContext(loop) ctx.home() mod = ctx.load_module(loadname, 7) assert isinstance(mod, klass) assert mod.geometry.model.value == model assert mod._module.model() == model
def run(protocol: protocol_api.ProtocolContext(api_version=api_version)): # define deck positions and labware # tips tiprack_300 = protocol.load_labware('opentrons_96_tiprack_300ul', 6) tipracks_10f = [ protocol.load_labware('opentrons_96_filtertiprack_10ul', x) for x in [1, 4, 7, 10] ] # plates reagents = protocol.load_labware('usascientific_12_reservoir_22ml', 3, 'reagents') assay = protocol.load_labware('corning_384_wellplate_112ul_flat', 9, 'assay') samples = [ protocol.load_labware('biorad_96_wellplate_200ul_pcr', x, 'samples') for x in [2, 5, 8, 11] ] # initialize pipettes pipette_left = protocol.load_instrument('p300_multi', 'left', tip_racks=[tiprack_300]) pipette_right = protocol.load_instrument('p10_multi', 'right', tip_racks=tipracks_10f) # distribute 38 µL of quantification reagent into each well of the assay # plate. Use the same tip for the entirety of these transfers, then # replace it in the rack. add_buffer(pipette_left, [reagents[x] for x in ['A1', 'A2']], assay, cols, 38, 13000 / 8, tip=None, tip_vol=300, remaining=None, drop_tip=False) # add 2 µL of each sample to each of the wells. Mix after dispensing. # Dispose of these tips. for i, plate in enumerate(samples): start = i + 1 assay_wells = get_96_from_384_wells(method='interleaved', start=start) pipette_right.transfer(2, plate.wells(), [assay[x] for x in assay_wells], mix_after=(1, 10), touch_tip=True, trash=True, new_tip='always')
def get_protocol_api( bundled_labware: Dict[str, Dict[str, Any]] = None, bundled_data: Dict[str, bytes] = None) -> protocol_api.ProtocolContext: """ Build and return a :py:class:`ProtocolContext` connected to the robot. This can be used to run protocols from interactive Python sessions such as Jupyter or an interpreter on the command line: .. code-block:: python >>> from opentrons.execute import get_protocol_api >>> protocol = get_protocol_api() >>> instr = protocol.load_instrument('p300_single', 'right') >>> instr.home() When this function is called, modules and instruments will be recached. :param bundled_labware: If specified, a mapping from labware names to labware definitions for labware to consider in the protocol. Note that if you specify this, _only_ labware in this argument will be allowed in the protocol. This is preparation for a beta feature and is best not used. :param bundled_data: If specified, a mapping from filenames to contents for data to be available in the protocol from :py:attr:`.ProtocolContext.bundled_data`. :returns opentrons.protocol_api.ProtocolContext: The protocol context. """ if not _HWCONTROL: # Build a hardware controller in a worker thread, which is necessary # because ipython runs its notebook in asyncio but the notebook # is at script/repl scope not function scope and is synchronous so # you can't control the loop from inside. If we update to # IPython 7 we can avoid this, but for now we can't def _build_hwcontroller(): global _HWCONTROL try: loop = asyncio.get_event_loop() except RuntimeError: loop = asyncio.new_event_loop() _HWCONTROL = loop.run_until_complete( API.build_hardware_controller()) thread = threading.Thread(target=_build_hwcontroller, name='Hardware-controller-builder') thread.start() thread.join() context = protocol_api.ProtocolContext(hardware=_HWCONTROL, bundled_labware=bundled_labware, bundled_data=bundled_data) context._hw_manager.hardware.cache_instruments() context._hw_manager.hardware.discover_modules() return context
def test_bundled_labware_missing(loop, get_labware_fixture): bundled_labware = {} with pytest.raises( RuntimeError, match='No labware found in bundle with load name fixture_96_plate' ): ctx = papi.ProtocolContext(loop, bundled_labware=bundled_labware) ctx.load_labware('fixture_96_plate', 3, namespace='fixture') fixture_96_plate = get_labware_fixture('fixture_96_plate') bundled_labware = {'fixture/fixture_96_plate/1': fixture_96_plate} with pytest.raises( RuntimeError, match='No labware found in bundle with load name fixture_96_plate' ): ctx = papi.ProtocolContext(loop, bundled_labware={}, extra_labware=bundled_labware) ctx.load_labware('fixture_96_plate', 3, namespace='fixture')
def _instr_labware(loop): ctx = papi.ProtocolContext(loop) lw1 = ctx.load_labware('biorad_96_wellplate_200ul_pcr', 1) lw2 = ctx.load_labware('corning_96_wellplate_360ul_flat', 2) tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 3) instr = ctx.load_instrument('p300_single', Mount.RIGHT, tip_racks=[tiprack]) return {'ctx': ctx, 'instr': instr, 'lw1': lw1, 'lw2': lw2, 'tiprack': tiprack}
def set_up_paired_instrument(loop): ctx = papi.ProtocolContext(loop) ctx.home() tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 1) tiprack2 = ctx.load_labware('opentrons_96_tiprack_300ul', 2) tiprack3 = ctx.load_labware('opentrons_96_tiprack_300ul', 3) right = ctx.load_instrument( 'p300_multi', Mount.RIGHT, tip_racks=[tiprack, tiprack2]) left = ctx.load_instrument( 'p300_multi', Mount.LEFT, tip_racks=[tiprack2, tiprack3]) return right.pair_with(left), [tiprack, tiprack2, tiprack3]
def test_multichannel_transfer_old_version(loop): # for API version below 2.2, multichannel pipette can only # reach row A of 384-well plates ctx = papi.ProtocolContext(loop, api_version=APIVersion(2, 1)) lw1 = ctx.load_labware('biorad_96_wellplate_200ul_pcr', 1) lw2 = ctx.load_labware('corning_384_wellplate_112ul_flat', 2) tiprack = ctx.load_labware('opentrons_96_tiprack_300ul', 3) instr_multi = ctx.load_instrument('p300_multi', Mount.LEFT, tip_racks=[tiprack]) xfer_plan = tx.TransferPlan( 100, lw1.rows()[0][0], [lw2.rows()[0][1], lw2.rows()[1][1]], instr_multi, max_volume=instr_multi.hw_pipette['working_volume'], api_version=ctx.api_version) xfer_plan_list = [] for step in xfer_plan: xfer_plan_list.append(step) exp1 = [{ 'method': 'pick_up_tip', 'args': [], 'kwargs': {} }, { 'method': 'aspirate', 'args': [100, lw1.wells_by_name()['A1'], 1.0], 'kwargs': {} }, { 'method': 'dispense', 'args': [100, lw2.wells_by_index()['A2'], 1.0], 'kwargs': {} }, { 'method': 'drop_tip', 'args': [], 'kwargs': {} }] assert xfer_plan_list == exp1 # target without row limit with pytest.raises(IndexError): xfer_plan = tx.TransferPlan( 100, lw1.rows()[0][1], lw2.rows()[1][1], instr_multi, max_volume=instr_multi.hw_pipette['working_volume'], api_version=ctx.api_version) xfer_plan_list = [] for step in xfer_plan: xfer_plan_list.append(step)