예제 #1
0
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
예제 #2
0
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
예제 #3
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
예제 #4
0
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)
예제 #5
0
    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
예제 #6
0
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
예제 #7
0
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])
예제 #8
0
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
예제 #9
0
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])
예제 #10
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
예제 #11
0
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
예제 #12
0
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)
예제 #13
0
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))
예제 #14
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
예제 #15
0
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
예제 #16
0
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
예제 #17
0
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]
예제 #18
0
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
예제 #19
0
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]
예제 #20
0
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
예제 #21
0
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
예제 #22
0
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
예제 #23
0
    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
예제 #24
0
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
예제 #25
0
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