device: Remove hard dependency on hidapi
This commit is contained in:
parent
9907cb2875
commit
615499dce2
|
@ -19,13 +19,12 @@ import logging
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Protocol
|
from typing import Protocol
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
import hidapi
|
|
||||||
|
|
||||||
from solaar import configuration
|
from solaar import configuration
|
||||||
|
|
||||||
from . import base
|
from . import base
|
||||||
|
@ -65,7 +64,9 @@ low_level_interface = cast(LowLevelInterface, base)
|
||||||
|
|
||||||
class DeviceFactory:
|
class DeviceFactory:
|
||||||
@staticmethod
|
@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.
|
"""Opens a Logitech Device found attached to the machine, by Linux device path.
|
||||||
:returns: An open file handle for the found receiver, or None.
|
:returns: An open file handle for the found receiver, or None.
|
||||||
"""
|
"""
|
||||||
|
@ -74,6 +75,7 @@ class DeviceFactory:
|
||||||
if handle:
|
if handle:
|
||||||
# a direct connected device might not be online (as reported by user)
|
# a direct connected device might not be online (as reported by user)
|
||||||
return Device(
|
return Device(
|
||||||
|
find_paired_node_func,
|
||||||
low_level,
|
low_level,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -98,6 +100,7 @@ class Device:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
find_paired_node_func: Callable[[str, int, int], Any],
|
||||||
low_level: LowLevelInterface,
|
low_level: LowLevelInterface,
|
||||||
receiver,
|
receiver,
|
||||||
number,
|
number,
|
||||||
|
@ -154,7 +157,7 @@ class Device:
|
||||||
self.cleanups = [] # functions to run on the device when it is closed
|
self.cleanups = [] # functions to run on the device when it is closed
|
||||||
|
|
||||||
if not self.path:
|
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:
|
if not self.handle:
|
||||||
try:
|
try:
|
||||||
self.handle = self.low_level.open_path(self.path) if self.path else None
|
self.handle = self.low_level.open_path(self.path) if self.path else None
|
||||||
|
|
|
@ -24,6 +24,7 @@ from collections import namedtuple
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
import hidapi
|
||||||
import logitech_receiver
|
import logitech_receiver
|
||||||
|
|
||||||
from logitech_receiver import base
|
from logitech_receiver import base
|
||||||
|
@ -257,7 +258,9 @@ def _start(device_info):
|
||||||
if not isDevice:
|
if not isDevice:
|
||||||
receiver_ = logitech_receiver.receiver.ReceiverFactory.create_receiver(device_info, _setting_callback)
|
receiver_ = logitech_receiver.receiver.ReceiverFactory.create_receiver(device_info, _setting_callback)
|
||||||
else:
|
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_:
|
if receiver_:
|
||||||
configuration.attach_to(receiver_)
|
configuration.attach_to(receiver_)
|
||||||
if receiver_.bluetooth and receiver_.hid_serial:
|
if receiver_.bluetooth and receiver_.hid_serial:
|
||||||
|
|
|
@ -80,12 +80,12 @@ def test_create_device(device_info, responses, expected_success):
|
||||||
low_level_mock = LowLevelInterfaceFake(responses)
|
low_level_mock = LowLevelInterfaceFake(responses)
|
||||||
if expected_success is None:
|
if expected_success is None:
|
||||||
with pytest.raises(PermissionError):
|
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:
|
elif not expected_success:
|
||||||
with pytest.raises(TypeError):
|
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:
|
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
|
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):
|
def test_device_name(device_info, responses, expected_codename, expected_name, expected_kind):
|
||||||
low_level = LowLevelInterfaceFake(responses)
|
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.codename == expected_codename
|
||||||
assert test_device.name == expected_name
|
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):
|
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.handle == handle
|
||||||
assert test_device._name == _name
|
assert test_device._name == _name
|
||||||
|
@ -152,12 +154,6 @@ class FakeReceiver:
|
||||||
return True
|
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_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_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"}
|
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):
|
def test_device_receiver(number, pairing_info, responses, handle, _name, codename, p, p2, name):
|
||||||
mock_hid.side_effect = lambda x, y, z: x
|
|
||||||
|
|
||||||
low_level = LowLevelInterfaceFake(responses)
|
low_level = LowLevelInterfaceFake(responses)
|
||||||
low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number))
|
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))
|
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
|
test_device.receiver.device = test_device
|
||||||
|
|
||||||
assert test_device.handle == handle
|
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
|
["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):
|
def test_device_ids(number, info, responses, handle, unitId, modelId, tid, kind, firmware, serial, id, psl, rate):
|
||||||
mock_hid.side_effect = lambda x, y, z: x
|
|
||||||
|
|
||||||
low_level = LowLevelInterfaceFake(responses)
|
low_level = LowLevelInterfaceFake(responses)
|
||||||
low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number))
|
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))
|
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.unitId == unitId
|
||||||
assert test_device.modelId == modelId
|
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
|
class FakeDevice(device.Device): # a fully functional Device but its HID++ functions look at local data
|
||||||
def __init__(self, responses, *args, **kwargs):
|
def __init__(self, responses, *args, **kwargs):
|
||||||
self.responses = responses
|
self.responses = responses
|
||||||
super().__init__(LowLevelInterfaceFake(responses), *args, **kwargs)
|
super().__init__(mock.Mock(), LowLevelInterfaceFake(responses), *args, **kwargs)
|
||||||
|
|
||||||
request = fake_hidpp.Device.request
|
request = fake_hidpp.Device.request
|
||||||
ping = fake_hidpp.Device.ping
|
ping = fake_hidpp.Device.ping
|
||||||
|
|
Loading…
Reference in New Issue