diff --git a/data/coverage.svg b/data/coverage.svg
index 4b105c68..5b40c8fe 100644
--- a/data/coverage.svg
+++ b/data/coverage.svg
@@ -15,7 +15,7 @@
coverage
coverage
- 82%
- 82%
+ 83%
+ 83%
diff --git a/data/pylint.svg b/data/pylint.svg
index 280836f4..df8fd8a5 100644
--- a/data/pylint.svg
+++ b/data/pylint.svg
@@ -17,7 +17,7 @@
pylint
- 9.66
- 9.66
+ 9.82
+ 9.82
\ No newline at end of file
diff --git a/keymapper/daemon.py b/keymapper/daemon.py
index e3a193aa..a637ae49 100644
--- a/keymapper/daemon.py
+++ b/keymapper/daemon.py
@@ -24,6 +24,7 @@
import subprocess
+import dbus
from dbus import service
import dbus.mainloop.glib
@@ -57,7 +58,7 @@ def get_dbus_interface():
remote_object = bus.get_object('keymapper.Control', '/')
interface = dbus.Interface(remote_object, 'keymapper.Interface')
logger.debug('Connected to dbus')
- except Exception as error:
+ except dbus.exceptions.DBusException as error:
logger.error(
'Could not connect to the dbus of "key-mapper-service", mapping '
'keys only works as long as the window is open.'
@@ -86,7 +87,11 @@ class Daemon(service.Object):
print(device, preset)
mapping = Mapping()
mapping.load(device, preset)
- self.injectors[device] = KeycodeInjector(device, mapping)
+ try:
+ injector = KeycodeInjector(device, mapping)
+ self.injectors[device] = injector
+ except OSError as error:
+ logger.error(error)
super().__init__(*args, **kwargs)
@dbus.service.method(
diff --git a/keymapper/dev/permissions.py b/keymapper/dev/permissions.py
index b8c923c5..1dc65a74 100644
--- a/keymapper/dev/permissions.py
+++ b/keymapper/dev/permissions.py
@@ -40,8 +40,10 @@ def can_read_devices():
def warn(group):
logger.warning(
'Some devices may not be visible without being in the '
- f'"{group}" user group. Try `sudo usermod -a -G {group} $USER` '
- 'and log out and back in.'
+ f'"%s" user group. Try `sudo usermod -a -G %s $USER` '
+ 'and log out and back in.',
+ group,
+ group
)
if not is_root and not is_test:
diff --git a/keymapper/gtk/row.py b/keymapper/gtk/row.py
index 5aa382d6..4e453d7a 100644
--- a/keymapper/gtk/row.py
+++ b/keymapper/gtk/row.py
@@ -109,6 +109,7 @@ class Row(Gtk.ListBoxRow):
self.get_style_context().remove_class('changed')
def on_character_input_change(self, _):
+ """When the output character for that keycode is typed in."""
keycode = self.get_keycode()
character = self.get_character()
diff --git a/keymapper/logger.py b/keymapper/logger.py
index 32fd4afe..5cc8950c 100644
--- a/keymapper/logger.py
+++ b/keymapper/logger.py
@@ -27,13 +27,17 @@ import logging
import pkg_resources
+SPAM = 5
+
+
def spam(self, message, *args, **kws):
+ """Log a more-verbose message than debug."""
+ # pylint: disable=protected-access
if self.isEnabledFor(SPAM):
# https://stackoverflow.com/a/13638084
self._log(SPAM, message, args, **kws)
-SPAM = 5
logging.addLevelName(SPAM, "SPAM")
logging.Logger.spam = spam
@@ -42,10 +46,11 @@ class Formatter(logging.Formatter):
"""Overwritten Formatter to print nicer logs."""
def format(self, record):
"""Overwritten format function."""
+ # pylint: disable=protected-access
debug = logger.level <= logging.DEBUG
if record.levelno == logging.INFO and not debug:
# if not launched with --debug, then don't print "INFO:"
- self._style._fmt = '%(message)s' # pylint: disable=line-too-long
+ self._style._fmt = '%(message)s'
else:
# see https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit
# for those numbers
diff --git a/keymapper/mapping.py b/keymapper/mapping.py
index 3ae5715a..89750bd8 100644
--- a/keymapper/mapping.py
+++ b/keymapper/mapping.py
@@ -30,19 +30,11 @@ from keymapper.logger import logger
from keymapper.paths import get_config_path
-def update_reverse_mapping(func):
- """Generate a reverse mapping to optimize reverse lookups.
-
- If _mapping contains `20: "a, A"` (the xkb syntax for modified keys),
- reverse mapping will contain `"a": 20, "A": 20`.
- """
+def keep_reverse_mapping_intact(func):
+ """Decorator for Mapping.update_reverse_mapping."""
def wrapper(self, *args, **kwargs):
func(self, *args, **kwargs)
-
- self._reverse_mapping = {}
- for key, value in self._mapping.items():
- for character in value.split(','):
- self._reverse_mapping[character.strip()] = key
+ self.update_reverse_mapping()
return wrapper
@@ -71,7 +63,18 @@ class Mapping:
def __len__(self):
return len(self._mapping)
- @update_reverse_mapping
+ def update_reverse_mapping(self):
+ """Generate a reverse mapping to optimize reverse lookups.
+
+ If _mapping contains `20: "a, A"` (the xkb syntax for modified keys),
+ reverse mapping will contain `"a": 20, "A": 20`.
+ """
+ self._reverse_mapping = {}
+ for key, value in self._mapping.items():
+ for character in value.split(','):
+ self._reverse_mapping[character.strip()] = key
+
+ @keep_reverse_mapping_intact
def change(self, new_keycode, character, previous_keycode=None):
"""Replace the mapping of a keycode with a different one.
@@ -110,7 +113,7 @@ class Mapping:
return False
- @update_reverse_mapping
+ @keep_reverse_mapping_intact
def clear(self, keycode):
"""Remove a keycode from the mapping.
@@ -122,13 +125,13 @@ class Mapping:
del self._mapping[keycode]
self.changed = True
- @update_reverse_mapping
+ @keep_reverse_mapping_intact
def empty(self):
"""Remove all mappings."""
self._mapping = {}
self.changed = True
- @update_reverse_mapping
+ @keep_reverse_mapping_intact
def load(self, device, preset):
"""Load a dumped JSON from home to overwrite the mappings."""
path = get_config_path(device, preset)