diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py index a627e6fc..0891bd63 100644 --- a/lib/logitech_receiver/device.py +++ b/lib/logitech_receiver/device.py @@ -19,13 +19,12 @@ import logging import threading import time +from typing import Any from typing import Callable from typing import Optional from typing import Protocol from typing import cast -import hidapi - from solaar import configuration from . import base @@ -65,7 +64,9 @@ low_level_interface = cast(LowLevelInterface, base) class DeviceFactory: @staticmethod - def create_device(low_level: LowLevelInterface, device_info, setting_callback=None): + def create_device( + find_paired_node_func: Callable[[str, int, int], Any], low_level: LowLevelInterface, device_info, setting_callback=None + ): """Opens a Logitech Device found attached to the machine, by Linux device path. :returns: An open file handle for the found receiver, or None. """ @@ -74,6 +75,7 @@ class DeviceFactory: if handle: # a direct connected device might not be online (as reported by user) return Device( + find_paired_node_func, low_level, None, None, @@ -98,6 +100,7 @@ class Device: def __init__( self, + find_paired_node_func: Callable[[str, int, int], Any], low_level: LowLevelInterface, receiver, number, @@ -154,7 +157,7 @@ class Device: self.cleanups = [] # functions to run on the device when it is closed if not self.path: - self.path = hidapi.find_paired_node(receiver.path, number, 1) if receiver else None + self.path = find_paired_node_func(receiver.path, number, 1) if receiver else None if not self.handle: try: self.handle = self.low_level.open_path(self.path) if self.path else None diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index ef76d8a8..9dfd53fd 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -24,6 +24,7 @@ from collections import namedtuple from functools import partial import gi +import hidapi import logitech_receiver from logitech_receiver import base @@ -257,7 +258,9 @@ def _start(device_info): if not isDevice: receiver_ = logitech_receiver.receiver.ReceiverFactory.create_receiver(device_info, _setting_callback) else: - receiver_ = logitech_receiver.device.DeviceFactory.create_device(base, device_info, _setting_callback) + receiver_ = logitech_receiver.device.DeviceFactory.create_device( + hidapi.find_paired_node, base, device_info, _setting_callback + ) if receiver_: configuration.attach_to(receiver_) if receiver_.bluetooth and receiver_.hid_serial: diff --git a/tests/logitech_receiver/test_device.py b/tests/logitech_receiver/test_device.py index e819b469..851b93d3 100644 --- a/tests/logitech_receiver/test_device.py +++ b/tests/logitech_receiver/test_device.py @@ -80,12 +80,12 @@ def test_create_device(device_info, responses, expected_success): low_level_mock = LowLevelInterfaceFake(responses) if expected_success is None: with pytest.raises(PermissionError): - device.DeviceFactory.create_device(low_level_mock, device_info) + device.DeviceFactory.create_device(mock.Mock(), low_level_mock, device_info) elif not expected_success: with pytest.raises(TypeError): - device.DeviceFactory.create_device(low_level_mock, device_info) + device.DeviceFactory.create_device(mock.Mock(), low_level_mock, device_info) else: - test_device = device.DeviceFactory.create_device(low_level_mock, device_info) + test_device = device.DeviceFactory.create_device(mock.Mock(), low_level_mock, device_info) assert bool(test_device) == expected_success @@ -96,7 +96,7 @@ def test_create_device(device_info, responses, expected_success): def test_device_name(device_info, responses, expected_codename, expected_name, expected_kind): low_level = LowLevelInterfaceFake(responses) - test_device = device.DeviceFactory.create_device(low_level, device_info) + test_device = device.DeviceFactory.create_device(mock.Mock(), low_level, device_info) assert test_device.codename == expected_codename assert test_device.name == expected_name @@ -124,7 +124,9 @@ def test_device_name(device_info, responses, expected_codename, expected_name, e ), ) def test_device_info(device_info, responses, handle, _name, _codename, number, protocol, registers): - test_device = device.Device(LowLevelInterfaceFake(responses), None, None, None, handle=handle, device_info=device_info) + test_device = device.Device( + mock.Mock(), LowLevelInterfaceFake(responses), None, None, None, handle=handle, device_info=device_info + ) assert test_device.handle == handle assert test_device._name == _name @@ -152,12 +154,6 @@ class FakeReceiver: return True -@pytest.fixture -def mock_hid(): - with mock.patch("hidapi.find_paired_node", return_value=None) as find_paired_node: - yield find_paired_node - - pi_CCCC = {"wpid": "CCCC", "kind": 0, "serial": None, "polling": "1ms", "power_switch": "top"} pi_2011 = {"wpid": "2011", "kind": 1, "serial": "1234", "polling": "2ms", "power_switch": "bottom"} pi_4066 = {"wpid": "4066", "kind": 1, "serial": "5678", "polling": "4ms", "power_switch": "left"} @@ -194,14 +190,14 @@ pi_DDDD = {"wpid": "DDDD", "kind": 2, "serial": "1234", "polling": "2ms", "power ], ), ) -def test_device_receiver(number, pairing_info, responses, handle, _name, codename, p, p2, name, mock_hid): - mock_hid.side_effect = lambda x, y, z: x - +def test_device_receiver(number, pairing_info, responses, handle, _name, codename, p, p2, name): low_level = LowLevelInterfaceFake(responses) low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number)) low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number)) - test_device = device.Device(low_level, FakeReceiver(codename="CODE"), number, True, pairing_info, handle=handle) + test_device = device.Device( + mock.Mock(), low_level, FakeReceiver(codename="CODE"), number, True, pairing_info, handle=handle + ) test_device.receiver.device = test_device assert test_device.handle == handle @@ -245,14 +241,12 @@ def test_device_receiver(number, pairing_info, responses, handle, _name, codenam ["1ms", "2ms", "4ms", "8ms", "1ms", "9ms"], # polling rate ), ) -def test_device_ids(number, info, responses, handle, unitId, modelId, tid, kind, firmware, serial, id, psl, rate, mock_hid): - mock_hid.side_effect = lambda x, y, z: x - +def test_device_ids(number, info, responses, handle, unitId, modelId, tid, kind, firmware, serial, id, psl, rate): low_level = LowLevelInterfaceFake(responses) low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number)) low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number)) - test_device = device.Device(low_level, FakeReceiver(), number, True, info, handle=handle) + test_device = device.Device(mock.Mock(), low_level, FakeReceiver(), number, True, info, handle=handle) assert test_device.unitId == unitId assert test_device.modelId == modelId @@ -267,7 +261,7 @@ def test_device_ids(number, info, responses, handle, unitId, modelId, tid, kind, class FakeDevice(device.Device): # a fully functional Device but its HID++ functions look at local data def __init__(self, responses, *args, **kwargs): self.responses = responses - super().__init__(LowLevelInterfaceFake(responses), *args, **kwargs) + super().__init__(mock.Mock(), LowLevelInterfaceFake(responses), *args, **kwargs) request = fake_hidpp.Device.request ping = fake_hidpp.Device.ping