From b936df8c1ec47300540403ebb6833f0fbf5f195f Mon Sep 17 00:00:00 2001 From: Nikola Dipanov Date: Mon, 25 Mar 2013 17:10:23 +0100 Subject: Add a format_message method to the Exceptions This patch adds a format_message method to the NovaException class that will almost always do what a user wants, when they want to print out the message of the exception. Exceptions that are received through RPC are turned into an actual exception classes by the deserialize_remote_exception function of the nova.openstack.common.rpc.common module. This function then overrides __str__ and __unicode__ methods of a new class to print the whole trace. We still want to preserve this functionality (for logging) but do not want to leak the trace back to the user in the HTTP response. Based on the above, This patch attempts to establish a convention that states: if you need to get the message of a NovaException subclass - always use the format_message method. Only use str(e) or unicode(e) when you suspect that they were overriden. Initially this was attempted through adding a custom metaclass to the NovaException class so that format_message cannot be overridden in subclasses, however due to a bug in testtools - many tests were failing. A patch was proposed to testtols to remedy this (https://github.com/testing-cabal/testtools/pull/34) however until it is merged, we cannot use metaclasses with our exception classes as they cause tests to fail. Change-Id: I0a399b9ab3227bad644b031c9b689fe0ce64586e --- nova/exception.py | 6 ++++++ nova/tests/test_exception.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/nova/exception.py b/nova/exception.py index cfc237120..1f32b0671 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -161,6 +161,12 @@ class NovaException(Exception): super(NovaException, self).__init__(message) + def format_message(self): + if self.__class__.__name__.endswith('_Remote'): + return self.args[0] + else: + return unicode(self) + class EC2APIError(NovaException): message = _("Unknown") diff --git a/nova/tests/test_exception.py b/nova/tests/test_exception.py index 6f5a9909e..040b56b13 100644 --- a/nova/tests/test_exception.py +++ b/nova/tests/test_exception.py @@ -140,3 +140,32 @@ class NovaExceptionTestCase(test.TestCase): kwargs = {} self.assertEquals(exception._cleanse_dict(kwargs), {}) + + def test_format_message_local(self): + class FakeNovaException(exception.NovaException): + message = "some message" + + exc = FakeNovaException() + self.assertEquals(unicode(exc), exc.format_message()) + + def test_format_message_remote(self): + class FakeNovaException_Remote(exception.NovaException): + message = "some message" + + def __unicode__(self): + return u"print the whole trace" + + exc = FakeNovaException_Remote() + self.assertEquals(unicode(exc), u"print the whole trace") + self.assertEquals(exc.format_message(), "some message") + + def test_format_message_remote_error(self): + class FakeNovaException_Remote(exception.NovaException): + message = "some message %(somearg)s" + + def __unicode__(self): + return u"print the whole trace" + + self.flags(fatal_exception_format_errors=False) + exc = FakeNovaException_Remote(lame_arg='lame') + self.assertEquals(exc.format_message(), "some message %(somearg)s") -- cgit