Skip to content

Commit

Permalink
multiple test file fixes. <400 left
Browse files Browse the repository at this point in the history
  • Loading branch information
aaron-kulkarni committed Jul 31, 2024
1 parent f4ab776 commit ecc6433
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 48 deletions.
5 changes: 3 additions & 2 deletions api/src/opentrons/hardware_control/backends/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,21 @@ class Controller:
"""

@classmethod
async def build(cls, config: RobotConfig) -> Controller:
async def build(cls, config: Optional[RobotConfig]) -> Controller:
"""Build a Controller instance.
Use this factory method rather than the initializer to handle proper
GPIO initialization.
:param config: A loaded robot config.
"""

gpio = build_gpio_chardev("gpiochip0")
gpio.config_by_board_rev()
await gpio.setup()
return cls(config, gpio)

def __init__(self, config: RobotConfig, gpio: GPIODriverLike):
def __init__(self, config: Optional[RobotConfig], gpio: GPIODriverLike):
"""Build a Controller instance.
Always prefer using :py:meth:`.build` to create an instance of this class. For
Expand Down
8 changes: 3 additions & 5 deletions api/src/opentrons/protocols/advanced_control/mix.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import typing
from typing import Any, Dict, Tuple

from opentrons.protocols.advanced_control.transfers import MixStrategy, Mix


def mix_from_kwargs(
top_kwargs: typing.Dict[str, typing.Any]
) -> typing.Tuple[MixStrategy, Mix]:
def mix_from_kwargs(top_kwargs: Dict[str, Any]) -> Tuple[MixStrategy, Mix]:
"""A utility function to determine mix strategy from key word arguments
to InstrumentContext.mix"""

def _mix_requested(kwargs, opt):
def _mix_requested(kwargs: Dict[str, Any], opt: str) -> bool:
"""
Helper for determining mix options from :py:meth:`transfer` kwargs
Mixes can be ignored in kwargs by either
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Iterator

from typing import AsyncGenerator, Iterator
import pytest

from opentrons.config.types import RobotConfig
from opentrons import _find_smoothie_file
from opentrons.config.robot_configs import build_config
from opentrons.hardware_control import Controller
Expand All @@ -12,31 +13,36 @@
async def subject(
emulation_app: Iterator[None],
emulator_settings: Settings,
) -> Controller:
) -> AsyncGenerator[Controller, None]:
conf = build_config({})
port = f"socket://127.0.0.1:{emulator_settings.smoothie.port}"
assert isinstance(conf, RobotConfig)
hc = await Controller.build(config=conf)
await hc.connect(port=port)
yield hc
await hc._smoothie_driver.disconnect()


async def test_get_fw_version(subject: Controller):
async def test_get_fw_version(subject: Controller) -> None:
"""It should be set."""
_, fw_version = _find_smoothie_file()
assert subject._cached_fw_version == fw_version


async def test_get_attached_instruments(subject: Controller):
async def test_get_attached_instruments(subject: Controller) -> None:
"""It should get the attached instruments."""
instruments = await subject.get_attached_instruments({})
assert instruments[Mount.RIGHT]["id"] == "P20SV202020070101"
assert instruments[Mount.RIGHT]["config"].display_name == "P20 Single-Channel GEN2"
right_config = instruments[Mount.RIGHT]["config"]
assert right_config is not None
assert right_config.display_name == "P20 Single-Channel GEN2"
assert instruments[Mount.LEFT]["id"] == "P3HMV202020041605"
assert instruments[Mount.LEFT]["config"].display_name == "P20 8-Channel GEN2"
left_config = instruments[Mount.LEFT]["config"]
assert left_config is not None
assert left_config.display_name == "P20 8-Channel GEN2"


async def test_move(subject: Controller):
async def test_move(subject: Controller) -> None:
"""It should move."""
new_position = {"X": 1.0, "Z": 2.0, "Y": 3.0, "A": 4.0, "B": 5.0, "C": 6.0}

Expand Down
16 changes: 10 additions & 6 deletions api/tests/opentrons/hardware_control/test_gpio.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from unittest.mock import MagicMock
import pytest
import pdb

from opentrons import hardware_control as hc
from opentrons.drivers import rpi_drivers
from opentrons.drivers.rpi_drivers.gpio_simulator import SimulatingGPIOCharDev
from opentrons.hardware_control.types import BoardRevision


async def test_gpio_setup(monkeypatch):
async def test_gpio_setup() -> None:
# Test without DTOVERLAY path
# Board revision should be defaulted to 2.1
pdb.set_trace()
backend = await hc.Controller.build(config=None)
assert str(backend.board_revision) == "2.1"

Expand All @@ -21,17 +25,17 @@ async def test_gpio_setup(monkeypatch):
(hc.types.BoardRevision.C, 0.5),
],
)
async def test_current_setting(monkeypatch, revision, a_current):
async def test_current_setting(
monkeypatch: pytest.MonkeyPatch, revision: BoardRevision, a_current: float
) -> None:
mock_gpio = MagicMock(spec=SimulatingGPIOCharDev)

async def fake_side_effect():
async def fake_side_effect() -> None:
pass

mock_gpio.setup.side_effect = fake_side_effect
mock_gpio.board_rev = revision
mock_build = MagicMock(
spec=hc.backends.controller.build_gpio_chardev, return_value=mock_gpio
)
mock_build = MagicMock(spec=rpi_drivers, return_value=mock_gpio)
monkeypatch.setattr(hc.backends.controller, "build_gpio_chardev", mock_build)
backend = await hc.Controller.build(config=None)
assert backend.board_revision == revision
Expand Down
4 changes: 2 additions & 2 deletions api/tests/opentrons/hardware_control/test_gripper.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ def test_reload_instrument_cal_ot3_conf_changed(

@pytest.mark.ot3_only
def test_jaw_calibration_error_checking() -> None:
subject = gripper.Gripper(fake_gripper_conf, fake_offset, "fakeid123")
subject = gripper.Gripper(fake_gripper_conf, fake_offset, "fakeid123") # type: ignore[arg-type]
with pytest.raises(MotionFailedError):
subject.update_jaw_open_position_from_closed_position(0)


@pytest.mark.ot3_only
def test_jaw_calibration() -> None:
subject = gripper.Gripper(fake_gripper_conf, fake_offset, "fakeid123")
subject = gripper.Gripper(fake_gripper_conf, fake_offset, "fakeid123") # type: ignore[arg-type]
subject.update_jaw_open_position_from_closed_position(
(
fake_gripper_conf.geometry.jaw_width["max"]
Expand Down
25 changes: 16 additions & 9 deletions api/tests/opentrons/hardware_control/test_pipette_handler.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"""Tests for the HardwareApi class."""
from _pytest.fixtures import FixtureRequest
import pytest

from decoy import Decoy
from typing import Optional, Tuple, Dict, List

from opentrons import types
from opentrons.hardware_control.types import OT3Mount, Axis
from opentrons.hardware_control.instruments.ot2.pipette import Pipette
from opentrons_shared_data.pipette.types import PipetteChannelType
from opentrons.hardware_control.instruments.ot2.pipette_handler import (
PipetteHandlerProvider,
)
Expand Down Expand Up @@ -39,7 +40,7 @@ def mock_pipettes_ot3(decoy: Decoy) -> Tuple[OT3Pipette, OT3Pipette]:


@pytest.fixture
def subject(decoy: Decoy, mock_pipette: Pipette) -> PipetteHandlerProvider:
def subject(decoy: Decoy, mock_pipette: Pipette) -> PipetteHandlerProvider[types.Mount]:
inst_by_mount = {types.Mount.LEFT: mock_pipette, types.Mount.RIGHT: None}
subject = PipetteHandlerProvider(attached_instruments=inst_by_mount)
return subject
Expand Down Expand Up @@ -99,7 +100,7 @@ def mock_pickup_list() -> List[TipActionMoveSpec]:
)
def test_plan_check_pick_up_tip_with_presses_argument(
decoy: Decoy,
subject: PipetteHandlerProvider,
subject: PipetteHandlerProvider[types.Mount],
mock_pipette: Pipette,
presses_input: int,
expected_array_length: int,
Expand Down Expand Up @@ -153,13 +154,13 @@ def test_plan_check_pick_up_tip_with_presses_argument(
)
def test_plan_check_pick_up_tip_with_presses_argument_ot3(
decoy: Decoy,
subject_ot3: PipetteHandlerProvider,
subject_ot3: PipetteHandlerProvider[types.Mount],
mock_pipette_ot3: OT3Pipette,
presses_input: int,
expected_array_length: int,
channels: int,
expected_pick_up_motor_actions: Optional[List[TipActionMoveSpec]],
request,
request: FixtureRequest,
) -> None:
"""Should return an array with expected length."""
mount = OT3Mount.LEFT
Expand Down Expand Up @@ -201,11 +202,13 @@ def test_plan_check_pick_up_tip_with_presses_argument_ot3(
).then_return(1.0)
decoy.when(mock_pipette_ot3.plunger_motor_current.run).then_return(1)
decoy.when(mock_pipette_ot3.config.quirks).then_return([])
decoy.when(mock_pipette_ot3.channels).then_return(channels)
decoy.when(mock_pipette_ot3.channels).then_return(PipetteChannelType(channels))
decoy.when(mock_pipette_ot3.config.end_tip_action_retract_distance_mm).then_return(
2
)

assert isinstance(subject_ot3, OT3PipetteHandler)

if channels == 96:
spec = subject_ot3.plan_ht_pick_up_tip(96)
else:
Expand All @@ -216,7 +219,9 @@ def test_plan_check_pick_up_tip_with_presses_argument_ot3(
)


def test_get_pipette_fails(decoy: Decoy, subject: PipetteHandlerProvider):
def test_get_pipette_fails(
decoy: Decoy, subject: PipetteHandlerProvider[types.Mount]
) -> None:
with pytest.raises(types.PipetteNotAttachedError):
subject.get_pipette(types.Mount.RIGHT)

Expand All @@ -233,12 +238,12 @@ def test_ot3_pipette_handler_gives_checks_with_different_pipettes(
left_offset: Optional[types.Point],
right_offset: Optional[types.Point],
ok: bool,
mock_pipettes_ot3: Tuple[OT3Pipette],
mock_pipettes_ot3: Tuple[OT3Pipette, OT3Pipette],
decoy: Decoy,
) -> None:
"""Should give you reasonable results with one or two pipettes attached."""
# with a left and not right pipette, we should be able to pass our checks
inst_by_mount: Dict[OT3Mount, OT3Pipette] = {}
inst_by_mount: Dict[OT3Mount, OT3Pipette | None] = {}
if left_offset is not None:
inst_by_mount[OT3Mount.LEFT] = mock_pipettes_ot3[0]
decoy.when(mock_pipettes_ot3[0].pipette_offset.offset).then_return(left_offset)
Expand All @@ -248,13 +253,15 @@ def test_ot3_pipette_handler_gives_checks_with_different_pipettes(
subject = OT3PipetteHandler(attached_instruments=inst_by_mount)
if left_offset is not None:
left_result = subject.get_instrument_offset(OT3Mount.LEFT)
assert left_result is not None
assert left_result.offset == left_offset
if ok:
assert left_result.reasonability_check_failures == []
else:
assert len(left_result.reasonability_check_failures) == 1
if right_offset is not None:
right_result = subject.get_instrument_offset(OT3Mount.RIGHT)
assert right_result is not None
assert right_result.offset == right_offset
if ok:
assert right_result.reasonability_check_failures == []
Expand Down
12 changes: 10 additions & 2 deletions api/tests/opentrons/hardware_control/test_types.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import enum
from typing import List, cast
from opentrons.hardware_control import types


def test_create_aionotify_event():
def test_create_aionotify_event() -> None:
class FakeEnum(enum.Enum):
CREATE = enum.auto()
DELETE = enum.auto()
MODIFY = enum.auto()

enum_list = [FakeEnum.CREATE, FakeEnum.DELETE, FakeEnum.MODIFY]
enum_list: List[enum.Enum] = cast(
List[enum.Enum], [FakeEnum.CREATE, FakeEnum.DELETE, FakeEnum.MODIFY]
)

# enum_list = [FakeEnum.CREATE, FakeEnum.DELETE, FakeEnum.MODIFY]

new_event = types.AionotifyEvent.build("fake event", enum_list)

assert hasattr(new_event.flags, "CREATE")
assert hasattr(new_event.flags, "DELETE")
assert hasattr(new_event.flags, "MODIFY")
assert new_event.flags.CREATE
assert new_event.flags.DELETE
assert new_event.flags.MODIFY
Expand Down
21 changes: 14 additions & 7 deletions api/tests/opentrons/hardware_control/test_util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List
from typing import List, Mapping, Tuple

from opentrons.hardware_control.util import plan_arc, check_motion_bounds
from opentrons.hardware_control.util import AxisType, plan_arc, check_motion_bounds
from opentrons.hardware_control.types import (
CriticalPoint,
MotionChecks,
Expand All @@ -13,7 +13,7 @@
import pytest


def check_arc_basic(arc: List[Point], from_pt: Point, to_pt: Point):
def check_arc_basic(arc: List[Point], from_pt: Point, to_pt: Point) -> None:
"""Check the tests that should always be true for different-well moves
- we should always go only up, then only xy, then only down
- we should have three moves
Expand Down Expand Up @@ -42,11 +42,11 @@ def check_arc_basic(arc: List[Point], from_pt: Point, to_pt: Point):
[Point(10, 20, 30), Point(10, 30, 40), 40],
],
)
def test_basic_arcs(from_pt, to_pt, z_height):
def test_basic_arcs(from_pt: Point, to_pt: Point, z_height: float) -> None:
check_arc_basic([a[0] for a in plan_arc(from_pt, to_pt, z_height)], from_pt, to_pt)


def test_arc_with_waypoint():
def test_arc_with_waypoint() -> None:
from_pt = Point(20, 20, 40)
to_pt = Point(0, 0, 10)
arc = plan_arc(from_pt, to_pt, 50, extra_waypoints=[(5, 10), (20, 30)])
Expand All @@ -59,7 +59,7 @@ def test_arc_with_waypoint():
assert arc[2][0].z == 50


def test_cp_blending():
def test_cp_blending() -> None:
from_pt = Point(10, 10, 10)
to_pt = Point(0, 0, 10)
arc = plan_arc(from_pt, to_pt, 50, None, CriticalPoint.XY_CENTER)
Expand Down Expand Up @@ -95,7 +95,14 @@ def test_cp_blending():
({Axis.Z: 5}, {Axis.Z: 3}, {Axis.Z: (2, 4)}, MotionChecks.BOTH, True, "high"),
],
)
def test_check_motion_bounds(xformed, deck, bounds, check, catch, phrase):
def test_check_motion_bounds(
xformed: Mapping[AxisType, float],
deck: Mapping[AxisType, float],
bounds: Mapping[AxisType, Tuple[float, float]],
check: MotionChecks,
catch: bool,
phrase: str,
) -> None:
if catch:
with pytest.raises(OutOfBoundsMove, match=phrase):
check_motion_bounds(xformed, deck, bounds, check)
Expand Down
Loading

0 comments on commit ecc6433

Please sign in to comment.