logging: Simplify logger instantiation

* logging: Simplify logger instantiation

Relates #2254

* logging: Remove aliases

Relates #2254

* logging: Replace deprecated warn with warning

Related #2254

* logging: Fix mistake

Related #2257
This commit is contained in:
MattHag 2024-02-10 19:55:27 +01:00 committed by GitHub
parent 8b1463c8f4
commit 87658fb189
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 638 additions and 703 deletions

View File

@ -26,16 +26,15 @@ which is MIT licensed.
""" """
import atexit import atexit
import ctypes import ctypes
import logging
import platform as _platform import platform as _platform
from collections import namedtuple from collections import namedtuple
from logging import INFO as _INFO
from logging import getLogger
from threading import Thread from threading import Thread
from time import sleep from time import sleep
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
native_implementation = 'hidapi' native_implementation = 'hidapi'
# Device info as expected by Solaar # Device info as expected by Solaar
@ -257,14 +256,14 @@ def _match(action, device, filterfn):
if len(report) == 1 + 19 and report[0] == 0x11: if len(report) == 1 + 19 and report[0] == 0x11:
device['hidpp_long'] = True device['hidpp_long'] = True
except HIDError as e: # noqa: F841 except HIDError as e: # noqa: F841
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}") logger.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}")
finally: finally:
if device_handle: if device_handle:
close(device_handle) close(device_handle)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info( logger.info(
'Found device BID %s VID %04X PID %04X HID++ %s %s', bus_id, vid, pid, device['hidpp_short'], device['hidpp_long'] 'Found device BID %s VID %04X PID %04X HID++ %s %s', bus_id, vid, pid, device['hidpp_short'], device['hidpp_long']
) )

View File

@ -25,13 +25,12 @@ necessary.
""" """
import errno as _errno import errno as _errno
import logging
import os as _os import os as _os
import warnings as _warnings import warnings as _warnings
# the tuple object we'll expose when enumerating devices # the tuple object we'll expose when enumerating devices
from collections import namedtuple from collections import namedtuple
from logging import INFO as _INFO
from logging import getLogger
from select import select as _select from select import select as _select
from time import sleep from time import sleep
from time import time as _timestamp from time import time as _timestamp
@ -42,8 +41,8 @@ from pyudev import DeviceNotFoundError
from pyudev import Devices as _Devices from pyudev import Devices as _Devices
from pyudev import Monitor as _Monitor from pyudev import Monitor as _Monitor
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
native_implementation = 'udev' native_implementation = 'udev'
fileopen = open fileopen = open
@ -123,7 +122,7 @@ def _match(action, device, filterfn):
return return
except Exception as e: # if can't process report descriptor fall back to old scheme except Exception as e: # if can't process report descriptor fall back to old scheme
hidpp_short = hidpp_long = None hidpp_short = hidpp_long = None
_log.warn( logger.warning(
'Report Descriptor not processed for DEVICE %s BID %s VID %s PID %s: %s', device.device_node, bid, vid, pid, e 'Report Descriptor not processed for DEVICE %s BID %s VID %s PID %s: %s', device.device_node, bid, vid, pid, e
) )
@ -147,8 +146,8 @@ def _match(action, device, filterfn):
intf_device = device.find_parent('usb', 'usb_interface') intf_device = device.find_parent('usb', 'usb_interface')
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber') usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
# print('*** usb interface', action, device, 'usb_interface:', intf_device, usb_interface, interface_number) # print('*** usb interface', action, device, 'usb_interface:', intf_device, usb_interface, interface_number)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info( logger.info(
'Found device %s BID %s VID %s PID %s HID++ %s %s USB %s %s', device.device_node, bid, vid, pid, hidpp_short, 'Found device %s BID %s VID %s PID %s HID++ %s %s USB %s %s', device.device_node, bid, vid, pid, hidpp_short,
hidpp_long, usb_interface, interface_number hidpp_long, usb_interface, interface_number
) )
@ -325,14 +324,14 @@ def open_path(device_path):
assert device_path assert device_path
assert device_path.startswith('/dev/hidraw') assert device_path.startswith('/dev/hidraw')
_log.info('OPEN PATH %s', device_path) logger.info('OPEN PATH %s', device_path)
retrycount = 0 retrycount = 0
while (retrycount < 3): while (retrycount < 3):
retrycount += 1 retrycount += 1
try: try:
return _os.open(device_path, _os.O_RDWR | _os.O_SYNC) return _os.open(device_path, _os.O_RDWR | _os.O_SYNC)
except OSError as e: except OSError as e:
_log.info('OPEN PATH FAILED %s ERROR %s %s', device_path, e.errno, e) logger.info('OPEN PATH FAILED %s ERROR %s %s', device_path, e.errno, e)
if e.errno == _errno.EACCES: if e.errno == _errno.EACCES:
sleep(0.1) sleep(0.1)
else: else:

View File

@ -37,12 +37,11 @@ from .device import Device # noqa: F401
from .hidpp20 import FeatureCallError, FeatureNotSupported # noqa: F401 from .hidpp20 import FeatureCallError, FeatureNotSupported # noqa: F401
from .receiver import Receiver # noqa: F401 from .receiver import Receiver # noqa: F401
_DEBUG = logging.DEBUG logger = logging.getLogger(__name__)
_log = logging.getLogger(__name__) logger.setLevel(logging.root.level)
_log.setLevel(logging.root.level)
# if logging.root.level > logging.DEBUG: # if logging.root.level > logging.DEBUG:
# _log.addHandler(logging.NullHandler()) # logger.addHandler(logging.NullHandler())
# _log.propagate = 0 # logger.propagate = 0
del logging del logging

View File

@ -19,13 +19,11 @@
# Base low-level functions used by the API proper. # Base low-level functions used by the API proper.
# Unlikely to be used directly unless you're expanding the API. # Unlikely to be used directly unless you're expanding the API.
import logging
import threading as _threading import threading as _threading
from collections import namedtuple from collections import namedtuple
from contextlib import contextmanager from contextlib import contextmanager
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import getLogger
from random import getrandbits as _random_bits from random import getrandbits as _random_bits
from struct import pack as _pack from struct import pack as _pack
from time import time as _timestamp from time import time as _timestamp
@ -40,8 +38,7 @@ from .base_usb import other_device_check as _other_device_check
from .common import KwException as _KwException from .common import KwException as _KwException
from .common import strhex as _strhex from .common import strhex as _strhex
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -184,10 +181,10 @@ def close(handle):
_hid.close(handle) _hid.close(handle)
else: else:
handle.close() handle.close()
# _log.info("closed receiver handle %r", handle) # logger.info("closed receiver handle %r", handle)
return True return True
except Exception: except Exception:
# _log.exception("closing receiver handle %r", handle) # logger.exception("closing receiver handle %r", handle)
pass pass
return False return False
@ -214,13 +211,13 @@ def write(handle, devnumber, data, long_message=False):
wdata = _pack('!BB18s', HIDPP_LONG_MESSAGE_ID, devnumber, data) wdata = _pack('!BB18s', HIDPP_LONG_MESSAGE_ID, devnumber, data)
else: else:
wdata = _pack('!BB5s', HIDPP_SHORT_MESSAGE_ID, devnumber, data) wdata = _pack('!BB5s', HIDPP_SHORT_MESSAGE_ID, devnumber, data)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('(%s) <= w[%02X %02X %s %s]', handle, ord(wdata[:1]), devnumber, _strhex(wdata[2:4]), _strhex(wdata[4:])) logger.debug('(%s) <= w[%02X %02X %s %s]', handle, ord(wdata[:1]), devnumber, _strhex(wdata[2:4]), _strhex(wdata[4:]))
try: try:
_hid.write(int(handle), wdata) _hid.write(int(handle), wdata)
except Exception as reason: except Exception as reason:
_log.error('write failed, assuming handle %r no longer available', handle) logger.error('write failed, assuming handle %r no longer available', handle)
close(handle) close(handle)
raise NoReceiver(reason=reason) raise NoReceiver(reason=reason)
@ -251,7 +248,7 @@ def check_message(data):
if report_lengths.get(report_id) == len(data): if report_lengths.get(report_id) == len(data):
return True return True
else: else:
_log.warn('unexpected message size: report_id %02X message %s' % (report_id, _strhex(data))) logger.warning('unexpected message size: report_id %02X message %s' % (report_id, _strhex(data)))
return False return False
@ -269,7 +266,7 @@ def _read(handle, timeout):
timeout = int(timeout * 1000) timeout = int(timeout * 1000)
data = _hid.read(int(handle), _MAX_READ_SIZE, timeout) data = _hid.read(int(handle), _MAX_READ_SIZE, timeout)
except Exception as reason: except Exception as reason:
_log.warn('read failed, assuming handle %r no longer available', handle) logger.warning('read failed, assuming handle %r no longer available', handle)
close(handle) close(handle)
raise NoReceiver(reason=reason) raise NoReceiver(reason=reason)
@ -277,8 +274,9 @@ def _read(handle, timeout):
report_id = ord(data[:1]) report_id = ord(data[:1])
devnumber = ord(data[1:2]) devnumber = ord(data[1:2])
if _log.isEnabledFor(_DEBUG) and (report_id != DJ_MESSAGE_ID or ord(data[2:3]) > 0x10): # ignore DJ input messages if logger.isEnabledFor(logging.DEBUG
_log.debug('(%s) => r[%02X %02X %s %s]', handle, report_id, devnumber, _strhex(data[2:4]), _strhex(data[4:])) ) and (report_id != DJ_MESSAGE_ID or ord(data[2:3]) > 0x10): # ignore DJ input messages
logger.debug('(%s) => r[%02X %02X %s %s]', handle, report_id, devnumber, _strhex(data[2:4]), _strhex(data[4:]))
return report_id, devnumber, data[2:] return report_id, devnumber, data[2:]
@ -299,7 +297,7 @@ def _skip_incoming(handle, ihandle, notifications_hook):
# read whatever is already in the buffer, if any # read whatever is already in the buffer, if any
data = _hid.read(ihandle, _MAX_READ_SIZE, 0) data = _hid.read(ihandle, _MAX_READ_SIZE, 0)
except Exception as reason: except Exception as reason:
_log.error('read failed, assuming receiver %s no longer available', handle) logger.error('read failed, assuming receiver %s no longer available', handle)
close(handle) close(handle)
raise NoReceiver(reason=reason) raise NoReceiver(reason=reason)
@ -363,8 +361,8 @@ handles_lock = {}
def handle_lock(handle): def handle_lock(handle):
with request_lock: with request_lock:
if handles_lock.get(handle) is None: if handles_lock.get(handle) is None:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('New lock %s', repr(handle)) logger.info('New lock %s', repr(handle))
handles_lock[handle] = _threading.Lock() # Serialize requests on the handle handles_lock[handle] = _threading.Lock() # Serialize requests on the handle
return handles_lock[handle] return handles_lock[handle]
@ -375,7 +373,7 @@ def acquire_timeout(lock, handle, timeout):
result = lock.acquire(timeout=timeout) result = lock.acquire(timeout=timeout)
try: try:
if not result: if not result:
_log.error('lock on handle %d not acquired, probably due to timeout', int(handle)) logger.error('lock on handle %d not acquired, probably due to timeout', int(handle))
yield result yield result
finally: finally:
if result: if result:
@ -414,8 +412,8 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
params = b''.join(_pack('B', p) if isinstance(p, int) else p for p in params) params = b''.join(_pack('B', p) if isinstance(p, int) else p for p in params)
else: else:
params = b'' params = b''
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("(%s) device %d request_id {%04X} params [%s]", handle, devnumber, request_id, _strhex(params)) # logger.debug("(%s) device %d request_id {%04X} params [%s]", handle, devnumber, request_id, _strhex(params))
request_data = _pack('!H', request_id) + params request_data = _pack('!H', request_id) + params
ihandle = int(handle) ihandle = int(handle)
@ -423,7 +421,7 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
try: try:
_skip_incoming(handle, ihandle, notifications_hook) _skip_incoming(handle, ihandle, notifications_hook)
except NoReceiver: except NoReceiver:
_log.warn('device or receiver disconnected') logger.warning('device or receiver disconnected')
return None return None
write(ihandle, devnumber, request_data, long_message) write(ihandle, devnumber, request_data, long_message)
@ -444,8 +442,8 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
]: ]:
error = ord(reply_data[3:4]) error = ord(reply_data[3:4])
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug( logger.debug(
'(%s) device 0x%02X error on request {%04X}: %d = %s', handle, devnumber, request_id, error, '(%s) device 0x%02X error on request {%04X}: %d = %s', handle, devnumber, request_id, error,
_hidpp10.ERROR[error] _hidpp10.ERROR[error]
) )
@ -453,7 +451,7 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
if reply_data[:1] == b'\xFF' and reply_data[1:3] == request_data[:2]: if reply_data[:1] == b'\xFF' and reply_data[1:3] == request_data[:2]:
# a HID++ 2.0 feature call returned with an error # a HID++ 2.0 feature call returned with an error
error = ord(reply_data[3:4]) error = ord(reply_data[3:4])
_log.error( logger.error(
'(%s) device %d error on feature request {%04X}: %d = %s', handle, devnumber, request_id, error, '(%s) device %d error on feature request {%04X}: %d = %s', handle, devnumber, request_id, error,
_hidpp20.ERROR[error] _hidpp20.ERROR[error]
) )
@ -481,16 +479,16 @@ def request(handle, devnumber, request_id, *params, no_reply=False, return_error
n = make_notification(report_id, reply_devnumber, reply_data) n = make_notification(report_id, reply_devnumber, reply_data)
if n: if n:
notifications_hook(n) notifications_hook(n)
# elif _log.isEnabledFor(_DEBUG): # elif logger.isEnabledFor(logging.DEBUG):
# _log.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data)) # logger.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data))
# elif _log.isEnabledFor(_DEBUG): # elif logger.isEnabledFor(logging.DEBUG):
# _log.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data)) # logger.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data))
delta = _timestamp() - request_started delta = _timestamp() - request_started
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("(%s) still waiting for reply, delta %f", handle, delta) # logger.debug("(%s) still waiting for reply, delta %f", handle, delta)
_log.warn( logger.warning(
'timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]', delta, timeout, devnumber, request_id, 'timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]', delta, timeout, devnumber, request_id,
_strhex(params) _strhex(params)
) )
@ -501,14 +499,14 @@ def ping(handle, devnumber, long_message=False):
"""Check if a device is connected to the receiver. """Check if a device is connected to the receiver.
:returns: The HID protocol supported by the device, as a floating point number, if the device is active. :returns: The HID protocol supported by the device, as a floating point number, if the device is active.
""" """
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('(%s) pinging device %d', handle, devnumber) logger.debug('(%s) pinging device %d', handle, devnumber)
with acquire_timeout(handle_lock(handle), handle, 10.): with acquire_timeout(handle_lock(handle), handle, 10.):
notifications_hook = getattr(handle, 'notifications_hook', None) notifications_hook = getattr(handle, 'notifications_hook', None)
try: try:
_skip_incoming(handle, int(handle), notifications_hook) _skip_incoming(handle, int(handle), notifications_hook)
except NoReceiver: except NoReceiver:
_log.warn('device or receiver disconnected') logger.warning('device or receiver disconnected')
return return
# randomize the SoftwareId and mark byte to be able to identify the ping # randomize the SoftwareId and mark byte to be able to identify the ping
@ -537,16 +535,16 @@ def ping(handle, devnumber, long_message=False):
if error == _hidpp10.ERROR.resource_error or error == _hidpp10.ERROR.connection_request_failed: if error == _hidpp10.ERROR.resource_error or error == _hidpp10.ERROR.connection_request_failed:
return # device unreachable return # device unreachable
if error == _hidpp10.ERROR.unknown_device: # no paired device with that number if error == _hidpp10.ERROR.unknown_device: # no paired device with that number
_log.error('(%s) device %d error on ping request: unknown device', handle, devnumber) logger.error('(%s) device %d error on ping request: unknown device', handle, devnumber)
raise NoSuchDevice(number=devnumber, request=request_id) raise NoSuchDevice(number=devnumber, request=request_id)
if notifications_hook: if notifications_hook:
n = make_notification(report_id, reply_devnumber, reply_data) n = make_notification(report_id, reply_devnumber, reply_data)
if n: if n:
notifications_hook(n) notifications_hook(n)
# elif _log.isEnabledFor(_DEBUG): # elif logger.isEnabledFor(logging.DEBUG):
# _log.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data)) # logger.debug("(%s) ignoring reply %02X [%s]", handle, reply_devnumber, _strhex(reply_data))
delta = _timestamp() - request_started delta = _timestamp() - request_started
_log.warn('(%s) timeout (%0.2f/%0.2f) on device %d ping', handle, delta, _PING_TIMEOUT, devnumber) logger.warning('(%s) timeout (%0.2f/%0.2f) on device %d ping', handle, delta, _PING_TIMEOUT, devnumber)

View File

@ -17,10 +17,9 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import errno as _errno import errno as _errno
import logging
import threading as _threading import threading as _threading
from logging import INFO as _INFO
from logging import getLogger
from typing import Optional from typing import Optional
import hidapi as _hid import hidapi as _hid
@ -33,8 +32,7 @@ from . import hidpp20 as _hidpp20
from .common import strhex as _strhex from .common import strhex as _strhex
from .settings_templates import check_feature_settings as _check_feature_settings from .settings_templates import check_feature_settings as _check_feature_settings
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
_IR = _hidpp10.INFO_SUBREGISTERS _IR = _hidpp10.INFO_SUBREGISTERS
@ -129,7 +127,7 @@ class Device:
elif receiver.receiver_kind == '27Mhz': # 27 Mhz receiver doesn't have pairing registers elif receiver.receiver_kind == '27Mhz': # 27 Mhz receiver doesn't have pairing registers
self.wpid = _hid.find_paired_node_wpid(receiver.path, number) self.wpid = _hid.find_paired_node_wpid(receiver.path, number)
if not self.wpid: if not self.wpid:
_log.error('Unable to get wpid from udev for device %d of %s', number, receiver) logger.error('Unable to get wpid from udev for device %d of %s', number, receiver)
raise _base.NoSuchDevice(number=number, receiver=receiver, error='Not present 27Mhz device') raise _base.NoSuchDevice(number=number, receiver=receiver, error='Not present 27Mhz device')
kind = receiver.get_kind_from_index(number) kind = receiver.get_kind_from_index(number)
self._kind = _hidpp10.DEVICE_KIND[kind] self._kind = _hidpp10.DEVICE_KIND[kind]
@ -220,8 +218,8 @@ class Device:
ids = _hidpp20.get_ids(self) ids = _hidpp20.get_ids(self)
if ids: if ids:
self._unitId, self._modelId, self._tid_map = ids self._unitId, self._modelId, self._tid_map = ids
if _log.isEnabledFor(_INFO) and self._serial and self._serial != self._unitId: if logger.isEnabledFor(logging.INFO) and self._serial and self._serial != self._unitId:
_log.info('%s: unitId %s does not match serial %s', self, self._unitId, self._serial) logger.info('%s: unitId %s does not match serial %s', self, self._unitId, self._serial)
@property @property
def unitId(self): def unitId(self):
@ -426,12 +424,12 @@ class Device:
set_flag_bits = 0 set_flag_bits = 0
ok = _hidpp10.set_notification_flags(self, set_flag_bits) ok = _hidpp10.set_notification_flags(self, set_flag_bits)
if not ok: if not ok:
_log.warn('%s: failed to %s device notifications', self, 'enable' if enable else 'disable') logger.warning('%s: failed to %s device notifications', self, 'enable' if enable else 'disable')
flag_bits = _hidpp10.get_notification_flags(self) flag_bits = _hidpp10.get_notification_flags(self)
flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits))
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: device notifications %s %s', self, 'enabled' if enable else 'disabled', flag_names) logger.info('%s: device notifications %s %s', self, 'enabled' if enable else 'disabled', flag_names)
return flag_bits if ok else None return flag_bits if ok else None
def add_notification_handler(self, id: str, fn): def add_notification_handler(self, id: str, fn):
@ -451,8 +449,8 @@ class Device:
def remove_notification_handler(self, id: str): def remove_notification_handler(self, id: str):
"""Unregisters the notification handler under name `id`.""" """Unregisters the notification handler under name `id`."""
if id not in self._notification_handlers and _log.isEnabledFor(_INFO): if id not in self._notification_handlers and logger.isEnabledFor(logging.INFO):
_log.info(f'Tried to remove nonexistent notification handler {id} from device {self}.') logger.info(f'Tried to remove nonexistent notification handler {id} from device {self}.')
else: else:
del self._notification_handlers[id] del self._notification_handlers[id]
@ -544,11 +542,11 @@ class Device:
bus_id=device_info.bus_id bus_id=device_info.bus_id
) )
except OSError as e: except OSError as e:
_log.exception('open %s', device_info) logger.exception('open %s', device_info)
if e.errno == _errno.EACCES: if e.errno == _errno.EACCES:
raise raise
except Exception: except Exception:
_log.exception('open %s', device_info) logger.exception('open %s', device_info)
def close(self): def close(self):
handle, self.handle = self.handle, None handle, self.handle = self.handle, None

View File

@ -17,15 +17,13 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import ctypes as _ctypes import ctypes as _ctypes
import logging
import os as _os import os as _os
import os.path as _path import os.path as _path
import platform as _platform import platform as _platform
import sys as _sys import sys as _sys
import time as _time import time as _time
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import getLogger
from math import sqrt as _sqrt from math import sqrt as _sqrt
from struct import unpack as _unpack from struct import unpack as _unpack
@ -54,8 +52,7 @@ import gi # isort:skip
gi.require_version('Gdk', '3.0') # isort:skip gi.require_version('Gdk', '3.0') # isort:skip
from gi.repository import Gdk, GLib # NOQA: E402 # isort:skip from gi.repository import Gdk, GLib # NOQA: E402 # isort:skip
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# See docs/rules.md for documentation # See docs/rules.md for documentation
@ -99,12 +96,12 @@ CLICK, DEPRESS, RELEASE = 'click', 'depress', 'release'
gdisplay = Gdk.Display.get_default() # can be None if Solaar is run without a full window system gdisplay = Gdk.Display.get_default() # can be None if Solaar is run without a full window system
gkeymap = Gdk.Keymap.get_for_display(gdisplay) if gdisplay else None gkeymap = Gdk.Keymap.get_for_display(gdisplay) if gdisplay else None
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('GDK Keymap %sset up', '' if gkeymap else 'not ') logger.info('GDK Keymap %sset up', '' if gkeymap else 'not ')
wayland = _os.getenv('WAYLAND_DISPLAY') # is this Wayland? wayland = _os.getenv('WAYLAND_DISPLAY') # is this Wayland?
if wayland: if wayland:
_log.warn( logger.warning(
'rules cannot access modifier keys in Wayland, ' 'rules cannot access modifier keys in Wayland, '
'accessing process only works on GNOME with Solaar Gnome extension installed' 'accessing process only works on GNOME with Solaar Gnome extension installed'
) )
@ -149,10 +146,10 @@ def x11_setup():
NET_WM_PID = xdisplay.intern_atom('_NET_WM_PID') NET_WM_PID = xdisplay.intern_atom('_NET_WM_PID')
WM_CLASS = xdisplay.intern_atom('WM_CLASS') WM_CLASS = xdisplay.intern_atom('WM_CLASS')
_x11 = True # X11 available _x11 = True # X11 available
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('X11 library loaded and display set up') logger.info('X11 library loaded and display set up')
except Exception: except Exception:
_log.warn('X11 not available - some rule capabilities inoperable', exc_info=_sys.exc_info()) logger.warning('X11 not available - some rule capabilities inoperable', exc_info=_sys.exc_info())
_x11 = False _x11 = False
xtest_available = False xtest_available = False
return _x11 return _x11
@ -167,7 +164,7 @@ def gnome_dbus_interface_setup():
remote_object = bus.get_object('org.gnome.Shell', '/io/github/pwr_solaar/solaar') remote_object = bus.get_object('org.gnome.Shell', '/io/github/pwr_solaar/solaar')
_dbus_interface = dbus.Interface(remote_object, 'io.github.pwr_solaar.solaar') _dbus_interface = dbus.Interface(remote_object, 'io.github.pwr_solaar.solaar')
except dbus.exceptions.DBusException: except dbus.exceptions.DBusException:
_log.warn('Solaar Gnome extension not installed - some rule capabilities inoperable', exc_info=_sys.exc_info()) logger.warning('Solaar Gnome extension not installed - some rule capabilities inoperable', exc_info=_sys.exc_info())
_dbus_interface = False _dbus_interface = False
return _dbus_interface return _dbus_interface
@ -181,10 +178,10 @@ def xkb_setup():
X11Lib.XOpenDisplay.restype = _ctypes.POINTER(XkbDisplay) X11Lib.XOpenDisplay.restype = _ctypes.POINTER(XkbDisplay)
X11Lib.XkbGetState.argtypes = [_ctypes.POINTER(XkbDisplay), _ctypes.c_uint, _ctypes.POINTER(XkbStateRec)] X11Lib.XkbGetState.argtypes = [_ctypes.POINTER(XkbDisplay), _ctypes.c_uint, _ctypes.POINTER(XkbStateRec)]
Xkbdisplay = X11Lib.XOpenDisplay(None) Xkbdisplay = X11Lib.XOpenDisplay(None)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('XKB display set up') logger.info('XKB display set up')
except Exception: except Exception:
_log.warn('XKB display not available - rules cannot access keyboard group', exc_info=_sys.exc_info()) logger.warning('XKB display not available - rules cannot access keyboard group', exc_info=_sys.exc_info())
Xkbdisplay = False Xkbdisplay = False
return Xkbdisplay return Xkbdisplay
@ -224,11 +221,11 @@ def setup_uinput():
return udevice return udevice
try: try:
udevice = evdev.uinput.UInput(events=devicecap, name='solaar-keyboard') udevice = evdev.uinput.UInput(events=devicecap, name='solaar-keyboard')
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('uinput device set up') logger.info('uinput device set up')
return True return True
except Exception as e: except Exception as e:
_log.warn('cannot create uinput device: %s', e) logger.warning('cannot create uinput device: %s', e)
if wayland: # Wayland can't use xtest so may as well set up uinput now if wayland: # Wayland can't use xtest so may as well set up uinput now
@ -297,12 +294,12 @@ def simulate_xtest(code, event):
) )
Xlib.ext.xtest.fake_input(xdisplay, event, code) Xlib.ext.xtest.fake_input(xdisplay, event, code)
xdisplay.sync() xdisplay.sync()
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('xtest simulated input %s %s %s', xdisplay, event, code) logger.debug('xtest simulated input %s %s %s', xdisplay, event, code)
return True return True
except Exception as e: except Exception as e:
xtest_available = False xtest_available = False
_log.warn('xtest fake input failed: %s', e) logger.warning('xtest fake input failed: %s', e)
def simulate_uinput(what, code, arg): def simulate_uinput(what, code, arg):
@ -311,12 +308,12 @@ def simulate_uinput(what, code, arg):
try: try:
udevice.write(what, code, arg) udevice.write(what, code, arg)
udevice.syn() udevice.syn()
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('uinput simulated input %s %s %s', what, code, arg) logger.debug('uinput simulated input %s %s %s', what, code, arg)
return True return True
except Exception as e: except Exception as e:
udevice = None udevice = None
_log.warn('uinput write failed: %s', e) logger.warning('uinput write failed: %s', e)
def simulate_key(code, event): # X11 keycode but Solaar event code def simulate_key(code, event): # X11 keycode but Solaar event code
@ -324,7 +321,7 @@ def simulate_key(code, event): # X11 keycode but Solaar event code
return True return True
if simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event): if simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event):
return True return True
_log.warn('no way to simulate key input') logger.warning('no way to simulate key input')
def click_xtest(button, count): def click_xtest(button, count):
@ -366,7 +363,7 @@ def click(button, count):
return True return True
if click_uinput(button, count): if click_uinput(button, count):
return True return True
_log.warn('no way to simulate mouse click') logger.warning('no way to simulate mouse click')
return False return False
@ -387,7 +384,7 @@ def simulate_scroll(dx, dy):
success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_WHEEL, dy) success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_WHEEL, dy)
if success: if success:
return True return True
_log.warn('no way to simulate scrolling') logger.warning('no way to simulate scrolling')
def thumb_wheel_up(f, r, d, a): def thumb_wheel_up(f, r, d, a):
@ -465,7 +462,7 @@ class RuleComponent:
k, v = next(iter(c.items())) k, v = next(iter(c.items()))
if k in COMPONENTS: if k in COMPONENTS:
return COMPONENTS[k](v) return COMPONENTS[k](v)
_log.warn('illegal component in rule: %s', c) logger.warning('illegal component in rule: %s', c)
return Condition() return Condition()
@ -480,8 +477,8 @@ class Rule(RuleComponent):
return 'Rule%s[%s]' % (source, ', '.join([c.__str__() for c in self.components])) return 'Rule%s[%s]' % (source, ', '.join([c.__str__() for c in self.components]))
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate rule: %s', self) logger.debug('evaluate rule: %s', self)
result = True result = True
for component in self.components: for component in self.components:
result = component.evaluate(feature, notification, device, status, result) result = component.evaluate(feature, notification, device, status, result)
@ -508,8 +505,8 @@ class Condition(RuleComponent):
return 'CONDITION' return 'CONDITION'
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return False return False
@ -525,8 +522,8 @@ class Not(Condition):
return 'Not: ' + str(self.component) return 'Not: ' + str(self.component)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
result = self.component.evaluate(feature, notification, device, status, last_result) result = self.component.evaluate(feature, notification, device, status, last_result)
return None if result is None else not result return None if result is None else not result
@ -543,8 +540,8 @@ class Or(Condition):
return 'Or: [' + ', '.join(str(c) for c in self.components) + ']' return 'Or: [' + ', '.join(str(c) for c in self.components) + ']'
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
result = False result = False
for component in self.components: for component in self.components:
result = component.evaluate(feature, notification, device, status, last_result) result = component.evaluate(feature, notification, device, status, last_result)
@ -567,8 +564,8 @@ class And(Condition):
return 'And: [' + ', '.join(str(c) for c in self.components) + ']' return 'And: [' + ', '.join(str(c) for c in self.components) + ']'
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
result = True result = True
for component in self.components: for component in self.components:
result = component.evaluate(feature, notification, device, status, last_result) result = component.evaluate(feature, notification, device, status, last_result)
@ -634,21 +631,21 @@ class Process(Condition):
self.process = process self.process = process
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
if warn: if warn:
_log.warn( logger.warning(
'rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome extension - %s', 'rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome extension - %s',
self self
) )
if not isinstance(process, str): if not isinstance(process, str):
if warn: if warn:
_log.warn('rule Process argument not a string: %s', process) logger.warning('rule Process argument not a string: %s', process)
self.process = str(process) self.process = str(process)
def __str__(self): def __str__(self):
return 'Process: ' + str(self.process) return 'Process: ' + str(self.process)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
if not isinstance(self.process, str): if not isinstance(self.process, str):
return False return False
focus = x11_focus_prog() if not wayland else gnome_dbus_focus_prog() focus = x11_focus_prog() if not wayland else gnome_dbus_focus_prog()
@ -665,21 +662,21 @@ class MouseProcess(Condition):
self.process = process self.process = process
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
if warn: if warn:
_log.warn( logger.warning(
'rules cannot access active mouse process ' 'rules cannot access active mouse process '
'in X11 or in Wayland under GNOME with Solaar Extension for GNOME - %s', self 'in X11 or in Wayland under GNOME with Solaar Extension for GNOME - %s', self
) )
if not isinstance(process, str): if not isinstance(process, str):
if warn: if warn:
_log.warn('rule MouseProcess argument not a string: %s', process) logger.warning('rule MouseProcess argument not a string: %s', process)
self.process = str(process) self.process = str(process)
def __str__(self): def __str__(self):
return 'MouseProcess: ' + str(self.process) return 'MouseProcess: ' + str(self.process)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
if not isinstance(self.process, str): if not isinstance(self.process, str):
return False return False
pointer_focus = x11_pointer_prog() if not wayland else gnome_dbus_pointer_prog() pointer_focus = x11_pointer_prog() if not wayland else gnome_dbus_pointer_prog()
@ -695,7 +692,7 @@ class Feature(Condition):
def __init__(self, feature, warn=True): def __init__(self, feature, warn=True):
if not (isinstance(feature, str) and feature in _F): if not (isinstance(feature, str) and feature in _F):
if warn: if warn:
_log.warn('rule Feature argument not name of a feature: %s', feature) logger.warning('rule Feature argument not name of a feature: %s', feature)
self.feature = None self.feature = None
self.feature = _F[feature] self.feature = _F[feature]
@ -703,8 +700,8 @@ class Feature(Condition):
return 'Feature: ' + str(self.feature) return 'Feature: ' + str(self.feature)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return feature == self.feature return feature == self.feature
def data(self): def data(self):
@ -716,7 +713,7 @@ class Report(Condition):
def __init__(self, report, warn=True): def __init__(self, report, warn=True):
if not (isinstance(report, int)): if not (isinstance(report, int)):
if warn: if warn:
_log.warn('rule Report argument not an integer: %s', report) logger.warning('rule Report argument not an integer: %s', report)
self.report = -1 self.report = -1
else: else:
self.report = report self.report = report
@ -725,8 +722,8 @@ class Report(Condition):
return 'Report: ' + str(self.report) return 'Report: ' + str(self.report)
def evaluate(self, report, notification, device, status, last_result): def evaluate(self, report, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return (notification.address >> 4) == self.report return (notification.address >> 4) == self.report
def data(self): def data(self):
@ -739,7 +736,7 @@ class Setting(Condition):
def __init__(self, args, warn=True): def __init__(self, args, warn=True):
if not (isinstance(args, list) and len(args) > 2): if not (isinstance(args, list) and len(args) > 2):
if warn: if warn:
_log.warn('rule Setting argument not list with minimum length 3: %s', args) logger.warning('rule Setting argument not list with minimum length 3: %s', args)
self.args = [] self.args = []
else: else:
self.args = args self.args = args
@ -748,24 +745,24 @@ class Setting(Condition):
return 'Setting: ' + ' '.join([str(a) for a in self.args]) return 'Setting: ' + ' '.join([str(a) for a in self.args])
def evaluate(self, report, notification, device, status, last_result): def evaluate(self, report, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
if len(self.args) < 3: if len(self.args) < 3:
return None return None
dev = _Device.find(self.args[0]) if self.args[0] is not None else device dev = _Device.find(self.args[0]) if self.args[0] is not None else device
if dev is None: if dev is None:
_log.warn('Setting condition: device %s is not known', self.args[0]) logger.warning('Setting condition: device %s is not known', self.args[0])
return False return False
setting = next((s for s in dev.settings if s.name == self.args[1]), None) setting = next((s for s in dev.settings if s.name == self.args[1]), None)
if setting is None: if setting is None:
_log.warn('Setting condition: setting %s is not the name of a setting for %s', self.args[1], dev.name) logger.warning('Setting condition: setting %s is not the name of a setting for %s', self.args[1], dev.name)
return None return None
# should the value argument be checked to be sure it is acceptable?? needs to be careful about boolean toggle # should the value argument be checked to be sure it is acceptable?? needs to be careful about boolean toggle
# TODO add compare methods for more validators # TODO add compare methods for more validators
try: try:
result = setting.compare(self.args[2:], setting.read()) result = setting.compare(self.args[2:], setting.read())
except Exception as e: except Exception as e:
_log.warn('Setting condition: error when checking setting %s: %s', self.args, e) logger.warning('Setting condition: error when checking setting %s: %s', self.args, e)
result = False result = False
return result return result
@ -794,19 +791,19 @@ class Modifiers(Condition):
self.modifiers.append(k) self.modifiers.append(k)
else: else:
if warn: if warn:
_log.warn('unknown rule Modifier value: %s', k) logger.warning('unknown rule Modifier value: %s', k)
def __str__(self): def __str__(self):
return 'Modifiers: ' + str(self.desired) return 'Modifiers: ' + str(self.desired)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
if gkeymap: if gkeymap:
current = gkeymap.get_modifier_state() # get the current keyboard modifier current = gkeymap.get_modifier_state() # get the current keyboard modifier
return self.desired == (current & MODIFIER_MASK) return self.desired == (current & MODIFIER_MASK)
else: else:
_log.warn('no keymap so cannot determine modifier keys') logger.warning('no keymap so cannot determine modifier keys')
return False return False
def data(self): def data(self):
@ -825,16 +822,16 @@ class Key(Condition):
if not args or not isinstance(args, (list, str)): if not args or not isinstance(args, (list, str)):
if warn: if warn:
_log.warn('rule Key arguments unknown: %s' % args) logger.warning('rule Key arguments unknown: %s' % args)
key = default_key key = default_key
action = default_action action = default_action
elif isinstance(args, str): elif isinstance(args, str):
_log.debug('rule Key assuming action "%s" for "%s"' % (default_action, args)) logger.debug('rule Key assuming action "%s" for "%s"' % (default_action, args))
key = args key = args
action = default_action action = default_action
elif isinstance(args, list): elif isinstance(args, list):
if len(args) == 1: if len(args) == 1:
_log.debug('rule Key assuming action "%s" for "%s"' % (default_action, args)) logger.debug('rule Key assuming action "%s" for "%s"' % (default_action, args))
key, action = args[0], default_action key, action = args[0], default_action
elif len(args) >= 2: elif len(args) >= 2:
key, action = args[:2] key, action = args[:2]
@ -843,22 +840,22 @@ class Key(Condition):
self.key = _CONTROL[key] self.key = _CONTROL[key]
else: else:
if warn: if warn:
_log.warn('rule Key key name not name of a Logitech key: %s' % key) logger.warning('rule Key key name not name of a Logitech key: %s' % key)
self.key = default_key self.key = default_key
if isinstance(action, str) and action in (self.DOWN, self.UP): if isinstance(action, str) and action in (self.DOWN, self.UP):
self.action = action self.action = action
else: else:
if warn: if warn:
_log.warn('rule Key action unknown: %s, assuming %s' % (action, default_action)) logger.warning('rule Key action unknown: %s, assuming %s' % (action, default_action))
self.action = default_action self.action = default_action
def __str__(self): def __str__(self):
return 'Key: %s (%s)' % ((str(self.key) if self.key else 'None'), self.action) return 'Key: %s (%s)' % ((str(self.key) if self.key else 'None'), self.action)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return bool(self.key and self.key == (key_down if self.action == self.DOWN else key_up)) return bool(self.key and self.key == (key_down if self.action == self.DOWN else key_up))
def data(self): def data(self):
@ -874,7 +871,7 @@ class KeyIsDown(Condition):
if not args or not isinstance(args, str): if not args or not isinstance(args, str):
if warn: if warn:
_log.warn('rule KeyDown arguments unknown: %s' % args) logger.warning('rule KeyDown arguments unknown: %s' % args)
key = default_key key = default_key
elif isinstance(args, str): elif isinstance(args, str):
key = args key = args
@ -883,15 +880,15 @@ class KeyIsDown(Condition):
self.key = _CONTROL[key] self.key = _CONTROL[key]
else: else:
if warn: if warn:
_log.warn('rule Key key name not name of a Logitech key: %s' % key) logger.warning('rule Key key name not name of a Logitech key: %s' % key)
self.key = default_key self.key = default_key
def __str__(self): def __str__(self):
return 'KeyIsDown: %s' % (str(self.key) if self.key else 'None') return 'KeyIsDown: %s' % (str(self.key) if self.key else 'None')
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return key_is_down(self.key) return key_is_down(self.key)
def data(self): def data(self):
@ -920,13 +917,13 @@ class Test(Condition):
test = [test] test = [test]
if isinstance(test, list) and all(isinstance(t, int) for t in test): if isinstance(test, list) and all(isinstance(t, int) for t in test):
if warn: if warn:
_log.warn('Test rules consisting of numbers are deprecated, converting to a TestBytes condition') logger.warning('Test rules consisting of numbers are deprecated, converting to a TestBytes condition')
self.__class__ = TestBytes self.__class__ = TestBytes
self.__init__(test, warn=warn) self.__init__(test, warn=warn)
elif isinstance(test, list): elif isinstance(test, list):
if test[0] in MOUSE_GESTURE_TESTS: if test[0] in MOUSE_GESTURE_TESTS:
if warn: if warn:
_log.warn('mouse movement test %s deprecated, converting to a MouseGesture', test) logger.warning('mouse movement test %s deprecated, converting to a MouseGesture', test)
self.__class__ = MouseGesture self.__class__ = MouseGesture
self.__init__(MOUSE_GESTURE_TESTS[0][test], warn=warn) self.__init__(MOUSE_GESTURE_TESTS[0][test], warn=warn)
elif test[0] in TESTS: elif test[0] in TESTS:
@ -935,19 +932,19 @@ class Test(Condition):
self.parameter = test[1] if len(test) > 1 else None self.parameter = test[1] if len(test) > 1 else None
else: else:
if warn: if warn:
_log.warn('rule Test name not name of a test: %s', test) logger.warning('rule Test name not name of a test: %s', test)
self.test = 'False' self.test = 'False'
self.function = TESTS['False'][0] self.function = TESTS['False'][0]
else: else:
if warn: if warn:
_log.warn('rule Test argument not valid %s', test) logger.warning('rule Test argument not valid %s', test)
def __str__(self): def __str__(self):
return 'Test: ' + str(self.test) return 'Test: ' + str(self.test)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return self.function(feature, notification.address, notification.data, self.parameter) return self.function(feature, notification.address, notification.data, self.parameter)
def data(self): def data(self):
@ -965,14 +962,14 @@ class TestBytes(Condition):
self.function = bit_test(*test) if len(test) == 3 else range_test(*test) self.function = bit_test(*test) if len(test) == 3 else range_test(*test)
else: else:
if warn: if warn:
_log.warn('rule TestBytes argument not valid %s', test) logger.warning('rule TestBytes argument not valid %s', test)
def __str__(self): def __str__(self):
return 'TestBytes: ' + str(self.test) return 'TestBytes: ' + str(self.test)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return self.function(feature, notification.address, notification.data) return self.function(feature, notification.address, notification.data)
def data(self): def data(self):
@ -991,15 +988,15 @@ class MouseGesture(Condition):
for x in movements: for x in movements:
if x not in self.MOVEMENTS and x not in _CONTROL: if x not in self.MOVEMENTS and x not in _CONTROL:
if warn: if warn:
_log.warn('rule Mouse Gesture argument not direction or name of a Logitech key: %s', x) logger.warning('rule Mouse Gesture argument not direction or name of a Logitech key: %s', x)
self.movements = movements self.movements = movements
def __str__(self): def __str__(self):
return 'MouseGesture: ' + ' '.join(self.movements) return 'MouseGesture: ' + ' '.join(self.movements)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
if feature == _F.MOUSE_GESTURE: if feature == _F.MOUSE_GESTURE:
d = notification.data d = notification.data
data = _unpack('!' + (int(len(d) / 2) * 'h'), d) data = _unpack('!' + (int(len(d) / 2) * 'h'), d)
@ -1033,7 +1030,7 @@ class Active(Condition):
def __init__(self, devID, warn=True): def __init__(self, devID, warn=True):
if not (isinstance(devID, str)): if not (isinstance(devID, str)):
if warn: if warn:
_log.warn('rule Active argument not a string: %s', devID) logger.warning('rule Active argument not a string: %s', devID)
self.devID = '' self.devID = ''
self.devID = devID self.devID = devID
@ -1041,8 +1038,8 @@ class Active(Condition):
return 'Active: ' + str(self.devID) return 'Active: ' + str(self.devID)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
dev = _Device.find(self.devID) dev = _Device.find(self.devID)
return bool(dev and dev.ping()) return bool(dev and dev.ping())
@ -1055,7 +1052,7 @@ class Device(Condition):
def __init__(self, devID, warn=True): def __init__(self, devID, warn=True):
if not (isinstance(devID, str)): if not (isinstance(devID, str)):
if warn: if warn:
_log.warn('rule Device argument not a string: %s', devID) logger.warning('rule Device argument not a string: %s', devID)
self.devID = '' self.devID = ''
self.devID = devID self.devID = devID
@ -1063,8 +1060,8 @@ class Device(Condition):
return 'Device: ' + str(self.devID) return 'Device: ' + str(self.devID)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
return device.unitId == self.devID or device.serial == self.devID return device.unitId == self.devID or device.serial == self.devID
def data(self): def data(self):
@ -1076,7 +1073,7 @@ class Host(Condition):
def __init__(self, host, warn=True): def __init__(self, host, warn=True):
if not (isinstance(host, str)): if not (isinstance(host, str)):
if warn: if warn:
_log.warn('rule Host Name argument not a string: %s', host) logger.warning('rule Host Name argument not a string: %s', host)
self.host = '' self.host = ''
self.host = host self.host = host
@ -1084,8 +1081,8 @@ class Host(Condition):
return 'Host: ' + str(self.host) return 'Host: ' + str(self.host)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluate condition: %s', self) logger.debug('evaluate condition: %s', self)
import socket import socket
hostname = socket.getfqdn() hostname = socket.getfqdn()
return hostname.startswith(self.host) return hostname.startswith(self.host)
@ -1109,13 +1106,13 @@ class KeyPress(Action):
self.key_names, self.action = self.regularize_args(args) self.key_names, self.action = self.regularize_args(args)
if not isinstance(self.key_names, list): if not isinstance(self.key_names, list):
if warn: if warn:
_log.warn('rule KeyPress keys not key names %s', self.keys_names) logger.warning('rule KeyPress keys not key names %s', self.keys_names)
self.key_symbols = [] self.key_symbols = []
else: else:
self.key_symbols = [XK_KEYS.get(k, None) for k in self.key_names] self.key_symbols = [XK_KEYS.get(k, None) for k in self.key_names]
if not all(self.key_symbols): if not all(self.key_symbols):
if warn: if warn:
_log.warn('rule KeyPress keys not key names %s', self.key_names) logger.warning('rule KeyPress keys not key names %s', self.key_names)
self.key_symbols = [] self.key_symbols = []
def regularize_args(self, args): def regularize_args(self, args):
@ -1168,7 +1165,7 @@ class KeyPress(Action):
for k in keysyms: for k in keysyms:
(keycode, level) = self.keysym_to_keycode(k, modifiers) (keycode, level) = self.keysym_to_keycode(k, modifiers)
if keycode is None: if keycode is None:
_log.warn('rule KeyPress key symbol not currently available %s', self) logger.warning('rule KeyPress key symbol not currently available %s', self)
elif self.action != CLICK or self.needed(keycode, modifiers): # only check needed when clicking elif self.action != CLICK or self.needed(keycode, modifiers): # only check needed when clicking
self.mods(level, modifiers, _KEY_PRESS) self.mods(level, modifiers, _KEY_PRESS)
simulate_key(keycode, _KEY_PRESS) simulate_key(keycode, _KEY_PRESS)
@ -1183,15 +1180,15 @@ class KeyPress(Action):
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if gkeymap: if gkeymap:
current = gkeymap.get_modifier_state() current = gkeymap.get_modifier_state()
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('KeyPress action: %s %s, group %s, modifiers %s', self.key_names, self.action, kbdgroup(), current) logger.info('KeyPress action: %s %s, group %s, modifiers %s', self.key_names, self.action, kbdgroup(), current)
if self.action != RELEASE: if self.action != RELEASE:
self.keyDown(self.key_symbols, current) self.keyDown(self.key_symbols, current)
if self.action != DEPRESS: if self.action != DEPRESS:
self.keyUp(reversed(self.key_symbols), current) self.keyUp(reversed(self.key_symbols), current)
_time.sleep(0.01) _time.sleep(0.01)
else: else:
_log.warn('no keymap so cannot determine which keycode to send') logger.warning('no keymap so cannot determine which keycode to send')
return None return None
def data(self): def data(self):
@ -1215,7 +1212,7 @@ class MouseScroll(Action):
amounts = amounts[0] amounts = amounts[0]
if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])): if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])):
if warn: if warn:
_log.warn('rule MouseScroll argument not two numbers %s', amounts) logger.warning('rule MouseScroll argument not two numbers %s', amounts)
amounts = [0, 0] amounts = [0, 0]
self.amounts = amounts self.amounts = amounts
@ -1228,8 +1225,8 @@ class MouseScroll(Action):
amounts = self.amounts amounts = self.amounts
if isinstance(last_result, numbers.Number): if isinstance(last_result, numbers.Number):
amounts = [math.floor(last_result * a) for a in self.amounts] amounts = [math.floor(last_result * a) for a in self.amounts]
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('MouseScroll action: %s %s %s', self.amounts, last_result, amounts) logger.info('MouseScroll action: %s %s %s', self.amounts, last_result, amounts)
dx, dy = amounts dx, dy = amounts
simulate_scroll(dx, dy) simulate_scroll(dx, dy)
_time.sleep(0.01) _time.sleep(0.01)
@ -1249,7 +1246,7 @@ class MouseClick(Action):
self.button = str(args[0]) if len(args) >= 0 else None self.button = str(args[0]) if len(args) >= 0 else None
if self.button not in buttons: if self.button not in buttons:
if warn: if warn:
_log.warn('rule MouseClick action: button %s not known', self.button) logger.warning('rule MouseClick action: button %s not known', self.button)
self.button = None self.button = None
count = args[1] if len(args) >= 2 else 1 count = args[1] if len(args) >= 2 else 1
try: try:
@ -1258,15 +1255,15 @@ class MouseClick(Action):
if count in [CLICK, DEPRESS, RELEASE]: if count in [CLICK, DEPRESS, RELEASE]:
self.count = count self.count = count
elif warn: elif warn:
_log.warn('rule MouseClick action: argument %s should be an integer or CLICK, PRESS, or RELEASE', count) logger.warning('rule MouseClick action: argument %s should be an integer or CLICK, PRESS, or RELEASE', count)
self.count = 1 self.count = 1
def __str__(self): def __str__(self):
return 'MouseClick: %s (%d)' % (self.button, self.count) return 'MouseClick: %s (%d)' % (self.button, self.count)
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('MouseClick action: %d %s' % (self.count, self.button)) logger.info('MouseClick action: %d %s' % (self.count, self.button))
if self.button and self.count: if self.button and self.count:
click(buttons[self.button], self.count) click(buttons[self.button], self.count)
_time.sleep(0.01) _time.sleep(0.01)
@ -1281,7 +1278,7 @@ class Set(Action):
def __init__(self, args, warn=True): def __init__(self, args, warn=True):
if not (isinstance(args, list) and len(args) > 2): if not (isinstance(args, list) and len(args) > 2):
if warn: if warn:
_log.warn('rule Set argument not list with minimum length 3: %s', args) logger.warning('rule Set argument not list with minimum length 3: %s', args)
self.args = [] self.args = []
else: else:
self.args = args self.args = args
@ -1295,19 +1292,19 @@ class Set(Action):
if len(self.args) < 3: if len(self.args) < 3:
return None return None
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('Set action: %s', self.args) logger.info('Set action: %s', self.args)
dev = _Device.find(self.args[0]) if self.args[0] is not None else device dev = _Device.find(self.args[0]) if self.args[0] is not None else device
if dev is None: if dev is None:
_log.warn('Set action: device %s is not known', self.args[0]) logger.warning('Set action: device %s is not known', self.args[0])
return None return None
setting = next((s for s in dev.settings if s.name == self.args[1]), None) setting = next((s for s in dev.settings if s.name == self.args[1]), None)
if setting is None: if setting is None:
_log.warn('Set action: setting %s is not the name of a setting for %s', self.args[1], dev.name) logger.warning('Set action: setting %s is not the name of a setting for %s', self.args[1], dev.name)
return None return None
args = setting.acceptable(self.args[2:], setting.read()) args = setting.acceptable(self.args[2:], setting.read())
if args is None: if args is None:
_log.warn('Set Action: invalid args %s for setting %s of %s', self.args[2:], self.args[1], self.args[0]) logger.warning('Set Action: invalid args %s for setting %s of %s', self.args[2:], self.args[1], self.args[0])
return None return None
_change_setting(dev, setting, args) _change_setting(dev, setting, args)
return None return None
@ -1323,7 +1320,7 @@ class Execute(Action):
args = [args] args = [args]
if not (isinstance(args, list) and all(isinstance(arg), str) for arg in args): if not (isinstance(args, list) and all(isinstance(arg), str) for arg in args):
if warn: if warn:
_log.warn('rule Execute argument not list of strings: %s', args) logger.warning('rule Execute argument not list of strings: %s', args)
self.args = [] self.args = []
else: else:
self.args = args self.args = args
@ -1333,8 +1330,8 @@ class Execute(Action):
def evaluate(self, feature, notification, device, status, last_result): def evaluate(self, feature, notification, device, status, last_result):
import subprocess import subprocess
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('Execute action: %s', self.args) logger.info('Execute action: %s', self.args)
subprocess.Popen(self.args) subprocess.Popen(self.args)
return None return None
@ -1352,10 +1349,10 @@ class Later(Action):
args = [args] args = [args]
if not (isinstance(args, list) and len(args) >= 1): if not (isinstance(args, list) and len(args) >= 1):
if warn: if warn:
_log.warn('rule Later argument not list with minimum length 1: %s', args) logger.warning('rule Later argument not list with minimum length 1: %s', args)
elif not (isinstance(args[0], int)) or not 0 < args[0] < 101: elif not (isinstance(args[0], int)) or not 0 < args[0] < 101:
if warn: if warn:
_log.warn('rule Later argument delay not integer between 1 and 100: %s', args) logger.warning('rule Later argument delay not integer between 1 and 100: %s', args)
else: else:
self.delay = args[0] self.delay = args[0]
self.rule = Rule(args[1:], warn=warn) self.rule = Rule(args[1:], warn=warn)
@ -1446,8 +1443,8 @@ def key_is_down(key):
def evaluate_rules(feature, notification, device, status): def evaluate_rules(feature, notification, device, status):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('evaluating rules on %s', notification) logger.debug('evaluating rules on %s', notification)
rules.evaluate(feature, notification, device, status, True) rules.evaluate(feature, notification, device, status, True)
@ -1541,15 +1538,15 @@ def _save_config_rule_file(file_name=_file_path):
# Save only user-defined rules # Save only user-defined rules
rules_to_save = sum((r.data()['Rule'] for r in rules.components if r.source == file_name), []) rules_to_save = sum((r.data()['Rule'] for r in rules.components if r.source == file_name), [])
if True: # save even if there are no rules to save if True: # save even if there are no rules to save
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('saving %d rule(s) to %s', len(rules_to_save), file_name) logger.info('saving %d rule(s) to %s', len(rules_to_save), file_name)
try: try:
with open(file_name, 'w') as f: with open(file_name, 'w') as f:
if rules_to_save: if rules_to_save:
f.write('%YAML 1.3\n') # Write version manually f.write('%YAML 1.3\n') # Write version manually
_yaml_dump_all(convert([r['Rule'] for r in rules_to_save]), f, **dump_settings) _yaml_dump_all(convert([r['Rule'] for r in rules_to_save]), f, **dump_settings)
except Exception as e: except Exception as e:
_log.error('failed to save to %s\n%s', file_name, e) logger.error('failed to save to %s\n%s', file_name, e)
return False return False
return True return True
@ -1563,13 +1560,13 @@ def _load_config_rule_file():
loaded_rules = [] loaded_rules = []
for loaded_rule in _yaml_safe_load_all(config_file): for loaded_rule in _yaml_safe_load_all(config_file):
rule = Rule(loaded_rule, source=_file_path) rule = Rule(loaded_rule, source=_file_path)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('load rule: %s', rule) logger.debug('load rule: %s', rule)
loaded_rules.append(rule) loaded_rules.append(rule)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('loaded %d rules from %s', len(loaded_rules), config_file.name) logger.info('loaded %d rules from %s', len(loaded_rules), config_file.name)
except Exception as e: except Exception as e:
_log.error('failed to load from %s\n%s', _file_path, e) logger.error('failed to load from %s\n%s', _file_path, e)
rules = Rule([Rule(loaded_rules, source=_file_path), built_in_rules]) rules = Rule([Rule(loaded_rules, source=_file_path), built_in_rules])

View File

@ -16,7 +16,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import getLogger # , DEBUG as _DEBUG import logging
from .common import BATTERY_APPROX as _BATTERY_APPROX from .common import BATTERY_APPROX as _BATTERY_APPROX
from .common import FirmwareInfo as _FirmwareInfo from .common import FirmwareInfo as _FirmwareInfo
@ -26,8 +26,7 @@ from .common import int2bytes as _int2bytes
from .common import strhex as _strhex from .common import strhex as _strhex
from .hidpp20 import BATTERY_STATUS, FIRMWARE_KIND from .hidpp20 import BATTERY_STATUS, FIRMWARE_KIND
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# Constants - most of them as defined by the official Logitech HID++ 1.0 # Constants - most of them as defined by the official Logitech HID++ 1.0
@ -258,7 +257,7 @@ def parse_battery_status(register, reply):
elif charging_byte & 0x22 == 0x22: elif charging_byte & 0x22 == 0x22:
status_text = BATTERY_STATUS.full status_text = BATTERY_STATUS.full
else: else:
_log.warn('could not parse 0x07 battery status: %02X (level %02X)', charging_byte, status_byte) logger.warning('could not parse 0x07 battery status: %02X (level %02X)', charging_byte, status_byte)
status_text = None status_text = None
if charging_byte & 0x03 and status_byte == 0: if charging_byte & 0x03 and status_byte == 0:

View File

@ -18,13 +18,9 @@
# Logitech Unifying Receiver API. # Logitech Unifying Receiver API.
import logging
import threading as _threading import threading as _threading
from logging import DEBUG as _DEBUG
from logging import ERROR as _ERROR
from logging import INFO as _INFO
from logging import WARNING as _WARNING
from logging import getLogger
from struct import pack as _pack from struct import pack as _pack
from struct import unpack as _unpack from struct import unpack as _unpack
from typing import List from typing import List
@ -43,8 +39,7 @@ from .common import crc16 as _crc16
from .common import int2bytes as _int2bytes from .common import int2bytes as _int2bytes
from .i18n import _ from .i18n import _
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
def hexint_presenter(dumper, data): def hexint_presenter(dumper, data):
@ -271,7 +266,7 @@ class FeaturesArray(dict):
if fs_index: if fs_index:
count = self.device.request(fs_index << 8) count = self.device.request(fs_index << 8)
if count is None: if count is None:
_log.warn('FEATURE_SET found, but failed to read features count') logger.warn('FEATURE_SET found, but failed to read features count')
return False return False
else: else:
self.count = ord(count[:1]) + 1 # ROOT feature not included in count self.count = ord(count[:1]) + 1 # ROOT feature not included in count
@ -455,8 +450,8 @@ class ReprogrammableKeyV4(ReprogrammableKey):
mapped_data = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x20, *tuple(_pack('!H', self._cid))) mapped_data = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x20, *tuple(_pack('!H', self._cid)))
if mapped_data: if mapped_data:
cid, mapping_flags_1, mapped_to = _unpack('!HBH', mapped_data[:5]) cid, mapping_flags_1, mapped_to = _unpack('!HBH', mapped_data[:5])
if cid != self._cid and _log.isEnabledFor(_WARNING): if cid != self._cid and logger.isEnabledFor(logging.WARNING):
_log.warn( logger.warn(
f'REPROG_CONTROLS_V4 endpoint getCidReporting on device {self._device} replied ' + f'REPROG_CONTROLS_V4 endpoint getCidReporting on device {self._device} replied ' +
f'with a different control ID ({cid}) than requested ({self._cid}).' f'with a different control ID ({cid}) than requested ({self._cid}).'
) )
@ -469,8 +464,8 @@ class ReprogrammableKeyV4(ReprogrammableKey):
else: else:
raise FeatureCallError(msg='No reply from device.') raise FeatureCallError(msg='No reply from device.')
except FeatureCallError: # if the key hasn't ever been configured then the read may fail so only produce a warning except FeatureCallError: # if the key hasn't ever been configured then the read may fail so only produce a warning
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn( logger.warn(
f'Feature Call Error in _getCidReporting on device {self._device} for cid {self._cid} - use defaults' f'Feature Call Error in _getCidReporting on device {self._device} for cid {self._cid} - use defaults'
) )
# Clear flags and set mapping target to self # Clear flags and set mapping target to self
@ -527,8 +522,8 @@ class ReprogrammableKeyV4(ReprogrammableKey):
# TODO: to fully support version 4 of REPROG_CONTROLS_V4, append `(bfield >> 8) & 0xff` here. # TODO: to fully support version 4 of REPROG_CONTROLS_V4, append `(bfield >> 8) & 0xff` here.
# But older devices might behave oddly given that byte, so we don't send it. # But older devices might behave oddly given that byte, so we don't send it.
ret = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x30, *pkt) ret = feature_request(self._device, FEATURE.REPROG_CONTROLS_V4, 0x30, *pkt)
if ret is None or _unpack('!BBBBB', ret[:5]) != pkt and _log.isEnabledFor(_DEBUG): if ret is None or _unpack('!BBBBB', ret[:5]) != pkt and logger.isEnabledFor(logging.DEBUG):
_log.debug(f"REPROG_CONTROLS_v4 setCidReporting on device {self._device} didn't echo request packet.") logger.debug(f"REPROG_CONTROLS_v4 setCidReporting on device {self._device} didn't echo request packet.")
class PersistentRemappableAction(): class PersistentRemappableAction():
@ -608,8 +603,8 @@ class KeysArray:
elif FEATURE.REPROG_CONTROLS_V2 in self.device.features: elif FEATURE.REPROG_CONTROLS_V2 in self.device.features:
self.keyversion = FEATURE.REPROG_CONTROLS_V2 self.keyversion = FEATURE.REPROG_CONTROLS_V2
else: else:
if _log.isEnabledFor(_ERROR): if logger.isEnabledFor(logging.ERROR):
_log.error(f'Trying to read keys on device {device} which has no REPROG_CONTROLS(_VX) support.') logger.error(f'Trying to read keys on device {device} which has no REPROG_CONTROLS(_VX) support.')
self.keyversion = None self.keyversion = None
self.keys = [None] * count self.keys = [None] * count
@ -634,8 +629,8 @@ class KeysArray:
self.cid_to_tid[cid] = tid self.cid_to_tid[cid] = tid
if group != 0: # 0 = does not belong to a group if group != 0: # 0 = does not belong to a group
self.group_cids[special_keys.CID_GROUP[group]].append(cid) self.group_cids[special_keys.CID_GROUP[group]].append(cid)
elif _log.isEnabledFor(_WARNING): elif logger.isEnabledFor(logging.WARNING):
_log.warn(f"Key with index {index} was expected to exist but device doesn't report it.") logger.warn(f"Key with index {index} was expected to exist but device doesn't report it.")
def _ensure_all_keys_queried(self): def _ensure_all_keys_queried(self):
"""The retrieval of key information is lazy, but for certain functionality """The retrieval of key information is lazy, but for certain functionality
@ -697,8 +692,8 @@ class KeysArrayV1(KeysArray):
cid, tid, flags = _unpack('!HHB', keydata[:5]) cid, tid, flags = _unpack('!HHB', keydata[:5])
self.keys[index] = ReprogrammableKey(self.device, index, cid, tid, flags) self.keys[index] = ReprogrammableKey(self.device, index, cid, tid, flags)
self.cid_to_tid[cid] = tid self.cid_to_tid[cid] = tid
elif _log.isEnabledFor(_WARNING): elif logger.isEnabledFor(logging.WARNING):
_log.warn(f"Key with index {index} was expected to exist but device doesn't report it.") logger.warn(f"Key with index {index} was expected to exist but device doesn't report it.")
class KeysArrayV4(KeysArrayV1): class KeysArrayV4(KeysArrayV1):
@ -717,8 +712,8 @@ class KeysArrayV4(KeysArrayV1):
self.cid_to_tid[cid] = tid self.cid_to_tid[cid] = tid
if group != 0: # 0 = does not belong to a group if group != 0: # 0 = does not belong to a group
self.group_cids[special_keys.CID_GROUP[group]].append(cid) self.group_cids[special_keys.CID_GROUP[group]].append(cid)
elif _log.isEnabledFor(_WARNING): elif logger.isEnabledFor(logging.WARNING):
_log.warn(f"Key with index {index} was expected to exist but device doesn't report it.") logger.warn(f"Key with index {index} was expected to exist but device doesn't report it.")
# we are only interested in the current host, so use 0xFF for the host throughout # we are only interested in the current host, so use 0xFF for the host throughout
@ -762,8 +757,8 @@ class KeysArrayPersistent(KeysArray):
elif actionId == special_keys.ACTIONID.Empty: # purge data from empty value elif actionId == special_keys.ACTIONID.Empty: # purge data from empty value
remapped = modifiers = 0 remapped = modifiers = 0
self.keys[index] = PersistentRemappableAction(self.device, index, key, actionId, remapped, modifiers, status) self.keys[index] = PersistentRemappableAction(self.device, index, key, actionId, remapped, modifiers, status)
elif _log.isEnabledFor(_WARNING): elif logger.isEnabledFor(logging.WARNING):
_log.warn(f"Key with index {index} was expected to exist but device doesn't report it.") logger.warn(f"Key with index {index} was expected to exist but device doesn't report it.")
# Gesture Ids for feature GESTURE_2 # Gesture Ids for feature GESTURE_2
@ -1050,8 +1045,8 @@ class Spec:
try: try:
value = feature_request(self._device, FEATURE.GESTURE_2, 0x50, self.id, 0xFF) value = feature_request(self._device, FEATURE.GESTURE_2, 0x50, self.id, 0xFF)
except FeatureCallError: # some calls produce an error (notably spec 5 multiplier on K400Plus) except FeatureCallError: # some calls produce an error (notably spec 5 multiplier on K400Plus)
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn(f'Feature Call Error reading Gesture Spec on device {self._device} for spec {self.id} - use None') logger.warn(f'Feature Call Error reading Gesture Spec on device {self._device} for spec {self.id} - use None')
return None return None
return _bytes2int(value[:self.byte_count]) return _bytes2int(value[:self.byte_count])
@ -1093,12 +1088,12 @@ class Gestures:
self.params[param.param] = param self.params[param.param] = param
elif field_high == 0x04: elif field_high == 0x04:
if field_low != 0x00: if field_low != 0x00:
_log.error(f'Unimplemented GESTURE_2 grouping {field_low} {field_high} found.') logger.error(f'Unimplemented GESTURE_2 grouping {field_low} {field_high} found.')
elif field_high & 0xF0 == 0x40: elif field_high & 0xF0 == 0x40:
spec = Spec(device, field_low, field_high) spec = Spec(device, field_low, field_high)
self.specs[spec.spec] = spec self.specs[spec.spec] = spec
else: else:
_log.warn(f'Unimplemented GESTURE_2 field {field_low} {field_high} found.') logger.warn(f'Unimplemented GESTURE_2 field {field_low} {field_high} found.')
index += 1 index += 1
def gesture(self, gesture): def gesture(self, gesture):
@ -1581,7 +1576,7 @@ class OnboardProfiles:
try: try:
written = 1 if OnboardProfiles.write_sector(device, 0, self.to_bytes()) else 0 written = 1 if OnboardProfiles.write_sector(device, 0, self.to_bytes()) else 0
except Exception as e: except Exception as e:
_log.warn('Exception writing onboard profile control sector') logger.warn('Exception writing onboard profile control sector')
raise e raise e
for p in self.profiles.values(): for p in self.profiles.values():
try: try:
@ -1589,7 +1584,7 @@ class OnboardProfiles:
raise Exception(f'Sector {p.sector} not a writable sector') raise Exception(f'Sector {p.sector} not a writable sector')
written += 1 if OnboardProfiles.write_sector(device, p.sector, p.to_bytes(self.size)) else 0 written += 1 if OnboardProfiles.write_sector(device, p.sector, p.to_bytes(self.size)) else 0
except Exception as e: except Exception as e:
_log.warn(f'Exception writing onboard profile sector {p.sector}') logger.warn(f'Exception writing onboard profile sector {p.sector}')
raise e raise e
return written return written
@ -1639,8 +1634,8 @@ def get_firmware(device):
fw_info = _FirmwareInfo(FIRMWARE_KIND.Other, '', '', None) fw_info = _FirmwareInfo(FIRMWARE_KIND.Other, '', '', None)
fw.append(fw_info) fw.append(fw_info)
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("device %d firmware %s", devnumber, fw_info) # logger.debug("device %d firmware %s", devnumber, fw_info)
return tuple(fw) return tuple(fw)
@ -1670,8 +1665,8 @@ def get_kind(device):
kind = feature_request(device, FEATURE.DEVICE_NAME, 0x20) kind = feature_request(device, FEATURE.DEVICE_NAME, 0x20)
if kind: if kind:
kind = ord(kind[:1]) kind = ord(kind[:1])
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("device %d type %d = %s", devnumber, kind, DEVICE_KIND[kind]) # logger.debug("device %d type %d = %s", devnumber, kind, DEVICE_KIND[kind])
return DEVICE_KIND[kind] return DEVICE_KIND[kind]
@ -1691,7 +1686,7 @@ def get_name(device):
if fragment: if fragment:
name += fragment[:name_length - len(name)] name += fragment[:name_length - len(name)]
else: else:
_log.error('failed to read whole name of %s (expected %d chars)', device, name_length) logger.error('failed to read whole name of %s (expected %d chars)', device, name_length)
return None return None
return name.decode('utf-8') return name.decode('utf-8')
@ -1714,7 +1709,7 @@ def get_friendly_name(device):
initial_null = 0 if fragment[0] else 1 # initial null actually seen on a device initial_null = 0 if fragment[0] else 1 # initial null actually seen on a device
name += fragment[initial_null:name_length + initial_null - len(name)] name += fragment[initial_null:name_length + initial_null - len(name)]
else: else:
_log.error('failed to read whole name of %s (expected %d chars)', device, name_length) logger.error('failed to read whole name of %s (expected %d chars)', device, name_length)
return None return None
return name.decode('utf-8') return name.decode('utf-8')
@ -1730,8 +1725,8 @@ def decipher_battery_status(report):
discharge, next, status = _unpack('!BBB', report[:3]) discharge, next, status = _unpack('!BBB', report[:3])
discharge = None if discharge == 0 else discharge discharge = None if discharge == 0 else discharge
status = BATTERY_STATUS[status] status = BATTERY_STATUS[status]
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('battery status %s%% charged, next %s%%, status %s', discharge, next, status) logger.debug('battery status %s%% charged, next %s%%, status %s', discharge, next, status)
return FEATURE.BATTERY_STATUS, discharge, next, status, None return FEATURE.BATTERY_STATUS, discharge, next, status, None
@ -1744,8 +1739,8 @@ def get_battery_unified(device):
def decipher_battery_unified(report): def decipher_battery_unified(report):
discharge, level, status, _ignore = _unpack('!BBBB', report[:4]) discharge, level, status, _ignore = _unpack('!BBBB', report[:4])
status = BATTERY_STATUS[status] status = BATTERY_STATUS[status]
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('battery unified %s%% charged, level %s, charging %s', discharge, level, status) logger.debug('battery unified %s%% charged, level %s, charging %s', discharge, level, status)
level = ( level = (
_BATTERY_APPROX.full if level == 8 # full _BATTERY_APPROX.full if level == 8 # full
else _BATTERY_APPROX.good if level == 4 # good else _BATTERY_APPROX.good if level == 4 # good
@ -1806,8 +1801,8 @@ def decipher_battery_voltage(report):
if level[0] < voltage: if level[0] < voltage:
charge_lvl = level[1] charge_lvl = level[1]
break break
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug( logger.debug(
'battery voltage %d mV, charging %s, status %d = %s, level %s, type %s', voltage, status, (flags & 0x03), 'battery voltage %d mV, charging %s, status %d = %s, level %s, type %s', voltage, status, (flags & 0x03),
charge_sts, charge_lvl, charge_type charge_sts, charge_lvl, charge_type
) )
@ -2015,8 +2010,8 @@ def get_host_names(device):
def set_host_name(device, name, currentName=''): def set_host_name(device, name, currentName=''):
name = bytearray(name, 'utf-8') name = bytearray(name, 'utf-8')
currentName = bytearray(currentName, 'utf-8') currentName = bytearray(currentName, 'utf-8')
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('Setting host name to %s', name) logger.info('Setting host name to %s', name)
state = feature_request(device, FEATURE.HOSTS_INFO, 0x00) state = feature_request(device, FEATURE.HOSTS_INFO, 0x00)
if state: if state:
flags, _ignore, _ignore, currentHost = _unpack('!BBBB', state[:4]) flags, _ignore, _ignore, currentHost = _unpack('!BBBB', state[:4])

View File

@ -16,12 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
import threading as _threading import threading as _threading
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import getLogger
from . import base as _base from . import base as _base
# from time import time as _timestamp # from time import time as _timestamp
@ -32,8 +29,7 @@ try:
except ImportError: except ImportError:
from queue import Queue as _Queue from queue import Queue as _Queue
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -64,10 +60,10 @@ class _ThreadedHandle:
def _open(self): def _open(self):
handle = _base.open_path(self.path) handle = _base.open_path(self.path)
if handle is None: if handle is None:
_log.error('%r failed to open new handle', self) logger.error('%r failed to open new handle', self)
else: else:
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("%r opened new handle %d", self, handle) # logger.debug("%r opened new handle %d", self, handle)
self._local.handle = handle self._local.handle = handle
self._handles.append(handle) self._handles.append(handle)
return handle return handle
@ -76,8 +72,8 @@ class _ThreadedHandle:
if self._local: if self._local:
self._local = None self._local = None
handles, self._handles = self._handles, [] handles, self._handles = self._handles, []
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%r closing %s', self, handles) logger.debug('%r closing %s', self, handles)
for h in handles: for h in handles:
_base.close(h) _base.close(h)
@ -155,8 +151,8 @@ class EventsListener(_threading.Thread):
self._active = True self._active = True
# replace the handle with a threaded one # replace the handle with a threaded one
self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle) self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('started with %s (%d)', self.receiver, int(self.receiver.handle)) logger.info('started with %s (%d)', self.receiver, int(self.receiver.handle))
self.has_started() self.has_started()
if self.receiver.isDevice: # ping (wired or BT) devices to see if they are really online if self.receiver.isDevice: # ping (wired or BT) devices to see if they are really online
@ -168,7 +164,7 @@ class EventsListener(_threading.Thread):
try: try:
n = _base.read(self.receiver.handle, _EVENT_READ_TIMEOUT) n = _base.read(self.receiver.handle, _EVENT_READ_TIMEOUT)
except _base.NoReceiver: except _base.NoReceiver:
_log.warning('%s disconnected', self.receiver.name) logger.warning('%s disconnected', self.receiver.name)
self.receiver.close() self.receiver.close()
break break
if n: if n:
@ -179,7 +175,7 @@ class EventsListener(_threading.Thread):
try: try:
self._notifications_callback(n) self._notifications_callback(n)
except Exception: except Exception:
_log.exception('processing %s', n) logger.exception('processing %s', n)
del self._queued_notifications del self._queued_notifications
self.has_stopped() self.has_stopped()
@ -206,8 +202,8 @@ class EventsListener(_threading.Thread):
# i.e. triggered by a callback handling a previous notification. # i.e. triggered by a callback handling a previous notification.
assert _threading.current_thread() == self assert _threading.current_thread() == self
if self._active: # and _threading.current_thread() == self: if self._active: # and _threading.current_thread() == self:
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("queueing unhandled %s", n) # logger.debug("queueing unhandled %s", n)
if not self._queued_notifications.full(): if not self._queued_notifications.full():
self._queued_notifications.put(n) self._queued_notifications.put(n)

View File

@ -17,11 +17,9 @@
# Handles incoming events from the receiver/devices, updating the related # Handles incoming events from the receiver/devices, updating the related
# status object as appropriate. # status object as appropriate.
import logging
import threading as _threading import threading as _threading
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import getLogger
from struct import unpack as _unpack from struct import unpack as _unpack
from . import diversion as _diversion from . import diversion as _diversion
@ -34,8 +32,7 @@ from .i18n import _
from .status import ALERT as _ALERT from .status import ALERT as _ALERT
from .status import KEYS as _K from .status import KEYS as _K
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
_F = _hidpp20.FEATURE _F = _hidpp20.FEATURE
@ -73,8 +70,8 @@ def _process_receiver_notification(receiver, status, n):
if n.sub_id == 0x4A: # pairing lock notification if n.sub_id == 0x4A: # pairing lock notification
status.lock_open = bool(n.address & 0x01) status.lock_open = bool(n.address & 0x01)
reason = (_('pairing lock is open') if status.lock_open else _('pairing lock is closed')) reason = (_('pairing lock is open') if status.lock_open else _('pairing lock is closed'))
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: %s', receiver, reason) logger.info('%s: %s', receiver, reason)
status[_K.ERROR] = None status[_K.ERROR] = None
if status.lock_open: if status.lock_open:
status.new_device = None status.new_device = None
@ -82,7 +79,7 @@ def _process_receiver_notification(receiver, status, n):
if pair_error: if pair_error:
status[_K.ERROR] = error_string = _hidpp10.PAIRING_ERRORS[pair_error] status[_K.ERROR] = error_string = _hidpp10.PAIRING_ERRORS[pair_error]
status.new_device = None status.new_device = None
_log.warn('pairing error %d: %s', pair_error, error_string) logger.warning('pairing error %d: %s', pair_error, error_string)
status.changed(reason=reason) status.changed(reason=reason)
return True return True
@ -90,8 +87,8 @@ def _process_receiver_notification(receiver, status, n):
with notification_lock: with notification_lock:
status.discovering = n.address == 0x00 status.discovering = n.address == 0x00
reason = (_('discovery lock is open') if status.discovering else _('discovery lock is closed')) reason = (_('discovery lock is open') if status.discovering else _('discovery lock is closed'))
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: %s', receiver, reason) logger.info('%s: %s', receiver, reason)
status[_K.ERROR] = None status[_K.ERROR] = None
if status.discovering: if status.discovering:
status.counter = status.device_address = status.device_authentication = status.device_name = None status.counter = status.device_address = status.device_authentication = status.device_name = None
@ -99,7 +96,7 @@ def _process_receiver_notification(receiver, status, n):
discover_error = ord(n.data[:1]) discover_error = ord(n.data[:1])
if discover_error: if discover_error:
status[_K.ERROR] = discover_string = _hidpp10.BOLT_PAIRING_ERRORS[discover_error] status[_K.ERROR] = discover_string = _hidpp10.BOLT_PAIRING_ERRORS[discover_error]
_log.warn('bolt discovering error %d: %s', discover_error, discover_string) logger.warning('bolt discovering error %d: %s', discover_error, discover_string)
status.changed(reason=reason) status.changed(reason=reason)
return True return True
@ -124,8 +121,8 @@ def _process_receiver_notification(receiver, status, n):
status.device_passkey = None status.device_passkey = None
status.lock_open = n.address == 0x00 status.lock_open = n.address == 0x00
reason = (_('pairing lock is open') if status.lock_open else _('pairing lock is closed')) reason = (_('pairing lock is open') if status.lock_open else _('pairing lock is closed'))
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: %s', receiver, reason) logger.info('%s: %s', receiver, reason)
status[_K.ERROR] = None status[_K.ERROR] = None
if not status.lock_open: if not status.lock_open:
status.counter = status.device_address = status.device_authentication = status.device_name = None status.counter = status.device_address = status.device_authentication = status.device_name = None
@ -137,7 +134,7 @@ def _process_receiver_notification(receiver, status, n):
if pair_error: if pair_error:
status[_K.ERROR] = error_string = _hidpp10.BOLT_PAIRING_ERRORS[pair_error] status[_K.ERROR] = error_string = _hidpp10.BOLT_PAIRING_ERRORS[pair_error]
status.new_device = None status.new_device = None
_log.warn('pairing error %d: %s', pair_error, error_string) logger.warning('pairing error %d: %s', pair_error, error_string)
status.changed(reason=reason) status.changed(reason=reason)
return True return True
@ -149,7 +146,7 @@ def _process_receiver_notification(receiver, status, n):
elif n.sub_id == _R.passkey_pressed_notification: # Bolt pairing elif n.sub_id == _R.passkey_pressed_notification: # Bolt pairing
return True return True
_log.warn('%s: unhandled notification %s', receiver, n) logger.warning('%s: unhandled notification %s', receiver, n)
# #
@ -190,46 +187,46 @@ def _process_device_notification(device, status, n):
# assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications # assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications
if not device.features: if not device.features:
_log.warn('%s: feature notification but features not set up: %02X %s', device, n.sub_id, n) logger.warning('%s: feature notification but features not set up: %02X %s', device, n.sub_id, n)
return False return False
try: try:
feature = device.features.get_feature(n.sub_id) feature = device.features.get_feature(n.sub_id)
except IndexError: except IndexError:
_log.warn('%s: notification from invalid feature index %02X: %s', device, n.sub_id, n) logger.warning('%s: notification from invalid feature index %02X: %s', device, n.sub_id, n)
return False return False
return _process_feature_notification(device, status, n, feature) return _process_feature_notification(device, status, n, feature)
def _process_dj_notification(device, status, n): def _process_dj_notification(device, status, n):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s (%s) DJ %s', device, device.protocol, n) logger.debug('%s (%s) DJ %s', device, device.protocol, n)
if n.sub_id == 0x40: if n.sub_id == 0x40:
# do all DJ paired notifications also show up as HID++ 1.0 notifications? # do all DJ paired notifications also show up as HID++ 1.0 notifications?
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: ignoring DJ unpaired: %s', device, n) logger.info('%s: ignoring DJ unpaired: %s', device, n)
return True return True
if n.sub_id == 0x41: if n.sub_id == 0x41:
# do all DJ paired notifications also show up as HID++ 1.0 notifications? # do all DJ paired notifications also show up as HID++ 1.0 notifications?
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: ignoring DJ paired: %s', device, n) logger.info('%s: ignoring DJ paired: %s', device, n)
return True return True
if n.sub_id == 0x42: if n.sub_id == 0x42:
connected = not n.address & 0x01 connected = not n.address & 0x01
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: DJ connection: %s %s', device, connected, n) logger.info('%s: DJ connection: %s %s', device, connected, n)
status.changed(active=connected, alert=_ALERT.NONE, reason=_('connected') if connected else _('disconnected')) status.changed(active=connected, alert=_ALERT.NONE, reason=_('connected') if connected else _('disconnected'))
return True return True
_log.warn('%s: unrecognized DJ %s', device, n) logger.warning('%s: unrecognized DJ %s', device, n)
def _process_hidpp10_custom_notification(device, status, n): def _process_hidpp10_custom_notification(device, status, n):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s (%s) custom notification %s', device, device.protocol, n) logger.debug('%s (%s) custom notification %s', device, device.protocol, n)
if n.sub_id in (_R.battery_status, _R.battery_charge): if n.sub_id in (_R.battery_status, _R.battery_charge):
# message layout: 10 ix <register> <xx> <yy> <zz> <00> # message layout: 10 ix <register> <xx> <yy> <zz> <00>
@ -242,11 +239,11 @@ def _process_hidpp10_custom_notification(device, status, n):
if n.sub_id == _R.keyboard_illumination: if n.sub_id == _R.keyboard_illumination:
# message layout: 10 ix 17("address") <??> <?> <??> <light level 1=off..5=max> # message layout: 10 ix 17("address") <??> <?> <??> <light level 1=off..5=max>
# TODO anything we can do with this? # TODO anything we can do with this?
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('illumination event: %s', n) logger.info('illumination event: %s', n)
return True return True
_log.warn('%s: unrecognized %s', device, n) logger.warning('%s: unrecognized %s', device, n)
def _process_hidpp10_notification(device, status, n): def _process_hidpp10_notification(device, status, n):
@ -261,7 +258,7 @@ def _process_hidpp10_notification(device, status, n):
del device.receiver[device.number] del device.receiver[device.number]
status.changed(active=False, alert=_ALERT.ALL, reason=_('unpaired')) status.changed(active=False, alert=_ALERT.ALL, reason=_('unpaired'))
else: else:
_log.warn('%s: disconnection with unknown type %02X: %s', device, n.address, n) logger.warning('%s: disconnection with unknown type %02X: %s', device, n.address, n)
return True return True
# device connection (and disconnection) # device connection (and disconnection)
@ -276,12 +273,12 @@ def _process_hidpp10_notification(device, status, n):
link_established = not (flags & 0x40) link_established = not (flags & 0x40)
link_encrypted = bool(flags & 0x20) or n.address == 0x10 # Bolt protocol always encrypted link_encrypted = bool(flags & 0x20) or n.address == 0x10 # Bolt protocol always encrypted
else: else:
_log.warn('%s: connection notification with unknown protocol %02X: %s', device.number, n.address, n) logger.warning('%s: connection notification with unknown protocol %02X: %s', device.number, n.address, n)
return True return True
if wpid != device.wpid: if wpid != device.wpid:
_log.warn('%s wpid mismatch, got %s', device, wpid) logger.warning('%s wpid mismatch, got %s', device, wpid)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug( logger.debug(
'%s: protocol %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s', device, n.address, '%s: protocol %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s', device, n.address,
bool(flags & 0x10), link_encrypted, link_established, bool(flags & 0x80) bool(flags & 0x10), link_encrypted, link_established, bool(flags & 0x80)
) )
@ -299,44 +296,44 @@ def _process_hidpp10_notification(device, status, n):
# power notification # power notification
if n.sub_id == 0x4B: if n.sub_id == 0x4B:
if n.address == 0x01: if n.address == 0x01:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: device powered on', device) logger.debug('%s: device powered on', device)
reason = status.to_string() or _('powered on') reason = status.to_string() or _('powered on')
status.changed(active=True, alert=_ALERT.NOTIFICATION, reason=reason) status.changed(active=True, alert=_ALERT.NOTIFICATION, reason=reason)
else: else:
_log.warn('%s: unknown %s', device, n) logger.warning('%s: unknown %s', device, n)
return True return True
_log.warn('%s: unrecognized %s', device, n) logger.warning('%s: unrecognized %s', device, n)
def _process_feature_notification(device, status, n, feature): def _process_feature_notification(device, status, n, feature):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: notification for feature %s, report %s, data %s', device, feature, n.address >> 4, _strhex(n.data)) logger.debug('%s: notification for feature %s, report %s, data %s', device, feature, n.address >> 4, _strhex(n.data))
if feature == _F.BATTERY_STATUS: if feature == _F.BATTERY_STATUS:
if n.address == 0x00: if n.address == 0x00:
_ignore, discharge_level, discharge_next_level, battery_status, voltage = _hidpp20.decipher_battery_status(n.data) _ignore, discharge_level, discharge_next_level, battery_status, voltage = _hidpp20.decipher_battery_status(n.data)
status.set_battery_info(discharge_level, discharge_next_level, battery_status, voltage) status.set_battery_info(discharge_level, discharge_next_level, battery_status, voltage)
elif n.address == 0x10: elif n.address == 0x10:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: spurious BATTERY status %s', device, n) logger.info('%s: spurious BATTERY status %s', device, n)
else: else:
_log.warn('%s: unknown BATTERY %s', device, n) logger.warning('%s: unknown BATTERY %s', device, n)
elif feature == _F.BATTERY_VOLTAGE: elif feature == _F.BATTERY_VOLTAGE:
if n.address == 0x00: if n.address == 0x00:
_ignore, level, nextl, battery_status, voltage = _hidpp20.decipher_battery_voltage(n.data) _ignore, level, nextl, battery_status, voltage = _hidpp20.decipher_battery_voltage(n.data)
status.set_battery_info(level, nextl, battery_status, voltage) status.set_battery_info(level, nextl, battery_status, voltage)
else: else:
_log.warn('%s: unknown VOLTAGE %s', device, n) logger.warning('%s: unknown VOLTAGE %s', device, n)
elif feature == _F.UNIFIED_BATTERY: elif feature == _F.UNIFIED_BATTERY:
if n.address == 0x00: if n.address == 0x00:
_ignore, level, nextl, battery_status, voltage = _hidpp20.decipher_battery_unified(n.data) _ignore, level, nextl, battery_status, voltage = _hidpp20.decipher_battery_unified(n.data)
status.set_battery_info(level, nextl, battery_status, voltage) status.set_battery_info(level, nextl, battery_status, voltage)
else: else:
_log.warn('%s: unknown UNIFIED BATTERY %s', device, n) logger.warning('%s: unknown UNIFIED BATTERY %s', device, n)
elif feature == _F.ADC_MEASUREMENT: elif feature == _F.ADC_MEASUREMENT:
if n.address == 0x00: if n.address == 0x00:
@ -347,7 +344,7 @@ def _process_feature_notification(device, status, n, feature):
else: # this feature is used to signal device becoming inactive else: # this feature is used to signal device becoming inactive
status.changed(active=False) status.changed(active=False)
else: else:
_log.warn('%s: unknown ADC MEASUREMENT %s', device, n) logger.warning('%s: unknown ADC MEASUREMENT %s', device, n)
elif feature == _F.SOLAR_DASHBOARD: elif feature == _F.SOLAR_DASHBOARD:
if n.data[5:9] == b'GOOD': if n.data[5:9] == b'GOOD':
@ -364,8 +361,8 @@ def _process_feature_notification(device, status, n, feature):
status_text = _hidpp20.BATTERY_STATUS.recharging status_text = _hidpp20.BATTERY_STATUS.recharging
status.set_battery_info(charge, None, status_text, None) status.set_battery_info(charge, None, status_text, None)
elif n.address == 0x20: elif n.address == 0x20:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: Light Check button pressed', device) logger.debug('%s: Light Check button pressed', device)
status.changed(alert=_ALERT.SHOW_WINDOW) status.changed(alert=_ALERT.SHOW_WINDOW)
# first cancel any reporting # first cancel any reporting
# device.feature_request(_F.SOLAR_DASHBOARD) # device.feature_request(_F.SOLAR_DASHBOARD)
@ -374,41 +371,41 @@ def _process_feature_notification(device, status, n, feature):
reports_period = 2 # seconds reports_period = 2 # seconds
device.feature_request(_F.SOLAR_DASHBOARD, 0x00, reports_count, reports_period) device.feature_request(_F.SOLAR_DASHBOARD, 0x00, reports_count, reports_period)
else: else:
_log.warn('%s: unknown SOLAR CHARGE %s', device, n) logger.warning('%s: unknown SOLAR CHARGE %s', device, n)
else: else:
_log.warn('%s: SOLAR CHARGE not GOOD? %s', device, n) logger.warning('%s: SOLAR CHARGE not GOOD? %s', device, n)
elif feature == _F.WIRELESS_DEVICE_STATUS: elif feature == _F.WIRELESS_DEVICE_STATUS:
if n.address == 0x00: if n.address == 0x00:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('wireless status: %s', n) logger.debug('wireless status: %s', n)
reason = 'powered on' if n.data[2] == 1 else None reason = 'powered on' if n.data[2] == 1 else None
if n.data[1] == 1: # device is asking for software reconfiguration so need to change status if n.data[1] == 1: # device is asking for software reconfiguration so need to change status
alert = _ALERT.NONE alert = _ALERT.NONE
status.changed(active=True, alert=alert, reason=reason, push=True) status.changed(active=True, alert=alert, reason=reason, push=True)
else: else:
_log.warn('%s: unknown WIRELESS %s', device, n) logger.warning('%s: unknown WIRELESS %s', device, n)
elif feature == _F.TOUCHMOUSE_RAW_POINTS: elif feature == _F.TOUCHMOUSE_RAW_POINTS:
if n.address == 0x00: if n.address == 0x00:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: TOUCH MOUSE points %s', device, n) logger.info('%s: TOUCH MOUSE points %s', device, n)
elif n.address == 0x10: elif n.address == 0x10:
touch = ord(n.data[:1]) touch = ord(n.data[:1])
button_down = bool(touch & 0x02) button_down = bool(touch & 0x02)
mouse_lifted = bool(touch & 0x01) mouse_lifted = bool(touch & 0x01)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s', device, button_down, mouse_lifted) logger.info('%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s', device, button_down, mouse_lifted)
else: else:
_log.warn('%s: unknown TOUCH MOUSE %s', device, n) logger.warning('%s: unknown TOUCH MOUSE %s', device, n)
# TODO: what are REPROG_CONTROLS_V{2,3}? # TODO: what are REPROG_CONTROLS_V{2,3}?
elif feature == _F.REPROG_CONTROLS: elif feature == _F.REPROG_CONTROLS:
if n.address == 0x00: if n.address == 0x00:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: reprogrammable key: %s', device, n) logger.info('%s: reprogrammable key: %s', device, n)
else: else:
_log.warn('%s: unknown REPROG_CONTROLS %s', device, n) logger.warning('%s: unknown REPROG_CONTROLS %s', device, n)
elif feature == _F.BACKLIGHT2: elif feature == _F.BACKLIGHT2:
if (n.address == 0x00): if (n.address == 0x00):
@ -420,43 +417,43 @@ def _process_feature_notification(device, status, n, feature):
elif feature == _F.REPROG_CONTROLS_V4: elif feature == _F.REPROG_CONTROLS_V4:
if n.address == 0x00: if n.address == 0x00:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
cid1, cid2, cid3, cid4 = _unpack('!HHHH', n.data[:8]) cid1, cid2, cid3, cid4 = _unpack('!HHHH', n.data[:8])
_log.debug('%s: diverted controls pressed: 0x%x, 0x%x, 0x%x, 0x%x', device, cid1, cid2, cid3, cid4) logger.debug('%s: diverted controls pressed: 0x%x, 0x%x, 0x%x, 0x%x', device, cid1, cid2, cid3, cid4)
elif n.address == 0x10: elif n.address == 0x10:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
dx, dy = _unpack('!hh', n.data[:4]) dx, dy = _unpack('!hh', n.data[:4])
_log.debug('%s: rawXY dx=%i dy=%i', device, dx, dy) logger.debug('%s: rawXY dx=%i dy=%i', device, dx, dy)
elif n.address == 0x20: elif n.address == 0x20:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: received analyticsKeyEvents', device) logger.debug('%s: received analyticsKeyEvents', device)
elif _log.isEnabledFor(_INFO): elif logger.isEnabledFor(logging.INFO):
_log.info('%s: unknown REPROG_CONTROLS_V4 %s', device, n) logger.info('%s: unknown REPROG_CONTROLS_V4 %s', device, n)
elif feature == _F.HIRES_WHEEL: elif feature == _F.HIRES_WHEEL:
if (n.address == 0x00): if (n.address == 0x00):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
flags, delta_v = _unpack('>bh', n.data[:3]) flags, delta_v = _unpack('>bh', n.data[:3])
high_res = (flags & 0x10) != 0 high_res = (flags & 0x10) != 0
periods = flags & 0x0f periods = flags & 0x0f
_log.info('%s: WHEEL: res: %d periods: %d delta V:%-3d', device, high_res, periods, delta_v) logger.info('%s: WHEEL: res: %d periods: %d delta V:%-3d', device, high_res, periods, delta_v)
elif (n.address == 0x10): elif (n.address == 0x10):
ratchet = n.data[0] ratchet = n.data[0]
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: WHEEL: ratchet: %d', device, ratchet) logger.info('%s: WHEEL: ratchet: %d', device, ratchet)
if ratchet < 2: # don't process messages with unusual ratchet values if ratchet < 2: # don't process messages with unusual ratchet values
from solaar.ui.config_panel import record_setting # prevent circular import from solaar.ui.config_panel import record_setting # prevent circular import
setting = next((s for s in device.settings if s.name == _st.ScrollRatchet.name), None) setting = next((s for s in device.settings if s.name == _st.ScrollRatchet.name), None)
if setting: if setting:
record_setting(device, setting, [2 if ratchet else 1]) record_setting(device, setting, [2 if ratchet else 1])
else: else:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: unknown WHEEL %s', device, n) logger.info('%s: unknown WHEEL %s', device, n)
elif feature == _F.ONBOARD_PROFILES: elif feature == _F.ONBOARD_PROFILES:
if (n.address > 0x10): if (n.address > 0x10):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: unknown ONBOARD PROFILES %s', device, n) logger.info('%s: unknown ONBOARD PROFILES %s', device, n)
else: else:
if (n.address == 0x00): if (n.address == 0x00):
resolution_index = None resolution_index = None

View File

@ -17,9 +17,7 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import errno as _errno import errno as _errno
import logging
from logging import INFO as _INFO
from logging import getLogger
import hidapi as _hid import hidapi as _hid
@ -29,8 +27,7 @@ from .base_usb import product_information as _product_information
from .common import strhex as _strhex from .common import strhex as _strhex
from .device import Device from .device import Device
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
_IR = _hidpp10.INFO_SUBREGISTERS _IR = _hidpp10.INFO_SUBREGISTERS
@ -56,7 +53,7 @@ class Receiver:
self.product_id = product_id self.product_id = product_id
product_info = _product_information(self.product_id) product_info = _product_information(self.product_id)
if not product_info: if not product_info:
_log.warning('Unknown receiver type: %s', self.product_id) logger.warning('Unknown receiver type: %s', self.product_id)
product_info = {} product_info = {}
self.receiver_kind = product_info.get('receiver_kind', 'unknown') self.receiver_kind = product_info.get('receiver_kind', 'unknown')
@ -131,13 +128,13 @@ class Receiver:
set_flag_bits = 0 set_flag_bits = 0
ok = _hidpp10.set_notification_flags(self, set_flag_bits) ok = _hidpp10.set_notification_flags(self, set_flag_bits)
if ok is None: if ok is None:
_log.warn('%s: failed to %s receiver notifications', self, 'enable' if enable else 'disable') logger.warning('%s: failed to %s receiver notifications', self, 'enable' if enable else 'disable')
return None return None
flag_bits = _hidpp10.get_notification_flags(self) flag_bits = _hidpp10.get_notification_flags(self)
flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits)) flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits))
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: receiver notifications %s => %s', self, 'enabled' if enable else 'disabled', flag_names) logger.info('%s: receiver notifications %s => %s', self, 'enabled' if enable else 'disabled', flag_names)
return flag_bits return flag_bits
def device_codename(self, n): def device_codename(self, n):
@ -172,7 +169,7 @@ class Receiver:
elif self.receiver_kind == '27Mz': # 27Mhz receiver, fill extracting WPID from udev path elif self.receiver_kind == '27Mz': # 27Mhz receiver, fill extracting WPID from udev path
wpid = _hid.find_paired_node_wpid(self.path, n) wpid = _hid.find_paired_node_wpid(self.path, n)
if not wpid: if not wpid:
_log.error('Unable to get wpid from udev for device %d of %s', n, self) logger.error('Unable to get wpid from udev for device %d of %s', n, self)
raise _base.NoSuchDevice(number=n, receiver=self, error='Not present 27Mhz device') raise _base.NoSuchDevice(number=n, receiver=self, error='Not present 27Mhz device')
kind = _hidpp10.DEVICE_KIND[self.get_kind_from_index(n)] kind = _hidpp10.DEVICE_KIND[self.get_kind_from_index(n)]
elif not self.receiver_kind == 'unifying': # unifying protocol not supported, may be an old Nano receiver elif not self.receiver_kind == 'unifying': # unifying protocol not supported, may be an old Nano receiver
@ -219,7 +216,7 @@ class Receiver:
elif index == 4: # numpad elif index == 4: # numpad
kind = 3 kind = 3
else: # unknown device number on 27Mhz receiver else: # unknown device number on 27Mhz receiver
_log.error('failed to calculate device kind for device %d of %s', index, self) logger.error('failed to calculate device kind for device %d of %s', index, self)
raise _base.NoSuchDevice(number=index, receiver=self, error='Unknown 27Mhz device number') raise _base.NoSuchDevice(number=index, receiver=self, error='Unknown 27Mhz device number')
return kind return kind
@ -227,7 +224,7 @@ class Receiver:
"""Scan all devices.""" """Scan all devices."""
if self.handle: if self.handle:
if not self.write_register(_R.receiver_connection, 0x02): if not self.write_register(_R.receiver_connection, 0x02):
_log.warn('%s: failed to trigger device link notifications', self) logger.warning('%s: failed to trigger device link notifications', self)
def register_new_device(self, number, notification=None): def register_new_device(self, number, notification=None):
if self._devices.get(number) is not None: if self._devices.get(number) is not None:
@ -238,14 +235,14 @@ class Receiver:
try: try:
dev = Device(self, number, notification) dev = Device(self, number, notification)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: found new device %d (%s)', self, number, dev.wpid) logger.info('%s: found new device %d (%s)', self, number, dev.wpid)
self._devices[number] = dev self._devices[number] = dev
return dev return dev
except _base.NoSuchDevice as e: except _base.NoSuchDevice as e:
_log.warn('register new device failed for %s device %d error %s', e.receiver, e.number, e.error) logger.warning('register new device failed for %s device %d error %s', e.receiver, e.number, e.error)
_log.warning('%s: looked for device %d, not found', self, number) logger.warning('%s: looked for device %d, not found', self, number)
self._devices[number] = None self._devices[number] = None
def set_lock(self, lock_closed=True, device=0, timeout=0): def set_lock(self, lock_closed=True, device=0, timeout=0):
@ -254,7 +251,7 @@ class Receiver:
reply = self.write_register(_R.receiver_pairing, action, device, timeout) reply = self.write_register(_R.receiver_pairing, action, device, timeout)
if reply: if reply:
return True return True
_log.warn('%s: failed to %s the receiver lock', self, 'close' if lock_closed else 'open') logger.warning('%s: failed to %s the receiver lock', self, 'close' if lock_closed else 'open')
def discover(self, cancel=False, timeout=30): # Bolt device discovery def discover(self, cancel=False, timeout=30): # Bolt device discovery
assert self.receiver_kind == 'bolt' assert self.receiver_kind == 'bolt'
@ -263,7 +260,7 @@ class Receiver:
reply = self.write_register(_R.bolt_device_discovery, timeout, action) reply = self.write_register(_R.bolt_device_discovery, timeout, action)
if reply: if reply:
return True return True
_log.warn('%s: failed to %s device discovery', self, 'cancel' if cancel else 'start') logger.warning('%s: failed to %s device discovery', self, 'cancel' if cancel else 'start')
def pair_device(self, pair=True, slot=0, address=b'\0\0\0\0\0\0', authentication=0x00, entropy=20): # Bolt pairing def pair_device(self, pair=True, slot=0, address=b'\0\0\0\0\0\0', authentication=0x00, entropy=20): # Bolt pairing
assert self.receiver_kind == 'bolt' assert self.receiver_kind == 'bolt'
@ -272,7 +269,7 @@ class Receiver:
reply = self.write_register(_R.bolt_pairing, action, slot, address, authentication, entropy) reply = self.write_register(_R.bolt_pairing, action, slot, address, authentication, entropy)
if reply: if reply:
return True return True
_log.warn('%s: failed to %s device %s', self, 'pair' if pair else 'unpair', address) logger.warning('%s: failed to %s device %s', self, 'pair' if pair else 'unpair', address)
def count(self): def count(self):
count = self.read_register(_R.receiver_connection) count = self.read_register(_R.receiver_connection)
@ -338,7 +335,7 @@ class Receiver:
dev.wpid = None dev.wpid = None
if key in self._devices: if key in self._devices:
del self._devices[key] del self._devices[key]
_log.warn('%s removed device %s', self, dev) logger.warning('%s removed device %s', self, dev)
else: else:
if self.receiver_kind == 'bolt': if self.receiver_kind == 'bolt':
reply = self.write_register(_R.bolt_pairing, 0x03, key) reply = self.write_register(_R.bolt_pairing, 0x03, key)
@ -350,10 +347,10 @@ class Receiver:
dev.wpid = None dev.wpid = None
if key in self._devices: if key in self._devices:
del self._devices[key] del self._devices[key]
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s unpaired device %s', self, dev) logger.info('%s unpaired device %s', self, dev)
else: else:
_log.error('%s failed to unpair device %s', self, dev) logger.error('%s failed to unpair device %s', self, dev)
raise Exception('failed to unpair device %s: %s' % (dev.name, key)) raise Exception('failed to unpair device %s: %s' % (dev.name, key))
def __len__(self): def __len__(self):
@ -392,8 +389,8 @@ class Receiver:
if handle: if handle:
return Receiver(handle, device_info.path, device_info.product_id) return Receiver(handle, device_info.path, device_info.product_id)
except OSError as e: except OSError as e:
_log.exception('open %s', device_info) logger.exception('open %s', device_info)
if e.errno == _errno.EACCES: if e.errno == _errno.EACCES:
raise raise
except Exception: except Exception:
_log.exception('open %s', device_info) logger.exception('open %s', device_info)

View File

@ -16,11 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
import math import math
from logging import DEBUG as _DEBUG
from logging import WARNING as _WARNING
from logging import getLogger
from struct import unpack as _unpack from struct import unpack as _unpack
from time import sleep as _sleep from time import sleep as _sleep
@ -31,8 +29,7 @@ from .common import bytes2int as _bytes2int
from .common import int2bytes as _int2bytes from .common import int2bytes as _int2bytes
from .i18n import _ from .i18n import _
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -141,13 +138,13 @@ class BooleanValidator(Validator):
reply_bytes = reply_bytes[self.read_skip_byte_count:] reply_bytes = reply_bytes[self.read_skip_byte_count:]
if isinstance(self.mask, int): if isinstance(self.mask, int):
reply_value = ord(reply_bytes[:1]) & self.mask reply_value = ord(reply_bytes[:1]) & self.mask
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('BooleanValidator: validate read %r => %02X', reply_bytes, reply_value) logger.debug('BooleanValidator: validate read %r => %02X', reply_bytes, reply_value)
if reply_value == self.true_value: if reply_value == self.true_value:
return True return True
if reply_value == self.false_value: if reply_value == self.false_value:
return False return False
_log.warn( logger.warning(
'BooleanValidator: reply %02X mismatched %02X/%02X/%02X', reply_value, self.true_value, self.false_value, 'BooleanValidator: reply %02X mismatched %02X/%02X/%02X', reply_value, self.true_value, self.false_value,
self.mask self.mask
) )
@ -165,7 +162,9 @@ class BooleanValidator(Validator):
if reply_value == false_value: if reply_value == false_value:
return False return False
_log.warn('BooleanValidator: reply %r mismatched %r/%r/%r', reply_bytes, self.true_value, self.false_value, self.mask) logger.warning(
'BooleanValidator: reply %r mismatched %r/%r/%r', reply_bytes, self.true_value, self.false_value, self.mask
)
return False return False
def prepare_write(self, new_value, current_value=None): def prepare_write(self, new_value, current_value=None):
@ -198,8 +197,8 @@ class BooleanValidator(Validator):
if current_value is not None and to_write == current_value[:len(to_write)]: if current_value is not None and to_write == current_value[:len(to_write)]:
return None return None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('BooleanValidator: prepare_write(%s, %s) => %r', new_value, current_value, to_write) logger.debug('BooleanValidator: prepare_write(%s, %s) => %r', new_value, current_value, to_write)
return self.write_prefix_bytes + to_write return self.write_prefix_bytes + to_write
@ -278,8 +277,8 @@ class Setting:
self._pre_read(cached) self._pre_read(cached)
if cached and self._value is not None: if cached and self._value is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: cached value %r on %s', self.name, self._value, self._device) logger.debug('%s: cached value %r on %s', self.name, self._value, self._device)
return self._value return self._value
if self._device.online: if self._device.online:
@ -290,8 +289,8 @@ class Setting:
# Don't update the persister if it already has a value, # Don't update the persister if it already has a value,
# otherwise the first read might overwrite the value we wanted. # otherwise the first read might overwrite the value we wanted.
self._device.persister[self.name] = self._value if self.persist else None self._device.persister[self.name] = self._value if self.persist else None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: read value %r on %s', self.name, self._value, self._device) logger.debug('%s: read value %r on %s', self.name, self._value, self._device)
return self._value return self._value
def _pre_write(self, save=True): def _pre_write(self, save=True):
@ -310,8 +309,8 @@ class Setting:
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert value is not None assert value is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: write %r to %s', self.name, value, self._device) logger.debug('%s: write %r to %s', self.name, value, self._device)
if self._device.online: if self._device.online:
if self._value != value: if self._value != value:
@ -321,13 +320,13 @@ class Setting:
if self._validator.needs_current_value: if self._validator.needs_current_value:
# the _validator needs the current value, possibly to merge flag values # the _validator needs the current value, possibly to merge flag values
current_value = self._rw.read(self._device) current_value = self._rw.read(self._device)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: current value %r on %s', self.name, current_value, self._device) logger.debug('%s: current value %r on %s', self.name, current_value, self._device)
data_bytes = self._validator.prepare_write(value, current_value) data_bytes = self._validator.prepare_write(value, current_value)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: prepare write(%s) => %r', self.name, value, data_bytes) logger.debug('%s: prepare write(%s) => %r', self.name, value, data_bytes)
reply = self._rw.write(self._device, data_bytes) reply = self._rw.write(self._device, data_bytes)
if not reply: if not reply:
@ -345,15 +344,15 @@ class Setting:
def apply(self): def apply(self):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: apply (%s)', self.name, self._device) logger.debug('%s: apply (%s)', self.name, self._device)
value = self.read(self.persist) # Don't use persisted value if setting doesn't persist value = self.read(self.persist) # Don't use persisted value if setting doesn't persist
if self.persist and value is not None: # If setting doesn't persist no need to write value just read if self.persist and value is not None: # If setting doesn't persist no need to write value just read
try: try:
self.write(value, save=False) self.write(value, save=False)
except Exception as e: except Exception as e:
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn( logger.warning(
'%s: error applying value %s so ignore it (%s): %s', self.name, self._value, self._device, repr(e) '%s: error applying value %s so ignore it (%s): %s', self.name, self._value, self._device, repr(e)
) )
@ -375,8 +374,8 @@ class Settings(Setting):
def read(self, cached=True): def read(self, cached=True):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r from %s', self.name, self._value, self._device) logger.debug('%s: settings read %r from %s', self.name, self._value, self._device)
self._pre_read(cached) self._pre_read(cached)
@ -400,8 +399,8 @@ class Settings(Setting):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert key is not None assert key is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device) logger.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device)
self._pre_read(cached) self._pre_read(cached)
if cached and self._value is not None: if cached and self._value is not None:
@ -420,16 +419,16 @@ class Settings(Setting):
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert map is not None assert map is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings write %r to %s', self.name, map, self._device) logger.debug('%s: settings write %r to %s', self.name, map, self._device)
if self._device.online: if self._device.online:
self.update(map, save) self.update(map, save)
for key, value in map.items(): for key, value in map.items():
data_bytes = self._validator.prepare_write(int(key), value) data_bytes = self._validator.prepare_write(int(key), value)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare map write(%s,%s) => %r', self.name, key, value, data_bytes) logger.debug('%s: settings prepare map write(%s,%s) => %r', self.name, key, value, data_bytes)
reply = self._rw.write(self._device, int(key), data_bytes) reply = self._rw.write(self._device, int(key), data_bytes)
if not reply: if not reply:
return None return None
@ -445,8 +444,8 @@ class Settings(Setting):
assert key is not None assert key is not None
assert value is not None assert value is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings write key %r value %r to %s', self.name, key, value, self._device) logger.debug('%s: settings write key %r value %r to %s', self.name, key, value, self._device)
if self._device.online: if self._device.online:
if not self._value: if not self._value:
@ -458,8 +457,8 @@ class Settings(Setting):
except ValueError: except ValueError:
data_bytes = value = None data_bytes = value = None
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, value, data_bytes) logger.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, value, data_bytes)
reply = self._rw.write(self._device, int(key), data_bytes) reply = self._rw.write(self._device, int(key), data_bytes)
if not reply: if not reply:
return None return None
@ -475,8 +474,8 @@ class LongSettings(Setting):
def read(self, cached=True): def read(self, cached=True):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r from %s', self.name, self._value, self._device) logger.debug('%s: settings read %r from %s', self.name, self._value, self._device)
self._pre_read(cached) self._pre_read(cached)
@ -502,8 +501,8 @@ class LongSettings(Setting):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert item is not None assert item is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r item %r from %s', self.name, self._value, item, self._device) logger.debug('%s: settings read %r item %r from %s', self.name, self._value, item, self._device)
self._pre_read(cached) self._pre_read(cached)
if cached and self._value is not None: if cached and self._value is not None:
@ -523,8 +522,8 @@ class LongSettings(Setting):
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert map is not None assert map is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: long settings write %r to %s', self.name, map, self._device) logger.debug('%s: long settings write %r to %s', self.name, map, self._device)
if self._device.online: if self._device.online:
self.update(map, save) self.update(map, save)
for item, value in map.items(): for item, value in map.items():
@ -532,8 +531,8 @@ class LongSettings(Setting):
if data_bytes_list is not None: if data_bytes_list is not None:
for data_bytes in data_bytes_list: for data_bytes in data_bytes_list:
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare map write(%s,%s) => %r', self.name, item, value, data_bytes) logger.debug('%s: settings prepare map write(%s,%s) => %r', self.name, item, value, data_bytes)
reply = self._rw.write(self._device, data_bytes) reply = self._rw.write(self._device, data_bytes)
if not reply: if not reply:
return None return None
@ -549,8 +548,8 @@ class LongSettings(Setting):
assert item is not None assert item is not None
assert value is not None assert value is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: long settings write item %r value %r to %s', self.name, item, value, self._device) logger.debug('%s: long settings write item %r value %r to %s', self.name, item, value, self._device)
if self._device.online: if self._device.online:
if not self._value: if not self._value:
@ -558,8 +557,8 @@ class LongSettings(Setting):
data_bytes = self._validator.prepare_write_item(item, value) data_bytes = self._validator.prepare_write_item(item, value)
self.update_key_value(item, value, save) self.update_key_value(item, value, save)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare item value write(%s,%s) => %r', self.name, item, value, data_bytes) logger.debug('%s: settings prepare item value write(%s,%s) => %r', self.name, item, value, data_bytes)
reply = self._rw.write(self._device, data_bytes) reply = self._rw.write(self._device, data_bytes)
if not reply: if not reply:
return None return None
@ -573,8 +572,8 @@ class BitFieldSetting(Setting):
def read(self, cached=True): def read(self, cached=True):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r from %s', self.name, self._value, self._device) logger.debug('%s: settings read %r from %s', self.name, self._value, self._device)
self._pre_read(cached) self._pre_read(cached)
@ -600,8 +599,8 @@ class BitFieldSetting(Setting):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert key is not None assert key is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device) logger.debug('%s: settings read %r key %r from %s', self.name, self._value, key, self._device)
self._pre_read(cached) self._pre_read(cached)
@ -624,14 +623,14 @@ class BitFieldSetting(Setting):
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert map is not None assert map is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: bit field settings write %r to %s', self.name, map, self._device) logger.debug('%s: bit field settings write %r to %s', self.name, map, self._device)
if self._device.online: if self._device.online:
self.update(map, save) self.update(map, save)
data_bytes = self._validator.prepare_write(self._value) data_bytes = self._validator.prepare_write(self._value)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare map write(%s) => %r', self.name, self._value, data_bytes) logger.debug('%s: settings prepare map write(%s) => %r', self.name, self._value, data_bytes)
# if prepare_write returns a list, write one item at a time # if prepare_write returns a list, write one item at a time
seq = data_bytes if isinstance(data_bytes, list) else [data_bytes] seq = data_bytes if isinstance(data_bytes, list) else [data_bytes]
for b in seq: for b in seq:
@ -650,8 +649,8 @@ class BitFieldSetting(Setting):
assert key is not None assert key is not None
assert value is not None assert value is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: bit field settings write key %r value %r to %s', self.name, key, value, self._device) logger.debug('%s: bit field settings write key %r value %r to %s', self.name, key, value, self._device)
if self._device.online: if self._device.online:
if not self._value: if not self._value:
@ -661,8 +660,8 @@ class BitFieldSetting(Setting):
data_bytes = self._validator.prepare_write(self._value) data_bytes = self._validator.prepare_write(self._value)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, str(value), data_bytes) logger.debug('%s: settings prepare key value write(%s,%s) => %r', self.name, key, str(value), data_bytes)
# if prepare_write returns a list, write one item at a time # if prepare_write returns a list, write one item at a time
seq = data_bytes if isinstance(data_bytes, list) else [data_bytes] seq = data_bytes if isinstance(data_bytes, list) else [data_bytes]
for b in seq: for b in seq:
@ -693,8 +692,8 @@ class RangeFieldSetting(Setting):
def read(self, cached=True): def read(self, cached=True):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: settings read %r from %s', self.name, self._value, self._device) logger.debug('%s: settings read %r from %s', self.name, self._value, self._device)
self._pre_read(cached) self._pre_read(cached)
if cached and self._value is not None: if cached and self._value is not None:
return self._value return self._value
@ -720,26 +719,26 @@ class RangeFieldSetting(Setting):
assert hasattr(self, '_value') assert hasattr(self, '_value')
assert hasattr(self, '_device') assert hasattr(self, '_device')
assert map is not None assert map is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: range field setting write %r to %s', self.name, map, self._device) logger.debug('%s: range field setting write %r to %s', self.name, map, self._device)
if self._device.online: if self._device.online:
self.update(map, save) self.update(map, save)
data_bytes = self._validator.prepare_write(self._value) data_bytes = self._validator.prepare_write(self._value)
if data_bytes is not None: if data_bytes is not None:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: range field setting prepare map write(%s) => %r', self.name, self._value, data_bytes) logger.debug('%s: range field setting prepare map write(%s) => %r', self.name, self._value, data_bytes)
reply = self._rw.write(self._device, data_bytes) reply = self._rw.write(self._device, data_bytes)
if not reply: if not reply:
return None return None
elif _log.isEnabledFor(_WARNING): elif logger.isEnabledFor(logging.WARNING):
_log.warn('%s: range field setting no data to write', self.name) logger.warning('%s: range field setting no data to write', self.name)
return map return map
def write_key_value(self, key, value, save=True): def write_key_value(self, key, value, save=True):
assert key is not None assert key is not None
assert value is not None assert value is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: range field setting write key %r value %r to %s', self.name, key, value, self._device) logger.debug('%s: range field setting write key %r value %r to %s', self.name, key, value, self._device)
if self._device.online: if self._device.online:
if not self._value: if not self._value:
self.read() self.read()
@ -1130,7 +1129,7 @@ class ChoicesMapValidator(ChoicesValidator):
def prepare_write(self, key, new_value): def prepare_write(self, key, new_value):
choices = self.choices.get(key) choices = self.choices.get(key)
if choices is None or (new_value not in choices and new_value != self.extra_default): if choices is None or (new_value not in choices and new_value != self.extra_default):
_log.error('invalid choice %r for %s', new_value, key) logger.error('invalid choice %r for %s', new_value, key)
return None return None
new_value = new_value | self.activate new_value = new_value | self.activate
return self._write_prefix_bytes + new_value.to_bytes(self._byte_count, 'big') return self._write_prefix_bytes + new_value.to_bytes(self._byte_count, 'big')
@ -1287,7 +1286,7 @@ class PackedRangeValidator(Validator):
return None if type(args[1]) != int or args[1] < self.min_value or args[1] > self.max_value else args return None if type(args[1]) != int or args[1] < self.min_value or args[1] > self.max_value else args
def compare(self, args, current): def compare(self, args, current):
_log.warn('compare not implemented for packed range settings') logger.warning('compare not implemented for packed range settings')
return False return False
@ -1316,7 +1315,7 @@ class MultipleRangeValidator(Validator):
r += b'\x00' * (sub_item.length - len(value)) r += b'\x00' * (sub_item.length - len(value))
v = _bytes2int(r) v = _bytes2int(r)
if not (sub_item.minimum < v < sub_item.maximum): if not (sub_item.minimum < v < sub_item.maximum):
_log.warn( logger.warning(
f'{self.__class__.__name__}: failed to validate read value for {item}.{sub_item}: ' + f'{self.__class__.__name__}: failed to validate read value for {item}.{sub_item}: ' +
f'{v} not in [{sub_item.minimum}..{sub_item.maximum}]' f'{v} not in [{sub_item.minimum}..{sub_item.maximum}]'
) )
@ -1376,7 +1375,7 @@ class MultipleRangeValidator(Validator):
return [int(item), {**args[1]}] return [int(item), {**args[1]}]
def compare(self, args, current): def compare(self, args, current):
_log.warn('compare not implemented for multiple range settings') logger.warning('compare not implemented for multiple range settings')
return False return False
@ -1438,7 +1437,7 @@ class ActionSettingRW:
divertSetting = next(filter(lambda s: s.name == self.divert_setting_name, device.settings), None) divertSetting = next(filter(lambda s: s.name == self.divert_setting_name, device.settings), None)
if divertSetting is None: if divertSetting is None:
_log.warn('setting %s not found on %s', self.divert_setting_name, device.name) logger.warning('setting %s not found on %s', self.divert_setting_name, device.name)
return None return None
self.device = device self.device = device
key = _bytes2int(data_bytes) key = _bytes2int(data_bytes)
@ -1453,7 +1452,7 @@ class ActionSettingRW:
self.activate_action() self.activate_action()
_status_changed(device, refresh=True) # update main window _status_changed(device, refresh=True) # update main window
else: else:
_log.error('cannot enable %s on %s for key %s', self.name, device, key) logger.error('cannot enable %s on %s for key %s', self.name, device, key)
else: # Disable else: # Disable
if self.active: if self.active:
self.active = False self.active = False
@ -1464,8 +1463,8 @@ class ActionSettingRW:
try: try:
device.remove_notification_handler(self.name) device.remove_notification_handler(self.name)
except Exception: except Exception:
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn('cannot disable %s on %s', self.name, device) logger.warning('cannot disable %s on %s', self.name, device)
self.deactivate_action() self.deactivate_action()
return True return True
@ -1526,8 +1525,8 @@ class RawXYProcessing:
try: try:
self.device.remove_notification_handler(self.name) self.device.remove_notification_handler(self.name)
except Exception: except Exception:
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn('cannot disable %s on %s', self.name, self.device) logger.warning('cannot disable %s on %s', self.name, self.device)
self.deactivate_action() self.deactivate_action()
self.active = False self.active = False

View File

@ -16,10 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import INFO as _INFO
from logging import WARN as _WARN from logging import WARN as _WARN
from logging import getLogger
from struct import pack as _pack from struct import pack as _pack
from struct import unpack as _unpack from struct import unpack as _unpack
from time import time as _time from time import time as _time
@ -52,8 +51,7 @@ from .settings import Setting as _Setting
from .settings import Settings as _Settings from .settings import Settings as _Settings
from .special_keys import DISABLE as _DKEY from .special_keys import DISABLE as _DKEY
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_DK = _hidpp10.DEVICE_KIND _DK = _hidpp10.DEVICE_KIND
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
@ -803,8 +801,8 @@ class MouseGesturesXY(_RawXYProcessing):
from .base import _HIDPP_Notification as _HIDPP_Notification from .base import _HIDPP_Notification as _HIDPP_Notification
from .diversion import process_notification as _process_notification from .diversion import process_notification as _process_notification
self.push_mouse_event() self.push_mouse_event()
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('mouse gesture notification %s', self.data) logger.info('mouse gesture notification %s', self.data)
payload = _pack('!' + (len(self.data) * 'h'), *self.data) payload = _pack('!' + (len(self.data) * 'h'), *self.data)
notification = _HIDPP_Notification(0, 0, 0, 0, payload) notification = _HIDPP_Notification(0, 0, 0, 0, payload)
_process_notification(self.device, self.device.status, notification, _hidpp20.FEATURE.MOUSE_GESTURE) _process_notification(self.device, self.device.status, notification, _hidpp20.FEATURE.MOUSE_GESTURE)
@ -830,8 +828,8 @@ class MouseGesturesXY(_RawXYProcessing):
self.data.append(1) self.data.append(1)
self.data.append(key) self.data.append(key)
self.lastEv = _time() * 1000 # _time_ns() / 1e6 self.lastEv = _time() * 1000 # _time_ns() / 1e6
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('mouse gesture key event %d %s', key, self.data) logger.debug('mouse gesture key event %d %s', key, self.data)
def push_mouse_event(self): def push_mouse_event(self):
x = int(self.dx) x = int(self.dx)
@ -843,8 +841,8 @@ class MouseGesturesXY(_RawXYProcessing):
self.data.append(y) self.data.append(y)
self.dx = 0. self.dx = 0.
self.dy = 0. self.dy = 0.
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('mouse gesture move event %d %d %s', x, y, self.data) logger.debug('mouse gesture move event %d %d %s', x, y, self.data)
class DivertKeys(_Settings): class DivertKeys(_Settings):
@ -982,7 +980,7 @@ class SpeedChange(_Setting):
if speed_setting: if speed_setting:
speed_setting.write(newSpeed) speed_setting.write(newSpeed)
else: else:
_log.error('cannot save sensitivity setting on %s', self.device) logger.error('cannot save sensitivity setting on %s', self.device)
from solaar.ui import status_changed as _status_changed from solaar.ui import status_changed as _status_changed
_status_changed(self.device, refresh=True) # update main window _status_changed(self.device, refresh=True) # update main window
if self.device.persister: if self.device.persister:
@ -1343,8 +1341,8 @@ class PersistentRemappableAction(_Settings):
elif capabilities & 0x0023 == 0x0023: # Key, Mouse, and HScroll Codes elif capabilities & 0x0023 == 0x0023: # Key, Mouse, and HScroll Codes
keys = _special_keys.KEYS_KEYS_MOUSE_HSCROLL keys = _special_keys.KEYS_KEYS_MOUSE_HSCROLL
else: else:
if _log.isEnabledFor(_WARN): if logger.isEnabledFor(_WARN):
_log.warn('%s: unimplemented Persistent Remappable capability %s', device.name, hex(capabilities)) logger.warning('%s: unimplemented Persistent Remappable capability %s', device.name, hex(capabilities))
return None return None
choices = {} choices = {}
for k in remap_keys: for k in remap_keys:
@ -1359,8 +1357,8 @@ class PersistentRemappableAction(_Settings):
reply_value = _bytes2int(reply_bytes[start:end]) & self.mask reply_value = _bytes2int(reply_bytes[start:end]) & self.mask
# Craft keyboard has a value that isn't valid so fudge these values # Craft keyboard has a value that isn't valid so fudge these values
if reply_value not in self.choices[key]: if reply_value not in self.choices[key]:
if _log.isEnabledFor(_WARN): if logger.isEnabledFor(_WARN):
_log.warn('unusual persistent remappable action mapping %x: use Default', reply_value) logger.warning('unusual persistent remappable action mapping %x: use Default', reply_value)
reply_value = _special_keys.KEYS_Default reply_value = _special_keys.KEYS_Default
return reply_value return reply_value
@ -1531,12 +1529,12 @@ def check_feature(device, sclass):
return return
try: try:
detected = sclass.build(device) detected = sclass.build(device)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('check_feature %s [%s] detected %s', sclass.name, sclass.feature, detected) logger.debug('check_feature %s [%s] detected %s', sclass.name, sclass.feature, detected)
return detected return detected
except Exception as e: except Exception as e:
from traceback import format_exc from traceback import format_exc
_log.error('check_feature %s [%s] error %s\n%s', sclass.name, sclass.feature, e, format_exc()) logger.error('check_feature %s [%s] error %s\n%s', sclass.name, sclass.feature, e, format_exc())
return False # differentiate from an error-free determination that the setting is not supported return False # differentiate from an error-free determination that the setting is not supported

View File

@ -16,9 +16,8 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import INFO as _INFO
from logging import getLogger
from time import time as _timestamp from time import time as _timestamp
from . import hidpp10 as _hidpp10 from . import hidpp10 as _hidpp10
@ -29,8 +28,7 @@ from .common import NamedInt as _NamedInt
from .common import NamedInts as _NamedInts from .common import NamedInts as _NamedInts
from .i18n import _, ngettext from .i18n import _, ngettext
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
@ -125,8 +123,8 @@ class ReceiverStatus(dict):
# r = self._receiver # r = self._receiver
# assert r # assert r
# #
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("polling status of %s", r) # logger.debug("polling status of %s", r)
# #
# # make sure to read some stuff that may be read later by the UI # # make sure to read some stuff that may be read later by the UI
# r.serial, r.firmware, None # r.serial, r.firmware, None
@ -194,8 +192,8 @@ class DeviceStatus(dict):
__nonzero__ = __bool__ __nonzero__ = __bool__
def set_battery_info(self, level, nextLevel, status, voltage, timestamp=None): def set_battery_info(self, level, nextLevel, status, voltage, timestamp=None):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s: battery %s, %s', self._device, level, status) logger.debug('%s: battery %s, %s', self._device, level, status)
if level is None: if level is None:
# Some notifications may come with no battery level info, just # Some notifications may come with no battery level info, just
@ -230,7 +228,7 @@ class DeviceStatus(dict):
if _hidpp20.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL): if _hidpp20.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL):
self[KEYS.ERROR] = None self[KEYS.ERROR] = None
else: else:
_log.warn('%s: battery %d%%, ALERT %s', self._device, level, status) logger.warning('%s: battery %d%%, ALERT %s', self._device, level, status)
if self.get(KEYS.ERROR) != status: if self.get(KEYS.ERROR) != status:
self[KEYS.ERROR] = status self[KEYS.ERROR] = status
# only show the notification once # only show the notification once
@ -288,8 +286,8 @@ class DeviceStatus(dict):
if was_active is None or push or not was_active and ( if was_active is None or push or not was_active and (
not d.features or _hidpp20.FEATURE.WIRELESS_DEVICE_STATUS not in d.features not d.features or _hidpp20.FEATURE.WIRELESS_DEVICE_STATUS not in d.features
): ):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s pushing device settings %s', d, d.settings) logger.info('%s pushing device settings %s', d, d.settings)
_settings.apply_all_settings(d) _settings.apply_all_settings(d)
else: else:
@ -314,19 +312,19 @@ class DeviceStatus(dict):
self.updated = timestamp self.updated = timestamp
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("device %d changed: active=%s %s", d.number, self._active, dict(self)) # logger.debug("device %d changed: active=%s %s", d.number, self._active, dict(self))
self._changed_callback(d, alert, reason) self._changed_callback(d, alert, reason)
# def poll(self, timestamp): # def poll(self, timestamp):
# d = self._device # d = self._device
# if not d: # if not d:
# _log.error("polling status of invalid device") # logger.error("polling status of invalid device")
# return # return
# #
# if self._active: # if self._active:
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("polling status of %s", d) # logger.debug("polling status of %s", d)
# #
# # read these from the device, the UI may need them later # # read these from the device, the UI may need them later
# d.protocol, d.serial, d.firmware, d.kind, d.name, d.settings, None # d.protocol, d.serial, d.firmware, d.kind, d.name, d.settings, None

View File

@ -17,15 +17,12 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse as _argparse import argparse as _argparse
import logging
import sys as _sys import sys as _sys
from logging import DEBUG as _DEBUG
from logging import getLogger
from solaar import NAME from solaar import NAME
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -114,12 +111,12 @@ def _receivers(dev_path=None):
continue continue
try: try:
r = Receiver.open(dev_info) r = Receiver.open(dev_info)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('[%s] => %s', dev_info.path, r) logger.debug('[%s] => %s', dev_info.path, r)
if r: if r:
yield r yield r
except Exception as e: except Exception as e:
_log.exception('opening ' + str(dev_info)) logger.exception('opening ' + str(dev_info))
_sys.exit('%s: error: %s' % (NAME, str(e))) _sys.exit('%s: error: %s' % (NAME, str(e)))
@ -131,12 +128,12 @@ def _receivers_and_devices(dev_path=None):
continue continue
try: try:
d = Device.open(dev_info) if dev_info.isDevice else Receiver.open(dev_info) d = Device.open(dev_info) if dev_info.isDevice else Receiver.open(dev_info)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('[%s] => %s', dev_info.path, d) logger.debug('[%s] => %s', dev_info.path, d)
if d is not None: if d is not None:
yield d yield d
except Exception as e: except Exception as e:
_log.exception('opening ' + str(dev_info)) logger.exception('opening ' + str(dev_info))
_sys.exit('%s: error: %s' % (NAME, str(e))) _sys.exit('%s: error: %s' % (NAME, str(e)))

View File

@ -17,12 +17,10 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import json as _json import json as _json
import logging
import os as _os import os as _os
import os.path as _path import os.path as _path
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import getLogger
from threading import Lock as _Lock from threading import Lock as _Lock
from threading import Timer as _Timer from threading import Timer as _Timer
@ -31,8 +29,7 @@ import yaml as _yaml
from logitech_receiver.common import NamedInt as _NamedInt from logitech_receiver.common import NamedInt as _NamedInt
from solaar import __version__ from solaar import __version__
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_XDG_CONFIG_HOME = _os.environ.get('XDG_CONFIG_HOME') or _path.expanduser(_path.join('~', '.config')) _XDG_CONFIG_HOME = _os.environ.get('XDG_CONFIG_HOME') or _path.expanduser(_path.join('~', '.config'))
_yaml_file_path = _path.join(_XDG_CONFIG_HOME, 'solaar', 'config.yaml') _yaml_file_path = _path.join(_XDG_CONFIG_HOME, 'solaar', 'config.yaml')
@ -57,19 +54,19 @@ def _load():
with open(_yaml_file_path) as config_file: with open(_yaml_file_path) as config_file:
loaded_config = _yaml.safe_load(config_file) loaded_config = _yaml.safe_load(config_file)
except Exception as e: except Exception as e:
_log.error('failed to load from %s: %s', _yaml_file_path, e) logger.error('failed to load from %s: %s', _yaml_file_path, e)
elif _path.isfile(_json_file_path): elif _path.isfile(_json_file_path):
path = _json_file_path path = _json_file_path
try: try:
with open(_json_file_path) as config_file: with open(_json_file_path) as config_file:
loaded_config = _json.load(config_file) loaded_config = _json.load(config_file)
except Exception as e: except Exception as e:
_log.error('failed to load from %s: %s', _json_file_path, e) logger.error('failed to load from %s: %s', _json_file_path, e)
loaded_config = _convert_json(loaded_config) loaded_config = _convert_json(loaded_config)
else: else:
path = None path = None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('load => %s', loaded_config) logger.debug('load => %s', loaded_config)
global _config global _config
_config = _parse_config(loaded_config, path) _config = _parse_config(loaded_config, path)
@ -84,8 +81,8 @@ def _parse_config(loaded_config, config_path):
loaded_version = loaded_config[0] loaded_version = loaded_config[0]
discard_derived_properties = loaded_version != current_version discard_derived_properties = loaded_version != current_version
if discard_derived_properties: if discard_derived_properties:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info( logger.info(
'config file \'%s\' was generated by another version of solaar ' 'config file \'%s\' was generated by another version of solaar '
'(config: %s, current: %s). refreshing detected device capabilities', config_path, loaded_version, '(config: %s, current: %s). refreshing detected device capabilities', config_path, loaded_version,
current_version current_version
@ -95,7 +92,7 @@ def _parse_config(loaded_config, config_path):
assert isinstance(device, dict) assert isinstance(device, dict)
parsed_config.append(_device_entry_from_config_dict(device, discard_derived_properties)) parsed_config.append(_device_entry_from_config_dict(device, discard_derived_properties))
except Exception as e: except Exception as e:
_log.warning('Exception processing config file \'%s\', ignoring contents: %s', config_path, e) logger.warning('Exception processing config file \'%s\', ignoring contents: %s', config_path, e)
return parsed_config return parsed_config
@ -138,7 +135,7 @@ def save(defer=False):
try: try:
_os.makedirs(dirname) _os.makedirs(dirname)
except Exception: except Exception:
_log.error('failed to create %s', dirname) logger.error('failed to create %s', dirname)
return return
if not defer or not defer_saves: if not defer or not defer_saves:
do_save() do_save()
@ -159,10 +156,10 @@ def do_save():
try: try:
with open(_yaml_file_path, 'w') as config_file: with open(_yaml_file_path, 'w') as config_file:
_yaml.dump(_config, config_file, default_flow_style=None, width=150) _yaml.dump(_config, config_file, default_flow_style=None, width=150)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('saved %s to %s', _config, _yaml_file_path) logger.info('saved %s to %s', _config, _yaml_file_path)
except Exception as e: except Exception as e:
_log.error('failed to save to %s: %s', _yaml_file_path, e) logger.error('failed to save to %s: %s', _yaml_file_path, e)
def _convert_json(json_dict): def _convert_json(json_dict):
@ -256,11 +253,11 @@ def persister(device):
break break
if not entry: if not entry:
if not device.online and not device.serial: # don't create entry for offline devices without serial number if not device.online and not device.serial: # don't create entry for offline devices without serial number
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('not setting up persister for offline device %s with missing serial number', device.name) logger.info('not setting up persister for offline device %s with missing serial number', device.name)
return return
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('setting up persister for device %s', device.name) logger.info('setting up persister for device %s', device.name)
entry = _DeviceEntry() entry = _DeviceEntry()
_config.append(entry) _config.append(entry)
entry.update(device, modelId) entry.update(device, modelId)

View File

@ -26,15 +26,12 @@ import signal
import sys import sys
import tempfile import tempfile
from logging import INFO as _INFO
from logging import WARNING as _WARNING
import solaar.cli as _cli import solaar.cli as _cli
import solaar.i18n as _i18n import solaar.i18n as _i18n
from solaar import NAME, __version__ from solaar import NAME, __version__
_log = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# #
# #
@ -117,8 +114,8 @@ def _parse_arguments():
logging.getLogger('').addHandler(stream_handler) logging.getLogger('').addHandler(stream_handler)
if not args.action: if not args.action:
if _log.isEnabledFor(logging.INFO): if logger.isEnabledFor(logging.INFO):
logging.info('version %s, language %s (%s)', __version__, _i18n.language, _i18n.encoding) logger.info('version %s, language %s (%s)', __version__, _i18n.language, _i18n.encoding)
return args return args
@ -130,7 +127,7 @@ def _handlesig(signl, stack):
signal.signal(signal.SIGTERM, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL)
if signl == int(signal.SIGINT): if signl == int(signal.SIGINT):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
faulthandler.dump_traceback() faulthandler.dump_traceback()
sys.exit('%s: exit due to keyboard interrupt' % (NAME.lower())) sys.exit('%s: exit due to keyboard interrupt' % (NAME.lower()))
else: else:
@ -157,12 +154,12 @@ def main():
signal.signal(signal.SIGTERM, _handlesig) signal.signal(signal.SIGTERM, _handlesig)
udev_file = '42-logitech-unify-permissions.rules' udev_file = '42-logitech-unify-permissions.rules'
if _log.isEnabledFor(_WARNING) \ if logger.isEnabledFor(logging.WARNING) \
and not os.path.isfile('/etc/udev/rules.d/' + udev_file) \ and not os.path.isfile('/etc/udev/rules.d/' + udev_file) \
and not os.path.isfile('/usr/lib/udev/rules.d/' + udev_file) \ and not os.path.isfile('/usr/lib/udev/rules.d/' + udev_file) \
and not os.path.isfile('/usr/local/lib/udev/rules.d/' + udev_file): and not os.path.isfile('/usr/local/lib/udev/rules.d/' + udev_file):
_log.warning('Solaar udev file not found in expected location') logger.warning('Solaar udev file not found in expected location')
_log.warning('See https://pwr-solaar.github.io/Solaar/installation for more information') logger.warning('See https://pwr-solaar.github.io/Solaar/installation for more information')
try: try:
import solaar.listener as listener import solaar.listener as listener
import solaar.ui as ui import solaar.ui as ui

View File

@ -17,13 +17,10 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import errno as _errno import errno as _errno
import logging
import time import time
from collections import namedtuple from collections import namedtuple
from logging import DEBUG as _DEBUG
from logging import INFO as _INFO
from logging import WARNING as _WARNING
from logging import getLogger
import gi import gi
@ -41,8 +38,7 @@ from gi.repository import GLib # NOQA: E402 # isort:skip
# from solaar.i18n import _ # from solaar.i18n import _
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
_R = _hidpp10.REGISTERS _R = _hidpp10.REGISTERS
_IR = _hidpp10.INFO_SUBREGISTERS _IR = _hidpp10.INFO_SUBREGISTERS
@ -87,12 +83,12 @@ class ReceiverListener(_listener.EventsListener):
_status.attach_to(receiver, self._status_changed) _status.attach_to(receiver, self._status_changed)
def has_started(self): def has_started(self):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: notifications listener has started (%s)', self.receiver, self.receiver.handle) logger.info('%s: notifications listener has started (%s)', self.receiver, self.receiver.handle)
nfs = self.receiver.enable_connection_notifications() nfs = self.receiver.enable_connection_notifications()
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
if not self.receiver.isDevice and not ((nfs if nfs else 0) & _hidpp10.NOTIFICATION_FLAG.wireless): if not self.receiver.isDevice and not ((nfs if nfs else 0) & _hidpp10.NOTIFICATION_FLAG.wireless):
_log.warning( logger.warning(
'Receiver on %s might not support connection notifications, GUI might not show its devices', 'Receiver on %s might not support connection notifications, GUI might not show its devices',
self.receiver.path self.receiver.path
) )
@ -103,8 +99,8 @@ class ReceiverListener(_listener.EventsListener):
def has_stopped(self): def has_stopped(self):
r, self.receiver = self.receiver, None r, self.receiver = self.receiver, None
assert r is not None assert r is not None
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: notifications listener has stopped', r) logger.info('%s: notifications listener has stopped', r)
# because udev is not notifying us about device removal, # because udev is not notifying us about device removal,
# make sure to clean up in _all_listeners # make sure to clean up in _all_listeners
@ -115,7 +111,7 @@ class ReceiverListener(_listener.EventsListener):
try: try:
r.close() r.close()
except Exception: except Exception:
_log.exception('closing receiver %s' % r.path) logger.exception('closing receiver %s' % r.path)
self.status_changed_callback(r) # , _status.ALERT.NOTIFICATION) self.status_changed_callback(r) # , _status.ALERT.NOTIFICATION)
# def tick(self, timestamp): # def tick(self, timestamp):
@ -126,7 +122,7 @@ class ReceiverListener(_listener.EventsListener):
# # if self._last_tick > 0 and timestamp - self._last_tick > _POLL_TICK * 2: # # if self._last_tick > 0 and timestamp - self._last_tick > _POLL_TICK * 2:
# # # if we missed a couple of polls, most likely the computer went into # # # if we missed a couple of polls, most likely the computer went into
# # # sleep, and we have to reinitialize the receiver again # # # sleep, and we have to reinitialize the receiver again
# # _log.warn("%s: possible sleep detected, closing this listener", self.receiver) # # logger.warning("%s: possible sleep detected, closing this listener", self.receiver)
# # self.stop() # # self.stop()
# # return # # return
# #
@ -153,25 +149,25 @@ class ReceiverListener(_listener.EventsListener):
# if dev and dev.status is not None: # if dev and dev.status is not None:
# dev.status.poll(timestamp) # dev.status.poll(timestamp)
# except Exception as e: # except Exception as e:
# _log.exception("polling", e) # logger.exception("polling", e)
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None): def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
assert device is not None assert device is not None
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
try: try:
device.ping() device.ping()
if device.kind is None: if device.kind is None:
_log.info( logger.info(
'status_changed %r: %s, %s (%X) %s', device, 'present' if bool(device) else 'removed', device.status, 'status_changed %r: %s, %s (%X) %s', device, 'present' if bool(device) else 'removed', device.status,
alert, reason or '' alert, reason or ''
) )
else: else:
_log.info( logger.info(
'status_changed %r: %s %s, %s (%X) %s', device, 'paired' if bool(device) else 'unpaired', 'status_changed %r: %s %s, %s (%X) %s', device, 'paired' if bool(device) else 'unpaired',
'online' if device.online else 'offline', device.status, alert, reason or '' 'online' if device.online else 'offline', device.status, alert, reason or ''
) )
except Exception: except Exception:
_log.info('status_changed for unknown device') logger.info('status_changed for unknown device')
if device.kind is None: if device.kind is None:
assert device == self.receiver assert device == self.receiver
@ -184,8 +180,8 @@ class ReceiverListener(_listener.EventsListener):
# Device was unpaired, and isn't valid anymore. # Device was unpaired, and isn't valid anymore.
# We replace it with a ghost so that the UI has something to work # We replace it with a ghost so that the UI has something to work
# with while cleaning up. # with while cleaning up.
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('device %s was unpaired, ghosting', device) logger.info('device %s was unpaired, ghosting', device)
device = _ghost(device) device = _ghost(device)
self.status_changed_callback(device, alert, reason) self.status_changed_callback(device, alert, reason)
@ -197,8 +193,8 @@ class ReceiverListener(_listener.EventsListener):
def _notifications_handler(self, n): def _notifications_handler(self, n):
assert self.receiver assert self.receiver
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("%s: handling %s", self.receiver, n) # logger.debug("%s: handling %s", self.receiver, n)
if n.devnumber == 0xFF: if n.devnumber == 0xFF:
# a receiver notification # a receiver notification
_notifications.process(self.receiver, n) _notifications.process(self.receiver, n)
@ -206,20 +202,20 @@ class ReceiverListener(_listener.EventsListener):
# a notification that came in to the device listener - strange, but nothing needs to be done here # a notification that came in to the device listener - strange, but nothing needs to be done here
if self.receiver.isDevice: if self.receiver.isDevice:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('Notification %s via device %s being ignored.', n, self.receiver) logger.debug('Notification %s via device %s being ignored.', n, self.receiver)
return return
# DJ pairing notification - ignore - hid++ 1.0 pairing notification is all that is needed # DJ pairing notification - ignore - hid++ 1.0 pairing notification is all that is needed
if n.sub_id == 0x41 and n.report_id == _base.DJ_MESSAGE_ID: if n.sub_id == 0x41 and n.report_id == _base.DJ_MESSAGE_ID:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('ignoring DJ pairing notification %s', n) logger.info('ignoring DJ pairing notification %s', n)
return return
# a device notification # a device notification
if not (0 < n.devnumber <= 16): # some receivers have devices past their max # devices if not (0 < n.devnumber <= 16): # some receivers have devices past their max # devices
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warning('Unexpected device number (%s) in notification %s.', n.devnumber, n) logger.warning('Unexpected device number (%s) in notification %s.', n.devnumber, n)
return return
already_known = n.devnumber in self.receiver already_known = n.devnumber in self.receiver
@ -255,17 +251,17 @@ class ReceiverListener(_listener.EventsListener):
dev = self.receiver[n.devnumber] dev = self.receiver[n.devnumber]
if not dev: if not dev:
_log.warn('%s: received %s for invalid device %d: %r', self.receiver, n, n.devnumber, dev) logger.warning('%s: received %s for invalid device %d: %r', self.receiver, n, n.devnumber, dev)
return return
# Apply settings every time the device connects # Apply settings every time the device connects
if n.sub_id == 0x41: if n.sub_id == 0x41:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
try: try:
dev.ping() dev.ping()
_log.info('connection %s for %r', n, dev) logger.info('connection %s for %r', n, dev)
except Exception: except Exception:
_log.info('connection %s for unknown device, number %s', n, n.devnumber) logger.info('connection %s for unknown device, number %s', n, n.devnumber)
# If there are saved configs, bring the device's settings up-to-date. # If there are saved configs, bring the device's settings up-to-date.
# They will be applied when the device is marked as online. # They will be applied when the device is marked as online.
configuration.attach_to(dev) configuration.attach_to(dev)
@ -275,15 +271,15 @@ class ReceiverListener(_listener.EventsListener):
if not hasattr(dev, 'status') or dev.status is None: if not hasattr(dev, 'status') or dev.status is None:
# notification before device status set up - don't process it # notification before device status set up - don't process it
_log.warn('%s before device %s has status', n, dev) logger.warning('%s before device %s has status', n, dev)
else: else:
_notifications.process(dev, n) _notifications.process(dev, n)
if self.receiver.status.lock_open and not already_known: if self.receiver.status.lock_open and not already_known:
# this should be the first notification after a device was paired # this should be the first notification after a device was paired
assert n.sub_id == 0x41, 'first notification was not a connection notification' assert n.sub_id == 0x41, 'first notification was not a connection notification'
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('%s: pairing detected new device', self.receiver) logger.info('%s: pairing detected new device', self.receiver)
self.receiver.status.new_device = dev self.receiver.status.new_device = dev
elif dev.online is None: elif dev.online is None:
dev.ping() dev.ping()
@ -316,15 +312,15 @@ def _start(device_info):
_all_listeners[device_info.path] = rl _all_listeners[device_info.path] = rl
return rl return rl
_log.warn('failed to open %s', device_info) logger.warning('failed to open %s', device_info)
def start_all(): def start_all():
# just in case this it called twice in a row... # just in case this it called twice in a row...
stop_all() stop_all()
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('starting receiver listening threads') logger.info('starting receiver listening threads')
for device_info in _base.receivers_and_devices(): for device_info in _base.receivers_and_devices():
_process_receiver_event('add', device_info) _process_receiver_event('add', device_info)
@ -334,8 +330,8 @@ def stop_all():
_all_listeners.clear() _all_listeners.clear()
if listeners: if listeners:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('stopping receiver listening threads %s', listeners) logger.info('stopping receiver listening threads %s', listeners)
for l in listeners: for l in listeners:
l.stop() l.stop()
@ -351,8 +347,8 @@ def stop_all():
# after a resume, the device may have been off # after a resume, the device may have been off
# so mark its saved status to ensure that the status is pushed to the device when it comes back # so mark its saved status to ensure that the status is pushed to the device when it comes back
def ping_all(resuming=False): def ping_all(resuming=False):
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('ping all devices%s', ' when resuming' if resuming else '') logger.info('ping all devices%s', ' when resuming' if resuming else '')
for l in _all_listeners.values(): for l in _all_listeners.values():
if l.receiver.isDevice: if l.receiver.isDevice:
if resuming and hasattr(l.receiver, 'status'): if resuming and hasattr(l.receiver, 'status'):
@ -396,8 +392,8 @@ def _process_add(device_info, retry):
try: try:
import subprocess import subprocess
output = subprocess.check_output(['/usr/bin/getfacl', '-p', device_info.path], text=True) output = subprocess.check_output(['/usr/bin/getfacl', '-p', device_info.path], text=True)
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warning('Missing permissions on %s\n%s.', device_info.path, output) logger.warning('Missing permissions on %s\n%s.', device_info.path, output)
except Exception: except Exception:
pass pass
if retry: if retry:
@ -416,8 +412,8 @@ def _process_receiver_event(action, device_info):
assert device_info is not None assert device_info is not None
assert _error_callback assert _error_callback
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('receiver event %s %s', action, device_info) logger.info('receiver event %s %s', action, device_info)
# whatever the action, stop any previous receivers at this path # whatever the action, stop any previous receivers at this path
l = _all_listeners.pop(device_info.path, None) l = _all_listeners.pop(device_info.path, None)

View File

@ -18,12 +18,11 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import getLogger
from threading import Thread as _Thread from threading import Thread as _Thread
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
try: try:
from Queue import Queue as _Queue from Queue import Queue as _Queue
@ -54,8 +53,8 @@ class TaskRunner(_Thread):
def run(self): def run(self):
self.alive = True self.alive = True
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('started') logger.debug('started')
while self.alive: while self.alive:
task = self.queue.get() task = self.queue.get()
@ -65,7 +64,7 @@ class TaskRunner(_Thread):
try: try:
function(*args, **kwargs) function(*args, **kwargs)
except Exception: except Exception:
_log.exception('calling %s', function) logger.exception('calling %s', function)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('stopped') logger.debug('stopped')

View File

@ -16,9 +16,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import INFO as _INFO
from logging import getLogger
import yaml as _yaml import yaml as _yaml
@ -29,8 +27,7 @@ from gi.repository import GLib, Gtk, Gio # NOQA: E402 # isort:skip
from logitech_receiver.status import ALERT # NOQA: E402 # isort:skip from logitech_receiver.status import ALERT # NOQA: E402 # isort:skip
from solaar.i18n import _ # NOQA: E402 # isort:skip from solaar.i18n import _ # NOQA: E402 # isort:skip
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -46,7 +43,7 @@ GLib.threads_init()
def _error_dialog(reason, object): def _error_dialog(reason, object):
_log.error('error: %s %s', reason, object) logger.error('error: %s %s', reason, object)
if reason == 'permissions': if reason == 'permissions':
title = _('Permissions error') title = _('Permissions error')
@ -103,8 +100,8 @@ from . import diversion_rules, notify, tray, window # isort:skip # noqa: E402
def _startup(app, startup_hook, use_tray, show_window): def _startup(app, startup_hook, use_tray, show_window):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('startup registered=%s, remote=%s', app.get_is_registered(), app.get_is_remote()) logger.debug('startup registered=%s, remote=%s', app.get_is_registered(), app.get_is_remote())
from solaar.tasks import TaskRunner as _TaskRunner from solaar.tasks import TaskRunner as _TaskRunner
global _task_runner global _task_runner
@ -120,8 +117,8 @@ def _startup(app, startup_hook, use_tray, show_window):
def _activate(app): def _activate(app):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('activate') logger.debug('activate')
if app.get_windows(): if app.get_windows():
window.popup() window.popup()
else: else:
@ -134,8 +131,8 @@ def _command_line(app, command_line):
if not args: if not args:
_activate(app) _activate(app)
elif args[0] == 'config': # config call from remote instance elif args[0] == 'config': # config call from remote instance
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('remote command line %s', args) logger.info('remote command line %s', args)
from solaar.ui.config_panel import change_setting # prevent circular import from solaar.ui.config_panel import change_setting # prevent circular import
from solaar.ui.window import find_device # prevent circular import from solaar.ui.window import find_device # prevent circular import
dev = find_device(args[1]) dev = find_device(args[1])
@ -147,8 +144,8 @@ def _command_line(app, command_line):
def _shutdown(app, shutdown_hook): def _shutdown(app, shutdown_hook):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('shutdown') logger.debug('shutdown')
shutdown_hook() shutdown_hook()
@ -185,8 +182,8 @@ def run_loop(startup_hook, shutdown_hook, use_tray, show_window):
def _status_changed(device, alert, reason, refresh=False): def _status_changed(device, alert, reason, refresh=False):
assert device is not None assert device is not None
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('status changed: %s (%s) %s', device, alert, reason) logger.debug('status changed: %s (%s) %s', device, alert, reason)
tray.update(device) tray.update(device)
if alert & ALERT.ATTENTION: if alert & ALERT.ATTENTION:

View File

@ -34,7 +34,7 @@ def _create():
about.set_program_name(NAME) about.set_program_name(NAME)
about.set_version(__version__) about.set_version(__version__)
about.set_comments(_('Manages Logitech receivers,\nkeyboards, mice, and tablets.')) about.set_comments(_('Manages Logitech receivers,\nkeyboards, mice, and tablets.'))
about.set_logo_icon_name(NAME.lower()) about.setloggero_icon_name(NAME.lower())
about.set_copyright('© 2012-2023 Daniel Pavel and contributors to the Solaar project') about.set_copyright('© 2012-2023 Daniel Pavel and contributors to the Solaar project')
about.set_license_type(Gtk.License.GPL_2_0) about.set_license_type(Gtk.License.GPL_2_0)

View File

@ -22,9 +22,8 @@ from solaar.i18n import _
from ..ui import error_dialog from ..ui import error_dialog
from . import pair_window from . import pair_window
# from logging import getLogger # import logging
# _log = getLogger(__name__) # logger = logging.getLogger(__name__)
# del getLogger
# #
# #
@ -97,5 +96,5 @@ def unpair(window, device):
try: try:
del receiver[device_number] del receiver[device_number]
except Exception: except Exception:
# _log.exception("unpairing %s", device) # logger.exception("unpairing %s", device)
error_dialog('unpair', device) error_dialog('unpair', device)

View File

@ -16,11 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
import traceback import traceback
from logging import DEBUG as _DEBUG
from logging import WARNING as _WARNING
from logging import getLogger
from threading import Timer as _Timer from threading import Timer as _Timer
from gi.repository import Gdk, GLib, Gtk from gi.repository import Gdk, GLib, Gtk
@ -30,8 +28,7 @@ from logitech_receiver.settings import SENSITIVITY_IGNORE as _SENSITIVITY_IGNORE
from solaar.i18n import _, ngettext from solaar.i18n import _, ngettext
from solaar.ui import ui_async as _ui_async from solaar.ui import ui_async as _ui_async
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -695,8 +692,8 @@ def _create_sbox(s, device):
elif s.kind == _SETTING_KIND.hetero: elif s.kind == _SETTING_KIND.hetero:
control = HeteroKeyControl(sbox, change) control = HeteroKeyControl(sbox, change)
else: else:
if _log.isEnabledFor(_WARNING): if logger.isEnabledFor(logging.WARNING):
_log.warn('setting %s display not implemented', s.label) logger.warning('setting %s display not implemented', s.label)
return None return None
control.set_sensitive(False) # the first read will enable it control.set_sensitive(False) # the first read will enable it
@ -828,8 +825,8 @@ def record_setting(device, setting, values):
def _record_setting(device, setting, values): def _record_setting(device, setting, values):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('on %s changing setting %s to %s', device, setting, values) logger.debug('on %s changing setting %s to %s', device, setting, values)
if len(values) > 1: if len(values) > 1:
setting.update_key_value(values[0], values[-1]) setting.update_key_value(values[0], values[-1])
value = {values[0]: values[-1]} value = {values[0]: values[-1]}

View File

@ -15,6 +15,7 @@
## You should have received a copy of the GNU General Public License along ## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
import string import string
import threading import threading
@ -22,7 +23,6 @@ from collections import defaultdict, namedtuple
from contextlib import contextmanager as contextlib_contextmanager from contextlib import contextmanager as contextlib_contextmanager
from copy import copy from copy import copy
from dataclasses import dataclass, field from dataclasses import dataclass, field
from logging import getLogger
from shlex import quote as shlex_quote from shlex import quote as shlex_quote
from typing import Dict from typing import Dict
@ -40,8 +40,7 @@ from logitech_receiver.settings_templates import SETTINGS as _SETTINGS
from logitech_receiver.special_keys import CONTROL as _CONTROL from logitech_receiver.special_keys import CONTROL as _CONTROL
from solaar.i18n import _ from solaar.i18n import _
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -2190,7 +2189,7 @@ def _all_settings():
prev_setting = settings[s.name][0] prev_setting = settings[s.name][0]
prev_kind = prev_setting.validator_class.kind prev_kind = prev_setting.validator_class.kind
if prev_kind != s.validator_class.kind: if prev_kind != s.validator_class.kind:
_log.warning( logger.warning(
'ignoring setting {} - same name of {}, but different kind ({} != {})'.format( 'ignoring setting {} - same name of {}, but different kind ({} != {})'.format(
s.__name__, prev_setting.__name__, prev_kind, s.validator_class.kind s.__name__, prev_setting.__name__, prev_kind, s.validator_class.kind
) )

View File

@ -16,15 +16,13 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import getLogger
import solaar.gtk as gtk import solaar.gtk as gtk
from gi.repository import Gtk from gi.repository import Gtk
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -47,18 +45,18 @@ def _init_icon_paths():
return return
_default_theme = Gtk.IconTheme.get_default() _default_theme = Gtk.IconTheme.get_default()
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('icon theme paths: %s', _default_theme.get_search_path()) logger.debug('icon theme paths: %s', _default_theme.get_search_path())
if gtk.battery_icons_style == 'symbolic': if gtk.battery_icons_style == 'symbolic':
global TRAY_OKAY global TRAY_OKAY
TRAY_OKAY = TRAY_INIT # use monochrome tray icon TRAY_OKAY = TRAY_INIT # use monochrome tray icon
if not _default_theme.has_icon('battery-good-symbolic'): if not _default_theme.has_icon('battery-good-symbolic'):
_log.warning('failed to detect symbolic icons') logger.warning('failed to detect symbolic icons')
gtk.battery_icons_style = 'regular' gtk.battery_icons_style = 'regular'
if gtk.battery_icons_style == 'regular': if gtk.battery_icons_style == 'regular':
if not _default_theme.has_icon('battery-good'): if not _default_theme.has_icon('battery-good'):
_log.warning('failed to detect icons') logger.warning('failed to detect icons')
gtk.battery_icons_style = 'solaar' gtk.battery_icons_style = 'solaar'
@ -70,10 +68,10 @@ def _init_icon_paths():
def battery(level=None, charging=False): def battery(level=None, charging=False):
icon_name = _battery_icon_name(level, charging) icon_name = _battery_icon_name(level, charging)
if not _default_theme.has_icon(icon_name): if not _default_theme.has_icon(icon_name):
_log.warning('icon %s not found in current theme', icon_name) logger.warning('icon %s not found in current theme', icon_name)
return TRAY_OKAY # use Solaar icon if battery icon not available return TRAY_OKAY # use Solaar icon if battery icon not available
elif _log.isEnabledFor(_DEBUG): elif logger.isEnabledFor(logging.DEBUG):
_log.debug('battery icon for %s:%s = %s', level, charging, icon_name) logger.debug('battery icon for %s:%s = %s', level, charging, icon_name)
return icon_name return icon_name
@ -172,8 +170,8 @@ def icon_file(name, size=_LARGE_SIZE):
theme_icon = _default_theme.lookup_icon(name, size, 0) theme_icon = _default_theme.lookup_icon(name, size, 0)
if theme_icon: if theme_icon:
file_name = theme_icon.get_filename() file_name = theme_icon.get_filename()
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("icon %s(%d) => %s", name, size, file_name) # logger.debug("icon %s(%d) => %s", name, size, file_name)
return file_name return file_name
_log.warn('icon %s(%d) not found in current theme', name, size) logger.warning('icon %s(%d) not found in current theme', name, size)

View File

@ -37,10 +37,8 @@ except (ValueError, ImportError):
available = False available = False
if available: if available:
from logging import INFO as _INFO import logging
from logging import getLogger logger = logging.getLogger(__name__)
_log = getLogger(__name__)
del getLogger
from solaar import NAME from solaar import NAME
@ -55,19 +53,19 @@ if available:
global available global available
if available: if available:
if not Notify.is_initted(): if not Notify.is_initted():
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('starting desktop notifications') logger.info('starting desktop notifications')
try: try:
return Notify.init(NAME) return Notify.init(NAME)
except Exception: except Exception:
_log.exception('initializing desktop notifications') logger.exception('initializing desktop notifications')
available = False available = False
return available and Notify.is_initted() return available and Notify.is_initted()
def uninit(): def uninit():
if available and Notify.is_initted(): if available and Notify.is_initted():
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('stopping desktop notifications') logger.info('stopping desktop notifications')
_notifications.clear() _notifications.clear()
Notify.uninit() Notify.uninit()
@ -96,11 +94,11 @@ if available:
n.set_hint('desktop-entry', GLib.Variant('s', NAME.lower())) n.set_hint('desktop-entry', GLib.Variant('s', NAME.lower()))
try: try:
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("showing %s", n) # logger.debug("showing %s", n)
n.show() n.show()
except Exception: except Exception:
_log.exception('showing %s', n) logger.exception('showing %s', n)
def show(dev, reason=None, icon=None, progress=None): def show(dev, reason=None, icon=None, progress=None):
"""Show a notification with title and text. """Show a notification with title and text.
@ -135,11 +133,11 @@ if available:
n.set_hint('value', GLib.Variant('i', progress)) n.set_hint('value', GLib.Variant('i', progress))
try: try:
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("showing %s", n) # logger.debug("showing %s", n)
n.show() n.show()
except Exception: except Exception:
_log.exception('showing %s', n) logger.exception('showing %s', n)
else: else:
init = lambda: False init = lambda: False

View File

@ -16,8 +16,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import getLogger
from gi.repository import GLib, Gtk from gi.repository import GLib, Gtk
from logitech_receiver import hidpp10 as _hidpp10 from logitech_receiver import hidpp10 as _hidpp10
@ -26,8 +25,7 @@ from solaar.i18n import _, ngettext
from . import icons as _icons from . import icons as _icons
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# #
@ -71,8 +69,8 @@ def _check_lock_state(assistant, receiver, count=2):
global address, kind, authentication, name, passcode global address, kind, authentication, name, passcode
if not assistant.is_drawable(): if not assistant.is_drawable():
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('assistant %s destroyed, bailing out', assistant) logger.debug('assistant %s destroyed, bailing out', assistant)
return False return False
if receiver.status.get(_K.ERROR): if receiver.status.get(_K.ERROR):
@ -115,8 +113,8 @@ def _check_lock_state(assistant, receiver, count=2):
def _show_passcode(assistant, receiver, passkey): def _show_passcode(assistant, receiver, passkey):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s show passkey: %s', receiver, passkey) logger.debug('%s show passkey: %s', receiver, passkey)
name = receiver.status.device_name name = receiver.status.device_name
authentication = receiver.status.device_authentication authentication = receiver.status.device_authentication
intro_text = _('%(receiver_name)s: pair new device') % {'receiver_name': receiver.name} intro_text = _('%(receiver_name)s: pair new device') % {'receiver_name': receiver.name}
@ -136,8 +134,8 @@ def _show_passcode(assistant, receiver, passkey):
def _prepare(assistant, page, receiver): def _prepare(assistant, page, receiver):
index = assistant.get_current_page() index = assistant.get_current_page()
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('prepare %s %d %s', assistant, index, page) logger.debug('prepare %s %d %s', assistant, index, page)
if index == 0: if index == 0:
if receiver.receiver_kind == 'bolt': if receiver.receiver_kind == 'bolt':
@ -164,8 +162,8 @@ def _prepare(assistant, page, receiver):
def _finish(assistant, receiver): def _finish(assistant, receiver):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('finish %s', assistant) logger.debug('finish %s', assistant)
assistant.destroy() assistant.destroy()
receiver.status.new_device = None receiver.status.new_device = None
if receiver.status.lock_open: if receiver.status.lock_open:
@ -180,8 +178,8 @@ def _finish(assistant, receiver):
def _pairing_failed(assistant, receiver, error): def _pairing_failed(assistant, receiver, error):
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s fail: %s', receiver, error) logger.debug('%s fail: %s', receiver, error)
assistant.commit() assistant.commit()
@ -202,8 +200,8 @@ def _pairing_failed(assistant, receiver, error):
def _pairing_succeeded(assistant, receiver, device): def _pairing_succeeded(assistant, receiver, device):
assert device assert device
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('%s success: %s', receiver, device) logger.debug('%s success: %s', receiver, device)
page = _create_page(assistant, Gtk.AssistantPageType.SUMMARY) page = _create_page(assistant, Gtk.AssistantPageType.SUMMARY)

View File

@ -16,10 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import logging
import os import os
from logging import DEBUG as _DEBUG
from logging import getLogger
from time import time as _timestamp from time import time as _timestamp
import solaar.gtk as gtk import solaar.gtk as gtk
@ -35,8 +34,7 @@ from .about import show_window as _show_about_window
from .window import popup as _window_popup from .window import popup as _window_popup
from .window import toggle as _window_toggle from .window import toggle as _window_toggle
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# constants # constants
@ -95,8 +93,8 @@ def _scroll(tray_icon, event, direction=None):
return return
_last_scroll = now _last_scroll = now
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("scroll direction %s", direction) # logger.debug("scroll direction %s", direction)
global _picked_device global _picked_device
candidate = None candidate = None
@ -141,8 +139,8 @@ def _scroll(tray_icon, event, direction=None):
_picked_device = None _picked_device = None
_picked_device = candidate or _picked_device _picked_device = candidate or _picked_device
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('scroll: picked %s', _picked_device) logger.debug('scroll: picked %s', _picked_device)
_update_tray_icon() _update_tray_icon()
@ -161,8 +159,8 @@ try:
# treat unavailable versions the same as unavailable packages # treat unavailable versions the same as unavailable packages
raise ImportError raise ImportError
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('using %sAppIndicator3' % ('Ayatana ' if ayatana_appindicator_found else '')) logger.debug('using %sAppIndicator3' % ('Ayatana ' if ayatana_appindicator_found else ''))
# Defense against AppIndicator3 bug that treats files in current directory as icon files # Defense against AppIndicator3 bug that treats files in current directory as icon files
# https://bugs.launchpad.net/ubuntu/+source/libappindicator/+bug/1363277 # https://bugs.launchpad.net/ubuntu/+source/libappindicator/+bug/1363277
@ -228,8 +226,8 @@ try:
except ImportError: except ImportError:
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('using StatusIcon') logger.debug('using StatusIcon')
def _create(menu): def _create(menu):
icon = Gtk.StatusIcon.new_from_icon_name(_icons.TRAY_INIT) icon = Gtk.StatusIcon.new_from_icon_name(_icons.TRAY_INIT)
@ -339,8 +337,8 @@ def _pick_device_with_lowest_battery():
picked = info picked = info
picked_level = level or 0 picked_level = level or 0
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('picked device with lowest battery: %s', picked) logger.debug('picked device with lowest battery: %s', picked)
return picked return picked
@ -424,7 +422,7 @@ def _remove_receiver(receiver):
def _update_menu_item(index, device): def _update_menu_item(index, device):
if device is None or device.status is None: if device is None or device.status is None:
_log.warn('updating an inactive device %s, assuming disconnected', device) logger.warning('updating an inactive device %s, assuming disconnected', device)
return None return None
menu_items = _menu.get_children() menu_items = _menu.get_children()

View File

@ -16,8 +16,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import DEBUG as _DEBUG import logging
from logging import getLogger
from gi.repository import Gdk, GLib, Gtk from gi.repository import Gdk, GLib, Gtk
from gi.repository.GObject import TYPE_PYOBJECT from gi.repository.GObject import TYPE_PYOBJECT
@ -36,8 +35,7 @@ from . import icons as _icons
from .about import show_window as _show_about_window from .about import show_window as _show_about_window
from .diversion_rules import show_window as _show_diversion_window from .diversion_rules import show_window as _show_diversion_window
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# constants # constants
@ -387,8 +385,8 @@ def _find_selected_device_id():
def _device_selected(selection): def _device_selected(selection):
model, item = selection.get_selected() model, item = selection.get_selected()
device = model.get_value(item, _COLUMN.DEVICE) if item else None device = model.get_value(item, _COLUMN.DEVICE) if item else None
# if _log.isEnabledFor(_DEBUG): # if logger.isEnabledFor(logging.DEBUG):
# _log.debug("window tree selected device %s", device) # logger.debug("window tree selected device %s", device)
if device: if device:
_update_info_panel(device, full=True) _update_info_panel(device, full=True)
else: else:
@ -418,8 +416,8 @@ def _receiver_row(receiver_path, receiver=None):
status_icon = None status_icon = None
row_data = (receiver_path, 0, True, receiver.name, icon_name, status_text, status_icon, receiver) row_data = (receiver_path, 0, True, receiver.name, icon_name, status_text, status_icon, receiver)
assert len(row_data) == len(_TREE_SEPATATOR) assert len(row_data) == len(_TREE_SEPATATOR)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('new receiver row %s', row_data) logger.debug('new receiver row %s', row_data)
item = _model.append(None, row_data) item = _model.append(None, row_data)
if _TREE_SEPATATOR: if _TREE_SEPATATOR:
_model.append(None, _TREE_SEPATATOR) _model.append(None, _TREE_SEPATATOR)
@ -443,7 +441,7 @@ def _device_row(receiver_path, device_number, device=None):
new_child_index = 0 new_child_index = 0
while item: while item:
if _model.get_value(item, _COLUMN.PATH) != receiver_path: if _model.get_value(item, _COLUMN.PATH) != receiver_path:
_log.warn( logger.warning(
'path for device row %s different from path for receiver %s', _model.get_value(item, _COLUMN.PATH), 'path for device row %s different from path for receiver %s', _model.get_value(item, _COLUMN.PATH),
receiver_path receiver_path
) )
@ -464,8 +462,8 @@ def _device_row(receiver_path, device_number, device=None):
receiver_path, device_number, bool(device.online), device.codename, icon_name, status_text, status_icon, device receiver_path, device_number, bool(device.online), device.codename, icon_name, status_text, status_icon, device
) )
assert len(row_data) == len(_TREE_SEPATATOR) assert len(row_data) == len(_TREE_SEPATATOR)
if _log.isEnabledFor(_DEBUG): if logger.isEnabledFor(logging.DEBUG):
_log.debug('new device row %s at index %d', row_data, new_child_index) logger.debug('new device row %s at index %d', row_data, new_child_index)
item = _model.insert(receiver_row, new_child_index, row_data) item = _model.insert(receiver_row, new_child_index, row_data)
return item or None return item or None
@ -487,7 +485,7 @@ def select(receiver_path, device_number=None):
selection = _tree.get_selection() selection = _tree.get_selection()
selection.select_iter(item) selection.select_iter(item)
else: else:
_log.warn('select(%s, %s) failed to find an item', receiver_path, device_number) logger.warning('select(%s, %s) failed to find an item', receiver_path, device_number)
def _hide(w, _ignore=None): def _hide(w, _ignore=None):

View File

@ -16,11 +16,9 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from logging import INFO as _INFO import logging
from logging import getLogger
_log = getLogger(__name__) logger = logging.getLogger(__name__)
del getLogger
# #
# As suggested here: http://stackoverflow.com/a/13548984 # As suggested here: http://stackoverflow.com/a/13548984
@ -31,8 +29,8 @@ _suspend_callback = None
def _suspend(): def _suspend():
if _suspend_callback: if _suspend_callback:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('received suspend event') logger.info('received suspend event')
_suspend_callback() _suspend_callback()
@ -41,8 +39,8 @@ _resume_callback = None
def _resume(): def _resume():
if _resume_callback: if _resume_callback:
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('received resume event') logger.info('received resume event')
_resume_callback() _resume_callback()
@ -73,12 +71,12 @@ try:
bus.add_signal_receiver(_suspend_or_resume, 'PrepareForSleep', dbus_interface=_LOGIND_INTERFACE, bus_name=_LOGIND_BUS) bus.add_signal_receiver(_suspend_or_resume, 'PrepareForSleep', dbus_interface=_LOGIND_INTERFACE, bus_name=_LOGIND_BUS)
if _log.isEnabledFor(_INFO): if logger.isEnabledFor(logging.INFO):
_log.info('connected to system dbus, watching for suspend/resume events') logger.info('connected to system dbus, watching for suspend/resume events')
except Exception: except Exception:
# Either: # Either:
# - the dbus library is not available # - the dbus library is not available
# - the system dbus is not running # - the system dbus is not running
_log.warn('failed to register suspend/resume callbacks') logger.warning('failed to register suspend/resume callbacks')
pass pass

View File

@ -81,7 +81,7 @@ For instructions on installing Solaar see https://pwr-solaar.github.io/Solaar/in
'PyYAML (>= 3.12)', 'PyYAML (>= 3.12)',
'python-xlib (>= 0.27)', 'python-xlib (>= 0.27)',
'psutil (>= 5.4.3)', 'psutil (>= 5.4.3)',
'dbus-python (>=1.3.2)', 'dbus-python',
], ],
extras_require={ extras_require={
'report-descriptor': ['hid-parser'], 'report-descriptor': ['hid-parser'],