summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2008-07-17 13:00:15 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2008-07-17 13:00:15 +0100
commitd1ded84e774c4aaad9bf02842e1898580dd599ea (patch)
tree8f29632421a1dd19899e1084f882605acc13591a
parentb962965f8c30d785ade69dd6a60924b42d6a1c8d (diff)
downloaddbus-python-d1ded84e774c4aaad9bf02842e1898580dd599ea.tar.gz
Omit the remote traceback from certain D-Bus errors
Specifically, DBusException and its subclasses no longer have the remote traceback by default (although subclasses can turn it back on again by setting include_traceback = True, and the various "programmer error" subclasses of DBusException do have this set). Hopefully this will stop people thinking it's a dbus-python or telepathy-python bug when a D-Bus API like Telepathy deliberately raises an error (and so dbus-python or telepathy-python is visible in the traceback).
-rw-r--r--dbus/exceptions.py33
-rw-r--r--dbus/service.py5
-rwxr-xr-xtest/test-client.py37
-rwxr-xr-xtest/test-service.py22
4 files changed, 96 insertions, 1 deletions
diff --git a/dbus/exceptions.py b/dbus/exceptions.py
index 6a0fbaf..8d84a29 100644
--- a/dbus/exceptions.py
+++ b/dbus/exceptions.py
@@ -28,6 +28,17 @@ __all__ = ('DBusException', 'MissingErrorHandlerException',
'NameExistsException')
class DBusException(Exception):
+
+ include_traceback = False
+ """If True, tracebacks will be included in the exception message sent to
+ D-Bus clients.
+
+ Exceptions that are not DBusException subclasses always behave
+ as though this is True. Set this to True on DBusException subclasses
+ that represent a programming error, and leave it False on subclasses that
+ represent an expected failure condition (e.g. a network server not
+ responding)."""
+
def __init__(self, *args, **kwargs):
name = kwargs.pop('name', None)
if name is not None or getattr(self, '_dbus_error_name', None) is None:
@@ -44,30 +55,52 @@ class DBusException(Exception):
else:
return s
+ def get_dbus_message(self):
+ s = Exception.__str__(self)
+ return s.decode('utf-8', 'replace')
+
def get_dbus_name(self):
return self._dbus_error_name
class MissingErrorHandlerException(DBusException):
+
+ include_traceback = True
+
def __init__(self):
DBusException.__init__(self, "error_handler not defined: if you define a reply_handler you must also define an error_handler")
class MissingReplyHandlerException(DBusException):
+
+ include_traceback = True
+
def __init__(self):
DBusException.__init__(self, "reply_handler not defined: if you define an error_handler you must also define a reply_handler")
class ValidationException(DBusException):
+
+ include_traceback = True
+
def __init__(self, msg=''):
DBusException.__init__(self, "Error validating string: %s"%msg)
class IntrospectionParserException(DBusException):
+
+ include_traceback = True
+
def __init__(self, msg=''):
DBusException.__init__(self, "Error parsing introspect data: %s"%msg)
class UnknownMethodException(DBusException):
+
+ include_traceback = True
_dbus_error_name = 'org.freedesktop.DBus.Error.UnknownMethod'
+
def __init__(self, method):
DBusException.__init__(self, "Unknown method: %s"%method)
class NameExistsException(DBusException):
+
+ include_traceback = True
+
def __init__(self, name):
DBusException.__init__(self, "Bus name already exists: %s"%name)
diff --git a/dbus/service.py b/dbus/service.py
index 55bb04e..b92d840 100644
--- a/dbus/service.py
+++ b/dbus/service.py
@@ -277,7 +277,10 @@ def _method_reply_error(connection, message, exception):
name = 'org.freedesktop.DBus.Python.%s.%s' % (exception.__module__, exception.__class__.__name__)
et, ev, etb = sys.exc_info()
- if ev is exception:
+ if isinstance(exception, DBusException) and not exception.include_traceback:
+ # We don't actually want the traceback anyway
+ contents = exception.get_dbus_message()
+ elif ev is exception:
# The exception was actually thrown, so we can get a traceback
contents = ''.join(traceback.format_exception(et, ev, etb))
else:
diff --git a/test/test-client.py b/test/test-client.py
index 5b977da..753d892 100755
--- a/test/test-client.py
+++ b/test/test-client.py
@@ -508,6 +508,43 @@ class TestDBusBindings(unittest.TestCase):
self.assertRaises(dbus.DBusException,
lambda: self.iface.AsyncWait500ms(timeout=0.25))
+ def testExceptions(self):
+ #self.assertRaises(dbus.DBusException,
+ # lambda: self.iface.RaiseValueError)
+ #self.assertRaises(dbus.DBusException,
+ # lambda: self.iface.RaiseDBusExceptionNoTraceback)
+ #self.assertRaises(dbus.DBusException,
+ # lambda: self.iface.RaiseDBusExceptionWithTraceback)
+
+ try:
+ self.iface.RaiseValueError()
+ except Exception, e:
+ self.assert_(isinstance(e, dbus.DBusException), e.__class__)
+ self.assert_('.ValueError: Traceback ' in str(e),
+ 'Wanted a traceback but got:\n"""%s"""' % str(e))
+ else:
+ raise AssertionError('Wanted an exception')
+
+ try:
+ self.iface.RaiseDBusExceptionNoTraceback()
+ except Exception, e:
+ self.assert_(isinstance(e, dbus.DBusException), e.__class__)
+ self.assertEquals(str(e),
+ 'com.example.Networking.ServerError: '
+ 'Server not responding')
+ else:
+ raise AssertionError('Wanted an exception')
+
+ try:
+ self.iface.RaiseDBusExceptionWithTraceback()
+ except Exception, e:
+ self.assert_(isinstance(e, dbus.DBusException), e.__class__)
+ self.assert_(str(e).startswith('com.example.Misc.RealityFailure: '
+ 'Traceback '),
+ 'Wanted a traceback but got:\n%s' % str(e))
+ else:
+ raise AssertionError('Wanted an exception')
+
""" Remove this for now
class TestDBusPythonToGLibBindings(unittest.TestCase):
def setUp(self):
diff --git a/test/test-service.py b/test/test-service.py
index 74829d4..51865eb 100755
--- a/test/test-service.py
+++ b/test/test-service.py
@@ -305,6 +305,28 @@ class TestObject(dbus.service.Object, TestInterface):
return False
gobject.timeout_add(500, return_from_async_wait)
+ @dbus.service.method(IFACE, in_signature='', out_signature='')
+ def RaiseValueError(self):
+ raise ValueError('Wrong!')
+
+ @dbus.service.method(IFACE, in_signature='', out_signature='')
+ def RaiseDBusExceptionNoTraceback(self):
+ class ServerError(dbus.DBusException):
+ """Exception representing a normal "environmental" error"""
+ include_traceback = False
+ _dbus_error_name = 'com.example.Networking.ServerError'
+
+ raise ServerError('Server not responding')
+
+ @dbus.service.method(IFACE, in_signature='', out_signature='')
+ def RaiseDBusExceptionWithTraceback(self):
+ class RealityFailure(dbus.DBusException):
+ """Exception representing a programming error"""
+ include_traceback = True
+ _dbus_error_name = 'com.example.Misc.RealityFailure'
+
+ raise RealityFailure('Botched invariant')
+
@dbus.service.method(IFACE, in_signature='', out_signature='',
async_callbacks=('return_cb', 'raise_cb'))
def AsyncRaise(self, return_cb, raise_cb):