Refactoring: modularity of write methods, improved error messages

pull/8/head^2
Ben Sartori 7 months ago
parent 105e23b187
commit b9a7466208
  1. 28
      README.md
  2. 317
      lednamebadge.py
  3. 162
      tests/test_lednamebadge_select_method.py

@ -146,27 +146,43 @@ prints the list of builtin icon names, including :happy: :happy2: :heart: :HEART
prints some condensed help:
<pre>
usage: led-badge-11x44.py [-h] [-t TYPE] [-s SPEED] [-B BRIGHTNESS] [-m MODE] [-b BLINK] [-a ANTS] [-l] MESSAGE [MESSAGE ...]
usage: lednamebadge.py [-h] [-t TYPE] [-H HID] [-M METHOD] [-E ENDPOINT]
[-s SPEED] [-B BRIGHTNESS] [-m MODE] [-b BLINK] [-a ANTS]
[-l]
MESSAGE [MESSAGE ...]
Upload messages or graphics to a 11x44 led badge via USB HID.
Version 0.12 from https://github.com/jnweiger/led-name-badge-ls32
-- see there for more examples and for updates.
positional arguments:
MESSAGE Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins
MESSAGE Up to 8 message texts with embedded builtin icons or
loaded images within colons(:) -- See -l for a list of
builtins
options:
-h, --help show this help message and exit
-t TYPE, --type TYPE Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.
-t TYPE, --type TYPE Type of display: supported values are 12x48 or (default)
11x44. Rename the program to led-badge-12x48, to switch
the default.
-H HID, --hid HID Deprecated, only for backwards compatibility, please use
-M! Set to 1 to ensure connect via HID API, program will
then not fallback to usb.core library
-M METHOD, --method METHOD
Force using the given write method ('hidapi' or 'libusb')
-E ENDPOINT, --endpoint ENDPOINT
Force using the given device endpoint
-s SPEED, --speed SPEED
Scroll speed (Range 1..8). Up to 8 comma-separated values
-B BRIGHTNESS, --brightness BRIGHTNESS
Brightness for the display in percent: 25, 50, 75, or 100
-m MODE, --mode MODE Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7);
laser(8); See '--mode-help' for more details.
-m MODE, --mode MODE Up to 8 mode values: Scroll-left(0) -right(1) -up(2)
-down(3); still-centered(4); animation(5); drop-down(6);
curtain(7); laser(8); See '--mode-help' for more details.
-b BLINK, --blink BLINK
1: blinking, 0: normal. Up to 8 comma-separated values
-a ANTS, --ants ANTS 1: animated border, 0: normal. Up to 8 comma-separated values
-a ANTS, --ants ANTS 1: animated border, 0: normal. Up to 8 comma-separated
values
-l, --list-names list named icons to be embedded in messages and exit
Example combining image and text:

@ -60,6 +60,7 @@
# * There is some initialization code executed in the classes not needed, if not imported. This is nagging me
# somehow, but it is acceptable, as we do not need to save every processor cycle, here :)
# * Have fun!
# v0.14, 2024-06-02, bs preparation for automatic or manual endpoint and bluetooth.
import argparse
@ -71,7 +72,7 @@ from array import array
from datetime import datetime
__version = "0.13"
__version = "0.14"
class SimpleTextAndIcons:
@ -294,7 +295,6 @@ class SimpleTextAndIcons:
for i in bitmap_named:
bitmap_builtin[bitmap_named[i][2]] = bitmap_named[i]
def __init__(self):
self.bitmap_preloaded = [([], 0)]
self.bitmaps_preloaded_unused = False
@ -304,17 +304,14 @@ class SimpleTextAndIcons:
self.bitmap_preloaded.append(SimpleTextAndIcons.bitmap_img(filename))
self.bitmaps_preloaded_unused = True
def are_preloaded_unused(self):
"""Still used by main, but deprecated. PLease use ":"-notation for bitmap() / bitmap_text()"""
return self.bitmaps_preloaded_unused == True
return self.bitmaps_preloaded_unused is True
@staticmethod
def _get_named_bitmaps_keys():
return SimpleTextAndIcons.bitmap_named.keys()
def bitmap_char(self, ch):
"""Returns a tuple of 11 bytes, it is the bitmap data of given character.
Example: ch = '_' returns (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255).
@ -330,7 +327,6 @@ class SimpleTextAndIcons:
o = SimpleTextAndIcons.char_offsets[ch]
return (SimpleTextAndIcons.font_11x44[o:o + 11], 1)
def bitmap_text(self, text):
"""Returns a tuple of (buffer, length_in_byte_columns_aka_chars)
We preprocess the text string for substitution patterns
@ -361,7 +357,6 @@ class SimpleTextAndIcons:
cols += n
return (buf, cols)
@staticmethod
def bitmap_img(file):
"""Returns a tuple of (buffer, length_in_byte_columns) representing the given image file.
@ -369,7 +364,12 @@ class SimpleTextAndIcons:
grayscale by arithmetic mean. Threshold for an active led is then > 127.
If the width is not a multiple on 8 it will be padded with empty pixel-columns.
"""
from PIL import Image
try:
from PIL import Image
except:
print("If you like to use images, the module pillow is needed. Try:")
print("$ pip install pillow")
sys.exit(1)
im = Image.open(file)
print("fetching bitmap from file %s -> (%d x %d)" % (file, im.width, im.height))
@ -398,7 +398,6 @@ class SimpleTextAndIcons:
im.close()
return (buf, cols)
def bitmap(self, arg):
"""If arg is a valid and existing path name, we load it as an image.
Otherwise, we take it as a string (with ":"-notation, see bitmap_text()).
@ -408,58 +407,124 @@ class SimpleTextAndIcons:
return self.bitmap_text(arg)
class LedNameBadge:
_protocol_header_template = (
0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
)
_have_pyhidapi = False
class WriteMethod:
@staticmethod
def add_padding(buf, blocksize):
need_padding = len(buf) % blocksize
if need_padding:
buf.extend((0,) * (blocksize - need_padding))
@staticmethod
def check_length(buf, maxsize):
if len(buf) > maxsize:
print("Writing more than %d bytes damages the display!" % (maxsize,))
sys.exit(1)
def has_device(self):
raise NotImplementedError()
def write(self, buf):
self.add_padding(buf, 64)
self.check_length(buf, 8192)
self._write(buf)
def _write(self, buf):
raise NotImplementedError()
class WriteLibUsb(WriteMethod):
_module_loaded = False
try:
if sys.version_info[0] < 3:
print("Preferring Pyusb over Pyhidapi with Python 2.x")
raise Exception("Prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
import pyhidapi
pyhidapi.hid_init()
_have_pyhidapi = True
print("Pyhidapi detected")
import usb.core
_module_loaded = True
print("Module pyusb detected")
except:
try:
import usb.core
print("Pyusb detected")
except:
print("ERROR: Need the pyhidapi or usb.core module.")
if sys.platform == "darwin":
print("""Please try
pip3 install pyhidapi
pip install pyhidapi
brew install hidapi
""")
elif sys.platform == "linux":
print("""Please try
sudo pip3 install pyhidapi
sudo pip install pyhidapi
sudo apt-get install libhidapi-hidraw0
sudo ln -s /usr/lib/x86_64-linux-gnu/libhidapi-hidraw.so.0 /usr/local/lib/
or
sudo apt-get install python3-usb
""")
else: # windows?
print("""Please try with Linux or MacOS or help us implement support for """ + sys.platform)
sys.exit(1)
pass
def __init__(self, endpoint):
self.dev = None
if WriteLibUsb._module_loaded:
self.dev = WriteLibUsb.usb.core.find(idVendor=0x0416, idProduct=0x5020)
if self.dev:
print("Libusb device initialized")
@staticmethod
def _prepare_iterable(iterable, min_, max_):
def is_ready():
return WriteLibUsb._module_loaded
def has_device(self):
return self.dev is not None
def _write(self, buf):
if not self.dev:
return
try:
iterable = [min(max(x, min_), max_) for x in iterable]
iterable = tuple(iterable) + (iterable[-1],) * (8 - len(iterable)) # repeat last element
return iterable
# win32: NotImplementedError: is_kernel_driver_active
if self.dev.is_kernel_driver_active(0):
self.dev.detach_kernel_driver(0)
except:
raise TypeError("Please give a list or tuple with at least one number: " + str(iterable))
pass
self.dev.set_configuration()
print("Write using [%s %s] bus=%d dev=%d via libusb" %
(self.dev.manufacturer, self.dev.product, self.dev.bus, self.dev.address))
for i in range(int(len(buf) / 64)):
time.sleep(0.1)
self.dev.write(1, buf[i * 64:i * 64 + 64])
class WriteUsbHidApi(WriteMethod):
_module_loaded = False
try:
import pyhidapi
pyhidapi.hid_init()
_module_loaded = True
print("Module pyhidapi detected")
except:
pass
def __init__(self, endpoint):
self.dev = None
self.dev_info = None
if WriteUsbHidApi._module_loaded:
self.dev_info = WriteUsbHidApi.pyhidapi.hid_enumerate(0x0416, 0x5020)
if self.dev_info:
self.dev = WriteUsbHidApi.pyhidapi.hid_open_path(self.dev_info[0].path)
if self.dev:
print("Hidapi device initialized")
# alternative: self.dev = WriteUsbHidApi.pyhidapi.hid_open(0x0416, 0x5020)
@staticmethod
def is_ready():
return WriteUsbHidApi._module_loaded
def has_device(self):
return self.dev is not None
def _write(self, buf):
if not self.dev or not self.dev_info:
return
print("Write using [%s %s] int=%d page=%s via hidapi" % (
self.dev_info[0].manufacturer_string, self.dev_info[0].product_string,
self.dev_info[0].interface_number, self.dev_info[0].usage_page))
for i in range(int(len(buf)/64)):
# sendbuf must contain "report ID" as first byte. "0" does the job here.
sendbuf = array('B', [0])
# Then, put the 64 payload bytes into the buffer
sendbuf.extend(buf[i*64:i*64+64])
WriteUsbHidApi.pyhidapi.hid_write(self.dev, sendbuf)
WriteUsbHidApi.pyhidapi.hid_close(self.dev)
class LedNameBadge:
_protocol_header_template = (
0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
)
@staticmethod
def header(lengths, speeds, modes, blinks, ants, brightness=100, date=datetime.now()):
@ -523,62 +588,106 @@ or
return h
@staticmethod
def _prepare_iterable(iterable, min_, max_):
try:
iterable = [min(max(x, min_), max_) for x in iterable]
iterable = tuple(iterable) + (iterable[-1],) * (8 - len(iterable)) # repeat last element
return iterable
except:
raise TypeError("Please give a list or tuple with at least one number: " + str(iterable))
@staticmethod
def write(buf):
def write(buf, method = 'auto', endpoint = 'auto'):
"""Write the given buffer to the device.
It has to begin with a protocol header as provided by header() and followed by the bitmap data.
In short: the bitmap data is organized in bytes with 8 horizontal pixels per byte and 11 resp. 12
bytes per (8 pixels wide) byte-column. Then just put one byte-column after the other and one bitmap
after the other.
"""
need_padding = len(buf) % 64
if need_padding:
buf.extend((0,) * (64 - need_padding))
write_method = LedNameBadge._find_write_method(method, endpoint)
if write_method:
write_method.write(buf)
if len(buf) > 8192:
print("Writing more than 8192 bytes damages the display!")
@staticmethod
def _find_write_method(method, endpoint):
if method is None:
method = 'auto'
if endpoint is None:
endpoint = 'auto'
if method not in ('libusb', 'hidapi', 'auto'):
print("Unknown write method '%s'." % (method,))
sys.exit(1)
if LedNameBadge._have_pyhidapi:
dev_info = LedNameBadge.pyhidapi.hid_enumerate(0x0416, 0x5020)
# dev = pyhidapi.hid_open(0x0416, 0x5020)
if dev_info:
dev = LedNameBadge.pyhidapi.hid_open_path(dev_info[0].path)
print("using [%s %s] int=%d page=%s via pyHIDAPI" % (
dev_info[0].manufacturer_string, dev_info[0].product_string, dev_info[0].interface_number, dev_info[0].usage_page))
else:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.")
if method == 'libusb':
if sys.platform == "darwin":
print("For MacOs, please use method 'hidapi' or 'auto'.")
print("Or help us implementing support for MacOs.")
sys.exit(1)
for i in range(int(len(buf)/64)):
# sendbuf must contain "report ID" as first byte. "0" does the job here.
sendbuf=array('B',[0])
# Then, put the 64 payload bytes into the buffer
sendbuf.extend(buf[i*64:i*64+64])
LedNameBadge.pyhidapi.hid_write(dev, sendbuf)
LedNameBadge.pyhidapi.hid_close(dev)
else:
dev = LedNameBadge.usb.core.find(idVendor=0x0416, idProduct=0x5020)
if dev is None:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.")
elif not WriteLibUsb.is_ready():
print("The method 'libusb' is not possible to be used: The module could not be loaded.")
print("* Have you installed the Module? Try:")
print(" $ pip install pyusb")
if sys.platform == 'windows':
print("""* Have you installed the libusb driver or libusb-filter for the device?""")
sys.exit(1)
try:
# win32: NotImplementedError: is_kernel_driver_active
if dev.is_kernel_driver_active(0):
dev.detach_kernel_driver(0)
except:
pass
dev.set_configuration()
print("using [%s %s] bus=%d dev=%d" % (dev.manufacturer, dev.product, dev.bus, dev.address))
for i in range(int(len(buf) / 64)):
time.sleep(0.1)
dev.write(1, buf[i * 64:i * 64 + 64])
if method == 'hidapi':
if sys.platform == "windows":
print("For Windows, please use method 'libusb' or 'auto'.")
print("Or help us implementing support for Windows.")
sys.exit(1)
elif sys.version_info[0] < 3:
print("Please use method 'libusb' or 'auto' with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
sys.exit(1)
elif not WriteUsbHidApi.is_ready():
print("The method 'hidapi' is not possible to be used: The module could not be loaded.")
print("* Have you installed the Module? Try:")
print(" $ pip install pyhidapi")
if sys.platform == 'darwin':
print("* Have you installed the library itself? Try:")
print(" $ brew install hidapi")
elif sys.platform == 'linux':
print(" or")
print(" $ sudo apt-get install python3-usb")
print("* Is the library itself installed? Try (or similar, suitable for your distro):")
print(" $ sudo apt-get install libhidapi-hidraw0")
print("* If the library is still not found by the module, try (or similar, suitable for you distro):")
print(" $ sudo ln -s /usr/lib/x86_64-linux-gnu/libhidapi-hidraw.so.0 /usr/local/lib/")
sys.exit(1)
# Python2 only with libusb
if method == 'auto' and sys.version_info[0] < 3:
method = 'libusb'
print("Preferring method 'libusb' over 'hidapi' with Python 2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
if (method == 'auto' or method == 'hidapi') and WriteUsbHidApi.is_ready():
method_obj = WriteUsbHidApi(endpoint)
if method_obj.has_device():
return method_obj
if (method == 'auto' or method == 'libusb') and WriteLibUsb.is_ready():
method_obj = WriteLibUsb(endpoint)
if method_obj.has_device():
return method_obj
endpoint_str = ''
if endpoint != 'auto':
endpoint = int(endpoint)
endpoint_str = ' on endpoint %d' % (endpoint,)
print("The device is not available with write method '%s'%s." % (method, endpoint_str))
print("* Is a led tag device with vendorID 0x0416 and productID 0x5020 connected?")
if endpoint != 'auto':
print("* Have you given the right endpoint?")
if sys.platform == "linux":
print(" Try this to find the available endpoint addresses:")
print(' $ lsusb -d 0416:5020 -v | grep -i "endpoint.*out"')
print("* If it is connected and still do not work, maybe you have to run this program as root.")
sys.exit(1)
def split_to_ints(list_str):
return [int(x) for x in re.split(r'[\s,]+', list_str)]
def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
@ -586,7 +695,9 @@ def main():
epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0])
parser.add_argument('-t', '--type', default='11x44',
help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.")
parser.add_argument('-H', '--hid', default='0', help="Set to 1 to ensure connect via HID API, program will then not fallback to usb.core library")
parser.add_argument('-H', '--hid', default='0', help="Deprecated, only for backwards compatibility, please use -M! Set to 1 to ensure connect via HID API, program will then not fallback to usb.core library")
parser.add_argument('-M', '--method', default='auto', help="Force using the given write method ('hidapi' or 'libusb')")
parser.add_argument('-E', '--endpoint', default='auto', help="Force using the given device endpoint")
parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values")
parser.add_argument('-B', '--brightness', default='100',
help="Brightness for the display in percent: 25, 50, 75, or 100")
@ -660,11 +771,19 @@ def main():
for msg_bitmap in msg_bitmaps:
buf.extend(msg_bitmap[0])
if not LedNameBadge._have_pyhidapi:
if args.hid != "0":
sys.exit("HID API access is needed but not initialized. Fix your setup")
# Translate -H to -M parameter
method = args.method
if args.hid == 1:
if not method or method == 'auto':
method = 'hidapi'
else:
sys.exit("Parameter values are ambiguous. Please use either -H or -M.")
LedNameBadge.write(buf, method, args.endpoint)
LedNameBadge.write(buf)
def split_to_ints(list_str):
return [int(x) for x in re.split(r'[\s,]+', list_str)]
if __name__ == '__main__':

@ -0,0 +1,162 @@
import sys
from unittest import TestCase
from unittest.mock import patch, MagicMock
from io import StringIO
class Test(TestCase):
def setUp(self):
print("Real platform: " + sys.platform)
@patch('sys.platform', new='linux')
def test_all_in_linux_positive(self):
method, output = self.call_it(True, True, True, None, None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(True, True, True, 'libusb', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(True, True, True, 'hidapi', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
@patch('sys.platform', new='linux')
def test_only_one_lib_linux_positive(self):
method, output = self.call_it(False, True, True, None, None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(False, True, True, 'hidapi', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(True, False, True, None, None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(True, False, True, 'libusb', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
@patch('sys.platform', new='windows')
def test_windows_positive(self):
method, output = self.call_it(True, False, True, None, None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(True, False, True, 'libusb', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
@patch('sys.platform', new='darwin')
def test_macos_positive(self):
method, output = self.call_it(False, True, True, None, None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
method, output = self.call_it(False, True, True, 'hidapi', None)
self.assertIn('device initialized', output)
self.assertIsNotNone(method)
#--------------------------------------------------------------------------
@patch('sys.platform', new='linux')
def test_all_in_linux_negative(self):
method, output = self.call_it(True, True, False, None, None)
self.assertNotIn('device initialized', output)
self.assertIn('device is not available', output)
self.assertIsNone(method)
method, output = self.call_it(True, True, False, 'libusb', None)
self.assertNotIn('device initialized', output)
self.assertIn('device is not available', output)
self.assertIsNone(method)
method, output = self.call_it(True, True, False, 'hidapi', None)
self.assertNotIn('device initialized', output)
self.assertIn('device is not available', output)
self.assertIsNone(method)
@patch('sys.platform', new='linux')
def test_all_out_linux_negative(self):
method, output = self.call_it(False, False, False, None, None)
self.assertNotIn('device initialized', output)
self.assertIn('device is not available', output)
self.assertIsNone(method)
method, output = self.call_it(False, False, False, 'libusb', None)
self.assertNotIn('device initialized', output)
self.assertIn('is not possible to be used', output)
self.assertIsNone(method)
method, output = self.call_it(False, False, False, 'hidapi', None)
self.assertNotIn('device initialized', output)
self.assertIn('is not possible to be used', output)
self.assertIsNone(method)
@patch('sys.platform', new='windows')
def test_windows_negative(self):
method, output = self.call_it(True, False, True, 'hidapi', None)
self.assertNotIn('device initialized', output)
self.assertIn('please use method', output)
self.assertIsNone(method)
@patch('sys.platform', new='darwin')
def test_macos_negative(self):
method, output = self.call_it(False, True, True, 'libusb', None)
self.assertNotIn('device initialized', output)
self.assertIn('please use method', output)
self.assertIsNone(method)
#--------------------------------------------------------------------------
def call_it_neg(self, pyusb_available, pyhidapi_available, device_available, method, endpoint):
method_obj = None
output = None
with self.assertRaises(SystemExit):
method_obj, output = self.call_it(pyusb_available, pyhidapi_available, device_available, method, endpoint)
return method_obj, output
def call_it(self, pyusb_available, pyhidapi_available, device_available, method, endpoint):
method_obj = None
output = None
with self.do_import_patch(pyusb_available, pyhidapi_available, device_available) as mock:
with patch('sys.stdout', new_callable=StringIO) as stdio_mock:
import lednamebadge
try:
method_obj = lednamebadge.LedNameBadge._find_write_method(method, endpoint)
except(SystemExit):
pass
output = stdio_mock.getvalue()
print(output)
self.assertEqual(pyusb_available, 'pyusb detected' in output)
self.assertEqual(pyhidapi_available, 'pyhidapi detected' in output)
return method_obj, output
def do_import_patch(self, pyusb_available, pyhidapi_available, device_available):
return patch.dict('sys.modules',
{
'pyhidapi': self.create_hid_mock(device_available) if pyhidapi_available else None,
'usb': self.create_usb_mock(device_available) if pyusb_available else None,
'usb.core': MagicMock() if pyusb_available else None})
def create_hid_mock(self, device_available):
device = MagicMock()
device.path = 'devicepath'
mock = MagicMock()
mock.hid_enumerate.return_value = [device] if device_available else None
mock.hid_open_path.return_value = 'device' if device_available else None
return mock
def create_usb_mock(self, device_available):
mock = MagicMock()
mock.core = MagicMock()
mock.core.find.return_value = 'device' if device_available else None
return mock
Loading…
Cancel
Save