Decode exception parameters to expand exception message properly

If a multibyte string without unicode prefix 'u' is passed to
NeutronException in python 2, string subsitution will fail.
In python 2, multibyte string without 'u' prefix is encoded into bytes.
As a result a string substitution in NeutronException.__init__ will fail.

Change-Id: I1aa08b69fe119087a7a49fda768a24f85f0e7c76
Closes-Bug: #1235228
This commit is contained in:
Akihiro Motoki 2015-12-09 06:22:03 +09:00 committed by Akihiro Motoki
parent f1ae9b7cb4
commit 266e6c3c3c
2 changed files with 22 additions and 1 deletions

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import encodeutils
import six
from neutronclient._i18n import _
@ -31,6 +32,14 @@ Exceptions are classified into three categories:
"""
# NOTE: This method is defined here to avoid
# an import loop between common.utils and this module.
def _safe_decode_dict(kwargs):
for k, v in kwargs.items():
kwargs[k] = encodeutils.safe_decode(v)
return kwargs
@six.python_2_unicode_compatible
class NeutronException(Exception):
"""Base Neutron Exception.
@ -45,7 +54,7 @@ class NeutronException(Exception):
if message:
self.message = message
try:
self._error_string = self.message % kwargs
self._error_string = self.message % _safe_decode_dict(kwargs)
except Exception:
# at least get the core message out if something happened
self._error_string = self.message

View File

@ -13,6 +13,8 @@
# under the License.
import fixtures
from oslo_utils import encodeutils
import six
import testtools
from neutronclient.common import exceptions
@ -34,3 +36,13 @@ class TestExceptions(testtools.TestCase):
print(e)
self.assertEqual('Exception with %s' % multibyte_unicode_string,
fixture.getDetails().get('stdout').as_text())
def test_exception_message_with_encoded_unicode(self):
class TestException(exceptions.NeutronException):
message = _('Exception with %(reason)s')
multibyte_string = u'\uff21\uff22\uff23'
multibyte_binary = encodeutils.safe_encode(multibyte_string)
e = TestException(reason=multibyte_binary)
self.assertEqual('Exception with %s' % multibyte_string,
six.text_type(e))