From ac308341f698ddad63b68af889b8b3c9d0b1300f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 2 Jul 2015 17:16:14 +0200 Subject: [PATCH] Fix exception_to_unicode() for oslo_i18n Message Message instances created by oslo_i18n are subclasses of the Unicode type (unicode on Python 2, str on Python 3) and have no __unicode__() method. exception_to_unicode() raises an AttributeError when trying to convert it to Unicode. This change fixes this issue and adds an unit test. Change-Id: Ica67429ac64f74e5c636b6d74d71910a26511378 --- oslo_utils/encodeutils.py | 20 +++++++++++++++----- oslo_utils/tests/tests_encodeutils.py | 7 +++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/oslo_utils/encodeutils.py b/oslo_utils/encodeutils.py index 7d8af13b..52da98aa 100644 --- a/oslo_utils/encodeutils.py +++ b/oslo_utils/encodeutils.py @@ -107,13 +107,23 @@ def exception_to_unicode(exc): """ msg = None if six.PY2: - # Don't call directly unicode(exc), because it fails with - # UnicodeDecodeError on Python 2 if exc.__unicode__() returns a bytes - # string not decodable from the default encoding (ASCII) + # First try by calling the unicode type constructor. We should try + # unicode() before exc.__unicode__() because subclasses of unicode can + # be easily casted to unicode, whereas they have no __unicode__() + # method. try: - msg = exc.__unicode__() + msg = unicode(exc) except UnicodeError: - pass + # unicode(exc) fail with UnicodeDecodeError on Python 2 if + # exc.__unicode__() or exc.__str__() returns a bytes string not + # decodable from the default encoding (ASCII) + if hasattr(exc, '__unicode__'): + # Call directly the __unicode__() method to avoid + # the implicit decoding from the default encoding + try: + msg = exc.__unicode__() + except UnicodeError: + pass if msg is None: # Don't call directly str(exc), because it fails with diff --git a/oslo_utils/tests/tests_encodeutils.py b/oslo_utils/tests/tests_encodeutils.py index d0f696ed..84cbd49d 100644 --- a/oslo_utils/tests/tests_encodeutils.py +++ b/oslo_utils/tests/tests_encodeutils.py @@ -20,6 +20,7 @@ from oslotest import base as test_base import six import testtools +import oslo_i18n.fixture from oslo_utils import encodeutils @@ -231,3 +232,9 @@ class ExceptionToUnicodeTest(test_base.BaseTestCase): exc = UnicodeOnlyException(b'utf-8 \xc3\xa9\xe2\x82\xac') self.assertEqual(encodeutils.exception_to_unicode(exc), u'utf-8 \xe9\u20ac') + + def test_oslo_i18n_message(self): + # use the lazy translation to get a Message instance of oslo_i18n + exc = oslo_i18n.fixture.Translation().lazy("test") + self.assertEqual(encodeutils.exception_to_unicode(exc), + u"test")