diff --git a/lib/hidapi/hidapi.py b/lib/hidapi/hidapi.py index 18464f9cd6..a9cbf82f04 100644 --- a/lib/hidapi/hidapi.py +++ b/lib/hidapi/hidapi.py @@ -33,6 +33,11 @@ from threading import Thread from time import sleep +import gi + +gi.require_version('Gdk', '3.0') +from gi.repository import GLib # NOQA: E402 + logger = logging.getLogger(__name__) native_implementation = 'hidapi' @@ -257,7 +262,7 @@ def _match(action, device, filterfn): device['hidpp_long'] = True except HIDError as e: # noqa: F841 if logger.isEnabledFor(logging.INFO): - logger.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}") # noqa finally: if device_handle: close(device_handle) @@ -279,8 +284,8 @@ def _match(action, device, filterfn): d_info = DeviceInfo( path=device['path'].decode(), bus_id=bus_id, - vendor_id=f'{vid:04X}', - product_id=f'{pid:04X}', + vendor_id=f'{vid:04X}', # noqa + product_id=f'{pid:04X}', # noqa interface=None, driver=None, manufacturer=device['manufacturer_string'], @@ -297,8 +302,8 @@ def _match(action, device, filterfn): d_info = DeviceInfo( path=device['path'].decode(), bus_id=None, - vendor_id=f'{vid:04X}', - product_id=f'{pid:04X}', + vendor_id=f'{vid:04X}', # noqa + product_id=f'{pid:04X}', # noqa interface=None, driver=None, manufacturer=None, @@ -323,7 +328,6 @@ def find_paired_node_wpid(receiver_path, index): def monitor_glib(callback, filterfn): - from gi.repository import GLib def device_callback(action, device): # print(f"device_callback({action}): {device}") diff --git a/lib/hidapi/hidconsole.py b/lib/hidapi/hidconsole.py index bc7bf4c043..a37dd1fa41 100644 --- a/lib/hidapi/hidconsole.py +++ b/lib/hidapi/hidconsole.py @@ -16,13 +16,16 @@ ## with this program; if not, write to the Free Software Foundation, Inc., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +import argparse import os +import os.path +import readline import sys import time from binascii import hexlify, unhexlify from select import select as _select -from threading import Lock +from threading import Lock, Thread import hidapi as _hid @@ -176,7 +179,6 @@ def matchfn(bid, vid, pid, _a, _b): def _parse_arguments(): - import argparse arg_parser = argparse.ArgumentParser() arg_parser.add_argument('--history', help='history file (default ~/.hidconsole-history)') arg_parser.add_argument('--hidpp', action='store_true', help='ensure input data is a valid HID++ request') @@ -196,9 +198,7 @@ def main(): if interactive: print('.. Press ^C/^D to exit, or type hex bytes to write to the device.') - import readline if args.history is None: - import os.path args.history = os.path.join(os.path.expanduser('~'), '.hidconsole-history') try: readline.read_history_file(args.history) @@ -207,7 +207,6 @@ def main(): pass try: - from threading import Thread t = Thread(target=_continuous_read, args=(handle, )) t.daemon = True t.start() diff --git a/lib/hidapi/udev.py b/lib/hidapi/udev.py index aaa11698bc..2329767877 100644 --- a/lib/hidapi/udev.py +++ b/lib/hidapi/udev.py @@ -35,12 +35,18 @@ from time import sleep from time import time as _timestamp +import gi + +from hid_parser import ReportDescriptor as _ReportDescriptor from pyudev import Context as _Context from pyudev import Device as _Device from pyudev import DeviceNotFoundError from pyudev import Devices as _Devices from pyudev import Monitor as _Monitor +gi.require_version('Gdk', '3.0') +from gi.repository import GLib # NOQA: E402 + logger = logging.getLogger(__name__) native_implementation = 'udev' @@ -105,9 +111,6 @@ def _match(action, device, filterfn): return # these are devices connected through a receiver so don't pick them up here try: # if report descriptor does not indicate HID++ capabilities then this device is not of interest to Solaar - from hid_parser import ReportDescriptor as _ReportDescriptor - - # from hid_parser import Usage as _Usage hidpp_short = hidpp_long = False devfile = '/sys' + hid_device.get('DEVPATH') + '/report_descriptor' with fileopen(devfile, 'rb') as fd: @@ -236,8 +239,6 @@ def find_paired_node_wpid(receiver_path, index): def monitor_glib(callback, filterfn): - from gi.repository import GLib - c = _Context() # already existing devices diff --git a/lib/logitech_receiver/diversion.py b/lib/logitech_receiver/diversion.py index adbb6050ef..3da2510f90 100644 --- a/lib/logitech_receiver/diversion.py +++ b/lib/logitech_receiver/diversion.py @@ -18,14 +18,20 @@ import ctypes as _ctypes import logging +import math +import numbers import os as _os import os.path as _path import platform as _platform +import socket +import subprocess import sys as _sys import time as _time -from math import sqrt as _sqrt -from struct import unpack as _unpack +import dbus +import gi +import keysyms.keysymdef as _keysymdef +import psutil # There is no evdev on macOS or Windows. Diversion will not work without # it but other Solaar functionality is available. @@ -34,9 +40,8 @@ else: import evdev -import dbus -import keysyms.keysymdef as _keysymdef -import psutil +from math import sqrt as _sqrt +from struct import unpack as _unpack from yaml import add_representer as _yaml_add_representer from yaml import dump_all as _yaml_dump_all @@ -46,8 +51,6 @@ from .hidpp20 import FEATURE as _F from .special_keys import CONTROL as _CONTROL -import gi # isort:skip - gi.require_version('Gdk', '3.0') # isort:skip from gi.repository import Gdk, GLib # NOQA: E402 # isort:skip @@ -1082,7 +1085,6 @@ def __str__(self): def evaluate(self, feature, notification, device, status, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug('evaluate condition: %s', self) - import socket hostname = socket.getfqdn() return hostname.startswith(self.host) @@ -1206,7 +1208,6 @@ def data(self): class MouseScroll(Action): def __init__(self, amounts, warn=True): - import numbers if len(amounts) == 1 and isinstance(amounts[0], list): amounts = amounts[0] if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])): @@ -1219,8 +1220,6 @@ def __str__(self): return 'MouseScroll: ' + ' '.join([str(a) for a in self.amounts]) def evaluate(self, feature, notification, device, status, last_result): - import math - import numbers amounts = self.amounts if isinstance(last_result, numbers.Number): amounts = [math.floor(last_result * a) for a in self.amounts] @@ -1328,7 +1327,6 @@ def __str__(self): return 'Execute: ' + ' '.join([a for a in self.args]) def evaluate(self, feature, notification, device, status, last_result): - import subprocess if logger.isEnabledFor(logging.INFO): logger.info('Execute action: %s', self.args) subprocess.Popen(self.args) diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index 4032d1c96c..42d0f545d9 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -19,6 +19,7 @@ # Logitech Unifying Receiver API. import logging +import socket import threading as _threading from struct import pack as _pack @@ -2003,7 +2004,6 @@ def get_host_names(device): remaining = 0 host_names[host] = (bool(status), name) # update the current host's name if it doesn't match the system name - import socket hostname = socket.gethostname().partition('.')[0] if host_names[currentHost][1] != hostname: set_host_name(device, hostname, host_names[currentHost][1]) diff --git a/lib/solaar/configuration.py b/lib/solaar/configuration.py index b011b50017..7066a0b984 100644 --- a/lib/solaar/configuration.py +++ b/lib/solaar/configuration.py @@ -26,6 +26,7 @@ import yaml as _yaml +from gi.repository import GLib from logitech_receiver.common import NamedInt as _NamedInt from solaar import __version__ @@ -142,7 +143,6 @@ def save(defer=False): else: with save_lock: if not save_timer: - from gi.repository import GLib save_timer = _Timer(5.0, lambda: GLib.idle_add(do_save)) save_timer.start() diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py index b4e3ed85f2..0bb54660f8 100755 --- a/lib/solaar/gtk.py +++ b/lib/solaar/gtk.py @@ -18,6 +18,8 @@ ## with this program; if not, write to the Free Software Foundation, Inc., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +import argparse +import faulthandler import importlib import logging import os.path @@ -26,8 +28,15 @@ import sys import tempfile +from traceback import format_exc + import solaar.cli as _cli +import solaar.configuration as _configuration import solaar.i18n as _i18n +import solaar.listener as _listener +import solaar.ui as _ui +import solaar.ui.common as _common +import solaar.upower as _upower from solaar import NAME, __version__ @@ -52,7 +61,6 @@ def _require(module, os_package, gi=None, gi_package=None, gi_version=None): def _parse_arguments(): - import argparse arg_parser = argparse.ArgumentParser( prog=NAME.lower(), epilog='For more information see https://pwr-solaar.github.io/Solaar' ) @@ -122,7 +130,6 @@ def _parse_arguments(): # On first SIGINT, dump threads to stderr; on second, exit def _handlesig(signl, stack): - import faulthandler signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) @@ -161,25 +168,18 @@ def main(): logger.warning('Solaar udev file not found in expected location') logger.warning('See https://pwr-solaar.github.io/Solaar/installation for more information') try: - import solaar.listener as listener - import solaar.ui as ui - import solaar.ui.common as common - - listener.setup_scanner(ui.status_changed, common.error_dialog) + _listener.setup_scanner(_ui.status_changed, _common.error_dialog) - import solaar.upower as _upower if args.restart_on_wake_up: - _upower.watch(listener.start_all, listener.stop_all) + _upower.watch(_listener.start_all, _listener.stop_all) else: - _upower.watch(lambda: listener.ping_all(True)) + _upower.watch(lambda: _listener.ping_all(True)) - import solaar.configuration as _configuration _configuration.defer_saves = True # allow configuration saves to be deferred # main UI event loop - ui.run_loop(listener.start_all, listener.stop_all, args.window != 'only', args.window != 'hide') + _ui.run_loop(_listener.start_all, _listener.stop_all, args.window != 'only', args.window != 'hide') except Exception: - from traceback import format_exc sys.exit('%s: error: %s' % (NAME.lower(), format_exc())) temp.close() diff --git a/lib/solaar/i18n.py b/lib/solaar/i18n.py index 7eddb7ef31..162ff8ed22 100644 --- a/lib/solaar/i18n.py +++ b/lib/solaar/i18n.py @@ -18,6 +18,10 @@ import gettext as _gettext import locale +import os.path as _path +import sys as _sys + +from glob import glob as _glob from solaar import NAME as _NAME @@ -27,13 +31,8 @@ def _find_locale_path(lc_domain): - import os.path as _path - import sys as _sys prefix_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..')) src_share = _path.normpath(_path.join(_path.realpath(_sys.path[0]), '..', 'share')) - del _sys - - from glob import glob as _glob for location in prefix_share, src_share: mo_files = _glob(_path.join(location, 'locale', '*', 'LC_MESSAGES', lc_domain + '.mo')) diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index 3ddba6d5be..94b39605f9 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -18,6 +18,7 @@ import errno as _errno import logging +import subprocess import time from collections import namedtuple @@ -390,7 +391,6 @@ def _process_add(device_info, retry): except OSError as e: if e.errno == _errno.EACCES: try: - import subprocess output = subprocess.check_output(['/usr/bin/getfacl', '-p', device_info.path], text=True) if logger.isEnabledFor(logging.WARNING): logger.warning('Missing permissions on %s\n%s.', device_info.path, output) diff --git a/lib/solaar/ui/__init__.py b/lib/solaar/ui/__init__.py index 449f78f6b7..b8673ffb14 100644 --- a/lib/solaar/ui/__init__.py +++ b/lib/solaar/ui/__init__.py @@ -21,7 +21,6 @@ import gi import yaml as _yaml -from gi.repository import Gio, GLib, Gtk from logitech_receiver.status import ALERT from solaar.i18n import _ from solaar.tasks import TaskRunner as _TaskRunner @@ -31,6 +30,8 @@ from . import diversion_rules, notify, tray, window gi.require_version('Gtk', '3.0') +from gi.repository import Gio, GLib, Gtk # NOQA: E402 + logger = logging.getLogger(__name__) # diff --git a/lib/solaar/ui/common.py b/lib/solaar/ui/common.py index 4b7f219e68..22440f885a 100644 --- a/lib/solaar/ui/common.py +++ b/lib/solaar/ui/common.py @@ -18,9 +18,13 @@ import logging -from gi.repository import GLib, Gtk +import gi + from solaar.i18n import _ +gi.require_version('Gtk', '3.0') +from gi.repository import GLib, Gtk # NOQA: E402 + logger = logging.getLogger(__name__) diff --git a/lib/solaar/ui/config_panel.py b/lib/solaar/ui/config_panel.py index 49fa4e81fb..d97f2e5a93 100644 --- a/lib/solaar/ui/config_panel.py +++ b/lib/solaar/ui/config_panel.py @@ -21,7 +21,8 @@ from threading import Timer as _Timer -from gi.repository import Gdk, GLib, Gtk +import gi + from logitech_receiver.hidpp20 import LEDEffectSetting as _LEDEffectSetting from logitech_receiver.settings import KIND as _SETTING_KIND from logitech_receiver.settings import SENSITIVITY_IGNORE as _SENSITIVITY_IGNORE @@ -29,6 +30,9 @@ from .common import ui_async as _ui_async +gi.require_version('Gtk', '3.0') +from gi.repository import Gdk, GLib, Gtk # NOQA: E402 + logger = logging.getLogger(__name__) # diff --git a/lib/solaar/ui/tray.py b/lib/solaar/ui/tray.py index c615943461..01f32049aa 100644 --- a/lib/solaar/ui/tray.py +++ b/lib/solaar/ui/tray.py @@ -21,6 +21,7 @@ from time import time as _timestamp +import gi import solaar.gtk as gtk from gi.repository import GLib, Gtk @@ -144,7 +145,6 @@ def _scroll(tray_icon, event, direction=None): try: - import gi try: gi.require_version('AyatanaAppIndicator3', '0.1') from gi.repository import AyatanaAppIndicator3 as AppIndicator3 diff --git a/setup.py b/setup.py index 2189e7638e..393d281355 100755 --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ import subprocess from glob import glob as _glob +from os.path import dirname as _dirname try: from setuptools import setup @@ -29,7 +30,6 @@ def _data_files(): - from os.path import dirname as _dirname yield 'share/icons/hicolor/scalable/apps', _glob('share/solaar/icons/solaar*.svg') yield 'share/icons/hicolor/32x32/apps', _glob('share/solaar/icons/solaar-light_*.png') @@ -41,8 +41,6 @@ def _data_files(): yield 'lib/udev/rules.d', ['rules.d/42-logitech-unify-permissions.rules'] yield 'share/metainfo', ['share/solaar/io.github.pwr_solaar.solaar.metainfo.xml'] - del _dirname - setup( name=NAME.lower(),