From 3dd4dc672b3c695ed26ec39b3d4537de1641245a Mon Sep 17 00:00:00 2001 From: Matthias Dellweg <2500@gmx.de> Date: Tue, 31 Oct 2017 17:04:37 +0100 Subject: [PATCH] Introduce DBusException for propagating DBusErrors DBusException can be subclassed, to indicate exceptions, that are meant to be translated to DBusErrors. The type of error is encoded by the class variable 'dbus_name'. The class variable 'silent' can be used to suppress logging. --- pydbus/__init__.py | 3 +- pydbus/exceptions.py | 3 ++ pydbus/registration.py | 17 ++++++--- tests/dbus_exception.py | 77 +++++++++++++++++++++++++++++++++++++++++ tests/run.sh | 1 + 5 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 pydbus/exceptions.py create mode 100644 tests/dbus_exception.py diff --git a/pydbus/__init__.py b/pydbus/__init__.py index 5576517..3b79e77 100644 --- a/pydbus/__init__.py +++ b/pydbus/__init__.py @@ -1,4 +1,5 @@ from .bus import SystemBus, SessionBus, connect +from .exceptions import DBusException from gi.repository.GLib import Variant -__all__ = ["SystemBus", "SessionBus", "connect", "Variant"] +__all__ = ["SystemBus", "SessionBus", "connect", "DBusException", "Variant"] diff --git a/pydbus/exceptions.py b/pydbus/exceptions.py new file mode 100644 index 0000000..46d4904 --- /dev/null +++ b/pydbus/exceptions.py @@ -0,0 +1,3 @@ +class DBusException(Exception): + dbus_name = 'org.freedesktop.DBus.Error.Failed' + silent = False diff --git a/pydbus/registration.py b/pydbus/registration.py index f531539..3749d83 100644 --- a/pydbus/registration.py +++ b/pydbus/registration.py @@ -6,6 +6,7 @@ from functools import partial from .method_call_context import MethodCallContext import logging +from .exceptions import DBusException try: from inspect import signature, Parameter @@ -87,15 +88,21 @@ def call_method(self, connection, sender, object_path, interface_name, method_na else: invocation.return_value(GLib.Variant("(" + "".join(outargs) + ")", result)) + # catch DBusExceptions and turn them into dbus_errors + except DBusException as e: + if not e.silent: + logger = logging.getLogger(__name__) + logger.exception("DBusException while handling %s.%s()", interface_name, method_name) + + invocation.return_dbus_error(e.dbus_name, str(e)) + + # catch all other Exceptions report and reraise them except Exception as e: logger = logging.getLogger(__name__) logger.exception("Exception while handling %s.%s()", interface_name, method_name) - #TODO Think of a better way to translate Python exception types to DBus error types. - e_type = type(e).__name__ - if not "." in e_type: - e_type = "unknown." + e_type - invocation.return_dbus_error(e_type, str(e)) + invocation.return_dbus_error(DBusException.dbus_name, "Uncought exception while handling.") + raise e def Get(self, interface_name, property_name): type = self.readable_properties[interface_name + "." + property_name] diff --git a/tests/dbus_exception.py b/tests/dbus_exception.py new file mode 100644 index 0000000..a46582a --- /dev/null +++ b/tests/dbus_exception.py @@ -0,0 +1,77 @@ +from pydbus import SessionBus, DBusException +from gi.repository import GLib +from threading import Thread +import sys + +done = 0 +loop = GLib.MainLoop() + +class CustomDBusException(DBusException): + dbus_name = "net.lew21.pydbus.Test.Error.Custom" + silent = True + +class TestObject(object): + ''' + + + + + + + + + + + ''' + def __init__(self, id): + self.id = id + + def QuitService(self): + loop.quit() + return None + + def RaiseException(self): + raise Exception("sensitive") + return None + + def RaiseDBusException(self): + raise CustomDBusException("insensitive") + return None + + +bus = SessionBus() + +with bus.publish("net.lew21.pydbus.Test", TestObject("Main")): + remoteMain = bus.get("net.lew21.pydbus.Test") + + def t1_func(): + try: + remoteMain.RaiseDBusException() + except Exception as e: + if 'insensitive' not in str(e): + raise e + if CustomDBusException.dbus_name not in str(e): + raise e + try: + remoteMain.RaiseException() + except Exception as e: + if 'sensitive' in str(e): + raise e + if DBusException.dbus_name not in str(e): + raise e + remoteMain.QuitService() + + t1 = Thread(None, t1_func) + t1.daemon = True + + def handle_timeout(): + print("ERROR: Timeout.") + sys.exit(1) + + GLib.timeout_add_seconds(2, handle_timeout) + + t1.start() + + loop.run() + + t1.join() diff --git a/tests/run.sh b/tests/run.sh index 8d93644..49a9352 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -15,4 +15,5 @@ then "$PYTHON" $TESTS_DIR/publish.py "$PYTHON" $TESTS_DIR/publish_properties.py "$PYTHON" $TESTS_DIR/publish_multiface.py + "$PYTHON" $TESTS_DIR/dbus_exception.py fi