示例#1
0
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
示例#2
0
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'])
示例#3
0
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
示例#4
0
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
示例#5
0
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
示例#6
0
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)
示例#7
0
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
示例#9
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()
示例#10
0
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']
示例#11
0
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']
示例#12
0
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()
示例#13
0
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
示例#14
0
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()
示例#15
0
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
示例#16
0
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()
示例#17
0
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']
示例#18
0
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
示例#19
0
def singletons(virtual_smoothie_env):
    rb.reset()
    yield {'robot': rb,
           'instruments': ins,
           'labware': cns,
           'modules': mods}
    rb.disconnect()
    rb.reset()
示例#20
0
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()
示例#21
0
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)
示例#22
0
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
示例#23
0
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')
    }
示例#24
0
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
示例#25
0
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()
示例#26
0
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)
示例#27
0
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
示例#28
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()
示例#29
0
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'
示例#30
0
 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