device: Remove hard dependency on hidapi

This commit is contained in:
MattHag 2024-09-26 01:30:18 +02:00 committed by Peter F. Patel-Schneider
parent 9907cb2875
commit 615499dce2
3 changed files with 25 additions and 25 deletions

View File

@ -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

View File

@ -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:

View File

@ -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