From 51a24b1c69920d2568bb40c49d0e4fdaad134134 Mon Sep 17 00:00:00 2001 From: Jonas Bosse Date: Thu, 22 Dec 2022 12:14:27 +0100 Subject: [PATCH] Fixed non-returning method decorator https://github.com/altdesktop/python-dbus-next/issues/119 --- inputremapper/daemon.py | 67 +++++++++++------------------ inputremapper/injection/injector.py | 17 +++++++- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/inputremapper/daemon.py b/inputremapper/daemon.py index 945bb27e3..31d127322 100644 --- a/inputremapper/daemon.py +++ b/inputremapper/daemon.py @@ -25,13 +25,15 @@ import asyncio import atexit import functools +import inspect import json import os import sys import time +import tracemalloc import typing from pathlib import PurePath -from typing import Protocol, Dict, Optional, Callable +from typing import Protocol, Dict, Optional from dbus_next.aio import MessageBus from dbus_next import BusType, service, RequestNameReply @@ -52,6 +54,7 @@ from inputremapper.injection.macros.macro import macro_variables from inputremapper.injection.global_uinputs import global_uinputs +tracemalloc.start() BUS_NAME = "inputremapper.Control" PATH_NAME = "/inputremapper/Control" @@ -152,6 +155,18 @@ def hello(self, out: str) -> str: ... +def method(name: str = None, disabled: bool = False): + # this is a workaround for https://github.com/altdesktop/python-dbus-next/issues/119 + @typing.no_type_check_decorator + def fixed_decorator(fn): + # we don't actually decorate the function + # dbus-next only cares about the __dict__ + fn.__dict__ = service.method(name, disabled)(fn).__dict__ + return fn + + return fixed_decorator + + class Daemon(service.ServiceInterface): """Starts injecting keycodes based on the configuration. @@ -163,40 +178,6 @@ class Daemon(service.ServiceInterface): on its own. """ - # https://dbus.freedesktop.org/doc/dbus-specification.html#type-system - dbus = f""" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """ - def __init__(self): """Constructs the daemon.""" logger.debug("Creating daemon") @@ -313,7 +294,7 @@ async def refresh(self, group_key: Optional[str] = None): groups.refresh() self.refreshed_devices_at = now - @service.method() + @method() def stop_injecting(self, group_key: "s"): """Stop injecting the preset mappings for a single device.""" if self.injectors.get(group_key) is None: @@ -326,13 +307,13 @@ def stop_injecting(self, group_key: "s"): self.injectors[group_key].stop_injecting() self.autoload_history.forget(group_key) - @service.method() + @method() def get_state(self, group_key: "s") -> "s": """Get the injectors state.""" injector = self.injectors.get(group_key) return injector.get_state() if injector else InjectorState.UNKNOWN - @service.method() + @method() def set_config_dir(self, config_dir: "s"): """All future operations will use this config dir. @@ -393,7 +374,7 @@ async def _autoload(self, group_key: str): await self.start_injecting(group.key, preset) self.autoload_history.remember(group.key, preset) - @service.method() + @method() async def autoload_single(self, group_key: "s"): """Inject the configured autoload preset for the device. @@ -420,7 +401,7 @@ async def autoload_single(self, group_key: "s"): await self._autoload(group_key) - @service.method() + @method() async def autoload(self): """Load all autoloaded presets for the current config_dir. @@ -444,7 +425,7 @@ async def autoload(self): for group_key, _ in autoload_presets: await self._autoload(group_key) - @service.method() + @method() async def start_injecting(self, group_key: "s", preset: "s") -> "b": """Start injecting the preset for the device. @@ -535,14 +516,14 @@ async def start_injecting(self, group_key: "s", preset: "s") -> "b": return True - @service.method() + @method() def stop_all(self): """Stop all injections.""" logger.info("Stopping all injections") for group_key in list(self.injectors.keys()): self.stop_injecting(group_key) - @service.method() + @method() def hello(self, out: "s") -> "s": """Used for tests.""" logger.info('Received "%s" from client', out) diff --git a/inputremapper/injection/injector.py b/inputremapper/injection/injector.py index 4707a70a7..ff0c7069f 100644 --- a/inputremapper/injection/injector.py +++ b/inputremapper/injection/injector.py @@ -377,7 +377,21 @@ def _create_forwarding_device(self, source: evdev.InputDevice) -> evdev.UInput: raise e return forward_to + def is_alive(self) -> bool: + """used in tests, can probably be removed, previously defined by the + multiprocessing.Process superclass""" + return self._alive + async def run(self) -> None: + self._alive = True + try: + await self._run() + except: + self._alive = False + raise + self._alive = False + + async def _run(self) -> None: """The injection worker that keeps injecting until terminated. Stuff is non-blocking by using asyncio in order to do multiple things @@ -386,7 +400,6 @@ async def run(self) -> None: Use this function as starting point in a process. It creates the loops needed to read and map events and keeps running them. """ - self._alive = True logger.info('Starting injecting the preset for "%s"', self.group.key) # create a new event loop, because somehow running an infinite loop @@ -414,6 +427,7 @@ async def run(self) -> None: # maybe the preset was empty or something logger.error("Did not grab any device") self._msg_pipe[0].send(InjectorState.NO_GRAB) + self._alive = False return numlock_state = is_numlock_on() @@ -465,4 +479,3 @@ async def run(self) -> None: logger.debug("OSError for ungrab on %s: %s", source.path, str(error)) self._msg_pipe[0].send(InjectorState.STOPPED) - self._alive = False