def test_shake_during_pick_up(monkeypatch): robot.reset() pip = instruments._create_pipette_from_config( config=pipette_config.load('p1000_single_v2.0'), mount='left', name='p1000_single_v2.0') tiprack = containers_load(robot, 'opentrons_96_tiprack_1000ul', '1') shake_tips_pick_up = mock.Mock( side_effect=pip._shake_off_tips_pick_up) monkeypatch.setattr(pip, '_shake_off_tips_pick_up', shake_tips_pick_up) # Test double shake for after pick up tips pip.pick_up_tip(tiprack[0]) assert shake_tips_pick_up.call_count == 2 actual_calls = [] def mock_jog(pose_tree, axis, distance): actual_calls.append((axis, distance)) monkeypatch.setattr(pip, '_jog', mock_jog) # Test shake in both x and y shake_tips_pick_up() expected_calls = [('x', -0.3), ('x', 0.6), ('x', -0.3), ('y', -0.3), ('y', 0.6), ('y', -0.3), ('z', 20)] assert actual_calls == expected_calls pip.tip_attached = False
def test_get_location(): robot.reset() command_type = 'aspirate' plate = labware.load("96-flat", 1) well = "B2" default_values = {'aspirate-mm-from-bottom': 2} loaded_labware = {"someLabwareId": plate} # test with nonzero and with zero command-specific offset for offset in [5, 0]: command_params = { "labware": "someLabwareId", "well": well, "offsetFromBottomMm": offset } result = execute_v1._get_location(loaded_labware, command_type, command_params, default_values) assert result == plate.well(well).bottom(offset) command_params = {"labware": "someLabwareId", "well": well} # no command-specific offset, use default result = execute_v1._get_location(loaded_labware, command_type, command_params, default_values) assert result == plate.well(well).bottom( default_values['aspirate-mm-from-bottom'])
async def test_incorrect_token(async_client, monkeypatch): """ Test that putting in an incorrect token for a POST request does not work after a session was already created with a different token. """ test_model = 'p300_multi_v1' def dummy_read_model(mount): return test_model monkeypatch.setattr(robot._driver, 'read_pipette_model', dummy_read_model) robot.reset() dummy_token = 'Test Token' def uuid_mock(): return dummy_token monkeypatch.setattr(endpoints, '_get_uuid', uuid_mock) await async_client.post('/calibration/deck/start') resp = await async_client.post('/calibration/deck', json={ 'token': 'FAKE TOKEN', 'command': 'init pipette', 'mount': 'left', 'model': 'p10_single_v1' }) assert resp.status == 403
def test_pipette_version_1_0_and_1_3_extended_travel(): models = [ 'p10_single', 'p10_multi', 'p50_single', 'p50_multi', 'p300_single', 'p300_multi', 'p1000_single' ] for m in models: robot.reset() v1 = m + '_v1' v13 = m + '_v1.3' left = instruments._create_pipette_from_config( config=pipette_config.load(v1), mount='left', name=v1) right = instruments._create_pipette_from_config( config=pipette_config.load(v13), mount='right', name=v13) # the difference between v1 and v1.3 is that the plunger's travel # distance extended, allowing greater ranges for aspirate/dispense # and blow-out. Test that all v1.3 pipette have larger travel thant v1 left_poses = left.plunger_positions left_diff = left_poses['top'] - left_poses['blow_out'] right_poses = right.plunger_positions right_diff = right_poses['top'] - right_poses['blow_out'] assert right_diff > left_diff
async def test_release(async_client, monkeypatch): """ Tests that the GET request to initiate a session manager for factory calibration returns an error if a session is in progress, and can be overridden. """ test_model = 'p300_multi_v1' def dummy_read_model(mount): return test_model monkeypatch.setattr(robot._driver, 'read_pipette_model', dummy_read_model) robot.reset() resp = await async_client.post('/calibration/deck/start') assert resp.status == 201 body = await resp.json() token = body.get('token') resp1 = await async_client.post('/calibration/deck/start') assert resp1.status == 409 # Release resp2 = await async_client.post('/calibration/deck', json={ 'token': token, 'command': 'release' }) assert resp2.status == 200 assert endpoints.session is None resp3 = await async_client.post('/calibration/deck/start') assert resp3.status == 201
async def test_save_calibration_file(dc_session, monkeypatch): robot.reset() expected_pos = endpoints.expected_points() dc_session.points = { k: (v[0], v[1] + 0.3) for k, v in expected_pos.items() } dc_session.z_value = 0.2 persisted_data = [] def dummy_save(config, filename=None, tag=None): nonlocal persisted_data persisted_data.append((config, filename, tag)) monkeypatch.setattr(robot_configs, 'save_deck_calibration', dummy_save) await endpoints.save_transform({}) in_memory = robot.config.gantry_calibration assert len(persisted_data) == 2 assert persisted_data[0][0].gantry_calibration == in_memory assert persisted_data[1][0].gantry_calibration == in_memory assert persisted_data[1][-1] is not None expected = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.3], [0.0, 0.0, 1.0, 0.2], [0.0, 0.0, 0.0, 1.0]] assert np.allclose(in_memory, expected)
def test_container_from_container_load(): robot.reset() plate = containers_load(robot, '96-flat', '1') actual = plate._coordinates expected = Vector(14.34, 11.24, 10.50) assert plate.get_type() == '96-flat' assert actual == expected
def main() -> int: parser = argparse.ArgumentParser(prog='opentrons-analyze', description='Analyze an OT-2 protocol') parser = opentrons.simulate.get_arguments(parser) parser.add_argument( '--mount_left', type=str ) parser.add_argument( '--mount_right', type=str ) args = parser.parse_args() if args.mount_left or args.mount_right: if args.mount_left: EnhancedSimulatingSmoothieDriver.mount(args.mount_left, 'left') if args.mount_right: EnhancedSimulatingSmoothieDriver.mount(args.mount_right, 'right') robot.reset() # pick up the new definitions run_log_and_bundle = opentrons.simulate.simulate(args.protocol, args.protocol.name, log_level=args.log_level) run_log = run_log_and_bundle[0] analysis = analyzeRunLog(run_log) print(opentrons.simulate.format_runlog(run_log)) print("\n") print(analysis.formatted()) return 0
def test_all_pipette_models_can_transfer(): from opentrons.config import pipette_config models = [ 'p10_single', 'p10_multi', 'p50_single', 'p50_multi', 'p300_single', 'p300_multi', 'p1000_single' ] for m in models: robot.reset() v1 = m + '_v1' v13 = m + '_v1.3' left = instruments._create_pipette_from_config( config=pipette_config.load(v1), mount='left', name=v1) right = instruments._create_pipette_from_config( config=pipette_config.load(v13), mount='right', name=v13) left.tip_attached = True right.tip_attached = True left.aspirate().dispense() right.aspirate().dispense()
def test_load_labware(get_labware_fixture): robot.reset() fixture_96_plate = get_labware_fixture('fixture_96_plate') data = { "labwareDefinitions": { "someDefId": fixture_96_plate }, "labware": { "sourcePlateId": { "slot": "10", "definitionId": "someDefId", "displayName": "Source (Buffer)" }, "destPlateId": { "slot": "11", "definitionId": "someDefId", "displayName": "Destination Plate" }, } } loaded_labware = execute_v3.load_labware(data) # objects in loaded_labware should be same objs as labware objs in the deck assert loaded_labware['sourcePlateId'] in robot.deck['10'] assert loaded_labware['destPlateId'] in robot.deck['11']
def test_load_pipettes(): # TODO Ian 2018-11-07 when `model` is dropped, delete its test case test_cases = [ # deprecated case { "pipettes": { "leftPipetteHere": { "mount": "left", "model": "p10_single_v1.3" } } }, # future case { "pipettes": { "leftPipetteHere": { "mount": "left", "name": "p10_single" } } } ] for data in test_cases: robot.reset() loaded_pipettes = execute_v1.load_pipettes(data) robot_instruments = robot.get_instruments() assert len(robot_instruments) == 1 mount, pipette = robot_instruments[0] assert mount == 'left' # loaded pipette in result dict should match that in robot_instruments assert pipette == loaded_pipettes['leftPipetteHere']
def test_dispense_move_to(old_aspiration): # TODO: same as for aspirate robot.reset() tip_rack = containers_load(robot, 'tiprack-200ul', '3') p300 = instruments.P300_Single( mount='left', tip_racks=[tip_rack]) x, y, z = (161.0, 116.7, 0.0) plate = containers_load(robot, '96-flat', '1') well = plate[0] pos = well.from_center(x=0, y=0, z=-1, reference=plate) location = (plate, pos) robot.poses = p300._move(robot.poses, x=x, y=y, z=z) robot.calibrate_container_with_instrument(plate, p300, False) p300.pick_up_tip() p300.aspirate(100, location) p300.dispense(100, location) current_pos = pose_tracker.absolute( robot.poses, p300.instrument_actuator) assert (current_pos == (1.5, 0.0, 0.0)).all() current_pos = pose_tracker.absolute(robot.poses, p300) assert isclose(current_pos, (161, 116.7, 10.5)).all()
def test_use_filter_tips(): # test tips with lower working volume than max volume of pipette used to # ensure that the pipette never over-aspirates with a smaller pipette tip tipracks = [ 'opentrons_96_filtertiprack_10ul', 'opentrons_96_filtertiprack_200ul', 'opentrons_96_filtertiprack_1000ul' ] for t in tipracks: robot.reset() tip_rack = containers_load(robot, t, '3') plate = containers_load(robot, '96-flat', '1') p300 = instruments.P300_Single( mount='left', tip_racks=[tip_rack]) p300.pick_up_tip() p300.aspirate(plate[0]) # working volume should be the lesser of the pipette max volume # and the tip max volume assert p300.current_volume == p300._working_volume assert p300.current_volume == min( tip_rack[0].max_volume(), p300.max_volume) # working volume should revert back to pipette max volume if no tip # is attached p300.return_tip() assert p300._working_volume == p300.max_volume
def test_aspirate_move_to(old_aspiration): # TODO: it seems like this test is checking that the aspirate point is # TODO: *fully* at the bottom of the well, which isn't the expected # TODO: behavior of aspirate when a location is not specified. This should # TODO: be split into two tests--one for this behavior (specifying a place) # TODO: and another one for the default robot.reset() tip_rack = containers_load(robot, 'tiprack-200ul', '3') p300 = instruments.P300_Single( mount='left', tip_racks=[tip_rack]) p300.pick_up_tip() x, y, z = (161.0, 116.7, 0.0) plate = containers_load(robot, '96-flat', '1') well = plate[0] pos = well.from_center(x=0, y=0, z=-1, reference=plate) location = (plate, pos) robot.poses = p300._move(robot.poses, x=x, y=y, z=z) robot.calibrate_container_with_instrument(plate, p300, False) p300.aspirate(100, location) current_pos = pose_tracker.absolute( robot.poses, p300.instrument_actuator) assert (current_pos == (6.889964, 0.0, 0.0)).all() current_pos = pose_tracker.absolute(robot.poses, p300) assert isclose(current_pos, (161, 116.7, 10.5)).all()
def test_delay_calls(monkeypatch): from opentrons import robot from opentrons.legacy_api.instruments import pipette robot.reset() p300 = instruments.P300_Single(mount='right') cmd = [] def mock_pause(): nonlocal cmd cmd.append('pause') def mock_resume(): nonlocal cmd cmd.append('resume') def mock_sleep(seconds): cmd.append("sleep {}".format(seconds)) def mock_is_simulating(): return False monkeypatch.setattr(robot, 'is_simulating', mock_is_simulating) monkeypatch.setattr(robot, 'pause', mock_pause) monkeypatch.setattr(robot, 'resume', mock_resume) monkeypatch.setattr(pipette, '_sleep', mock_sleep) p300.delay(seconds=4, minutes=1) assert 'pause' in cmd assert 'sleep 64.0' in cmd assert 'resume' in cmd
def test_fixed_trash(): robot.reset() p300 = instruments.P300_Single(mount='right') p300.move_to(p300.trash_container) assert isclose(pose_tracker.absolute(robot.poses, p300), (345.0, 351.5, 85.0)).all()
def test_backwards_compatibility(backcompat, monkeypatch): expected_name, old_name, old_constructor = backcompat robot.reset() fake_pip = { 'left': { 'model': None, 'id': None, 'name': None }, 'right': { 'model': expected_name.split('_gen2')[0] + '_v2.0', 'id': 'FakePip', 'name': expected_name } } monkeypatch.setattr(robot, 'model_by_mount', fake_pip) old_config = pipette_config.name_config()[old_name] pipette = old_constructor(mount='right') assert pipette.name.startswith(expected_name) is True assert pipette.mount == 'right' assert pipette.min_volume == old_config['minVolume'] assert pipette.max_volume == old_config['maxVolume']
async def test_get_pipettes(virtual_smoothie_env, loop, test_client, monkeypatch): test_model = 'p300_multi_v1' def dummy_read_model(mount): return test_model monkeypatch.setattr(robot._driver, 'read_pipette_model', dummy_read_model) robot.reset() app = init(loop) cli = await loop.create_task(test_client(app)) model = pipette_config.load(test_model) expected = { 'left': { 'model': model.name, 'tip_length': model.tip_length, 'mount_axis': 'z', 'plunger_axis': 'b' }, 'right': { 'model': model.name, 'tip_length': model.tip_length, 'mount_axis': 'a', 'plunger_axis': 'c' } } resp = await cli.get('/pipettes?refresh=true') text = await resp.text() assert resp.status == 200 assert json.loads(text) == expected
def singletons(virtual_smoothie_env): rb.reset() yield {'robot': rb, 'instruments': ins, 'labware': cns, 'modules': mods} rb.disconnect() rb.reset()
def test_load_correct_engage_height(): robot.reset() md = modules.load('magdeck', '1') test_container = labware.load('biorad_96_wellplate_200ul_pcr', '1', share=True) assert test_container.magdeck_engage_height() == 18 assert md.labware.get_children_list()[1].magdeck_engage_height() == \ test_container.magdeck_engage_height()
def test_legacy_execute_json_v3(get_json_protocol_fixture): robot.reset() protocol_data = get_json_protocol_fixture('3', 'testAllAtomicSingleV3') protocol = JsonProtocol(text=json.dumps(protocol_data), filename=None, contents=protocol_data, schema_version=3) execute_protocol(protocol)
def test_container_parse(): robot.reset() plate = containers_load(robot, '96-flat', '1') if ff.split_labware_definitions(): expected = {'x': 0, 'y': 0, 'z': 0} else: expected = {'x': 14.34, 'y': 11.24, 'z': 10.50} assert database._parse_container_obj(plate) == expected
def containers(): from opentrons import robot from opentrons import containers robot.reset() return { '1': containers.load('96-flat', '1'), '11': containers.load('96-flat', '11') }
def test_shake_during_drop(monkeypatch): robot.reset() pip = instruments._create_pipette_from_config( config=pipette_config.load('p1000_single_v2.0'), mount='left', name='p1000_single_v2.0') tiprack = containers_load(robot, 'opentrons_96_tiprack_1000ul', '1') shake_tips_drop = mock.Mock( side_effect=pip._shake_off_tips_drop) monkeypatch.setattr(pip, '_shake_off_tips_drop', shake_tips_drop) # Test single shake for after pick up tips pip.tip_attached = True pip.drop_tip(tiprack.wells(0)) assert shake_tips_drop.call_count == 1 actual_calls = [] def jog_side_effect(pose_tree, axis, distance): actual_calls.append((axis, distance)) jog = mock.Mock(side_effect=jog_side_effect) monkeypatch.setattr(pip, '_jog', jog) # Test shake only in x, with no location passed, shake distance is 2.25 shake_tips_drop() expected_calls = [('x', -2.25), ('x', 4.5), ('x', -2.25), ('z', 20)] assert actual_calls == expected_calls # Test drop tip shake at a well with diameter above upper limit (2.25 mm) tiprack.wells(0).properties['width'] = 2.3*4 actual_calls.clear() shake_tips_drop(tiprack.wells(0)) expected_calls = [('x', -2.25), ('x', 4.5), ('x', -2.25), ('z', 20)] assert actual_calls == expected_calls # Test drop tip shake at a well with diameter between upper limit # and lower limit (1.00 - 2.25 mm) tiprack.wells(0).properties['width'] = 2*4 actual_calls.clear() shake_tips_drop(tiprack.wells(0)) expected_calls = [('x', -2), ('x', 4), ('x', -2), ('z', 20)] assert actual_calls == expected_calls # Test drop tip shake at a well with diameter below lower limit (1.00 mm) tiprack.wells(0).properties['width'] = 0.9*4 actual_calls.clear() shake_tips_drop(tiprack.wells(0)) expected_calls = [('x', -1), ('x', 2), ('x', -1), ('z', 20)] assert actual_calls == expected_calls pip.tip_attached = False
def test_move_head(virtual_smoothie_env): robot.reset() robot.move_head(x=100, y=0) assert isclose( pose_tracker.absolute( robot.poses, robot.gantry)[:2], (100, 0, 0)[:2] ).all()
def test_pipette_max_deck_height(): robot.reset() tallest_point = robot._driver.homed_position['Z'] p = instruments.P300_Single(mount='left') assert p._max_deck_height() == tallest_point for tip_length in [10, 25, 55, 100]: p._add_tip(length=tip_length) assert p._max_deck_height() == tallest_point - tip_length p._remove_tip(length=tip_length)
def test_pos_tracker_persistance(virtual_smoothie_env): robot.reset() p300 = instruments.P300_Single(mount='left') plate = containers_load(robot, 'trough-12row', '5') assert robot.max_placeable_height_on_deck(plate) == 40.0 robot.poses = p300._move(robot.poses, x=10, y=10, z=10) robot.calibrate_container_with_instrument(plate, p300, save=False) assert robot.max_placeable_height_on_deck(plate) == 10.0
def test_robot_move_to(virtual_smoothie_env): robot.reset() robot.home() p300 = instruments.P300_Single(mount='right') robot.move_to((robot._deck, (100, 0, 0)), p300) assert isclose( pose_tracker.absolute( robot.poses, p300), (100, 0, 0) ).all()
def probe(tip_length: float) -> str: robot.reset() pipette = instruments.Pipette(mount='right', channels=1) probe_center = tuple(probe_instrument( pipette, robot, tip_length=tip_length)) log.debug("Setting probe center to {}".format(probe_center)) robot.config = robot.config._replace( probe_center=probe_center ) return 'Tip probe'
def _test_offset(x, y, z): robot.reset() robot.config = robot.config._replace(mount_offset=(x, y, z)) left = instruments.P300_Single(mount='left') right = instruments.P300_Single(mount='right') robot.home() left_pos = pose_tracker.absolute(robot.poses, left) right_pos = pose_tracker.absolute(robot.poses, right) assert left_pos[0] == right_pos[0] + x assert left_pos[1] == right_pos[1] + y assert left_pos[2] == right_pos[2] + z