diff --git a/HACKING.rst b/HACKING.rst index ef9bd588904..507aea50b21 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -19,6 +19,7 @@ Cinder Specific Commandments - [N333] Ensure that oslo namespaces are used for namespaced libraries. - [N339] Prevent use of deprecated contextlib.nested. - [C301] timeutils.utcnow() from oslo_utils should be used instead of datetime.now(). +- [C302] six.text_type should be used instead of unicode General diff --git a/cinder/api/contrib/volume_actions.py b/cinder/api/contrib/volume_actions.py index aca5c118448..423cf17a288 100644 --- a/cinder/api/contrib/volume_actions.py +++ b/cinder/api/contrib/volume_actions.py @@ -16,6 +16,7 @@ from oslo_log import log as logging import oslo_messaging as messaging from oslo_utils import strutils +import six import webob from cinder.api import extensions @@ -269,13 +270,13 @@ class VolumeActionsController(wsgi.Controller): except exception.InvalidVolume as error: raise webob.exc.HTTPBadRequest(explanation=error.msg) except ValueError as error: - raise webob.exc.HTTPBadRequest(explanation=unicode(error)) + raise webob.exc.HTTPBadRequest(explanation=six.text_type(error)) except messaging.RemoteError as error: msg = "%(err_type)s: %(err_msg)s" % {'err_type': error.exc_type, 'err_msg': error.value} raise webob.exc.HTTPBadRequest(explanation=msg) except Exception as error: - raise webob.exc.HTTPBadRequest(explanation=unicode(error)) + raise webob.exc.HTTPBadRequest(explanation=six.text_type(error)) return {'os-volume_upload_image': response} @wsgi.action('os-extend') diff --git a/cinder/api/contrib/volume_replication.py b/cinder/api/contrib/volume_replication.py index 338d46f4b29..e0846548f32 100644 --- a/cinder/api/contrib/volume_replication.py +++ b/cinder/api/contrib/volume_replication.py @@ -13,6 +13,7 @@ # under the License. from oslo_log import log as logging +import six import webob from webob import exc @@ -76,7 +77,7 @@ class VolumeReplicationController(wsgi.Controller): msg = _("Volume could not be found") raise exc.HTTPNotFound(explanation=msg) except exception.ReplicationError as error: - raise exc.HTTPBadRequest(explanation=unicode(error)) + raise exc.HTTPBadRequest(explanation=six.text_type(error)) return webob.Response(status_int=202) @wsgi.response(202) @@ -94,7 +95,7 @@ class VolumeReplicationController(wsgi.Controller): msg = _("Volume could not be found") raise exc.HTTPNotFound(explanation=msg) except exception.ReplicationError as error: - raise exc.HTTPBadRequest(explanation=unicode(error)) + raise exc.HTTPBadRequest(explanation=six.text_type(error)) return webob.Response(status_int=202) diff --git a/cinder/api/middleware/fault.py b/cinder/api/middleware/fault.py index 480f8a89f63..0575b46f108 100644 --- a/cinder/api/middleware/fault.py +++ b/cinder/api/middleware/fault.py @@ -15,6 +15,7 @@ # under the License. from oslo_log import log as logging +import six import webob.dec import webob.exc @@ -64,7 +65,7 @@ class FaultWrapper(base_wsgi.Middleware): # including those that are safe to expose, see bug 1021373 if safe: msg = (inner.msg if isinstance(inner, exception.CinderException) - else unicode(inner)) + else six.text_type(inner)) params = {'exception': inner.__class__.__name__, 'explanation': msg} outer.explanation = _('%(exception)s: %(explanation)s') % params diff --git a/cinder/api/xmlutil.py b/cinder/api/xmlutil.py index 76d102f5ee1..a867555fa1d 100644 --- a/cinder/api/xmlutil.py +++ b/cinder/api/xmlutil.py @@ -17,6 +17,7 @@ import os.path import re from lxml import etree +import six from cinder.i18n import _ from cinder import utils @@ -338,12 +339,12 @@ class TemplateElement(object): # Start with the text... if self.text is not None: - elem.text = unicode(self.text(obj)) + elem.text = six.text_type(self.text(obj)) # Now set up all the attributes... for key, value in self.attrib.items(): try: - elem.set(key, unicode(value(obj, True))) + elem.set(key, six.text_type(value(obj, True))) except KeyError: # Attribute has no value, so don't include it pass diff --git a/cinder/backup/chunkeddriver.py b/cinder/backup/chunkeddriver.py index 1750fdd0474..cb7d7317ea7 100644 --- a/cinder/backup/chunkeddriver.py +++ b/cinder/backup/chunkeddriver.py @@ -80,7 +80,7 @@ class ChunkedBackupDriver(driver.BackupDriver): pass err = _('unsupported compression algorithm: %s') % algorithm - raise ValueError(unicode(err)) + raise ValueError(err) def __init__(self, context, chunk_size_bytes, sha_block_size_bytes, backup_default_container, enable_progress_timer, diff --git a/cinder/backup/drivers/ceph.py b/cinder/backup/drivers/ceph.py index f0ee60d38c4..a975984540b 100644 --- a/cinder/backup/drivers/ceph.py +++ b/cinder/backup/drivers/ceph.py @@ -493,7 +493,7 @@ class CephBackupDriver(driver.BackupDriver): p1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: - LOG.error(_LE("Pipe1 failed - %s ") % unicode(e)) + LOG.error(_LE("Pipe1 failed - %s "), e) raise # NOTE(dosaboy): ensure that the pipe is blocking. This is to work @@ -507,7 +507,7 @@ class CephBackupDriver(driver.BackupDriver): stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: - LOG.error(_LE("Pipe2 failed - %s ") % unicode(e)) + LOG.error(_LE("Pipe2 failed - %s "), e) raise p1.stdout.close() diff --git a/cinder/backup/manager.py b/cinder/backup/manager.py index 0c6096bc05f..8bdde385222 100644 --- a/cinder/backup/manager.py +++ b/cinder/backup/manager.py @@ -38,6 +38,7 @@ from oslo_log import log as logging import oslo_messaging as messaging from oslo_utils import excutils from oslo_utils import importutils +import six from cinder.backup import driver from cinder.backup import rpcapi as backup_rpcapi @@ -298,7 +299,7 @@ class BackupManager(manager.SchedulerDependentManager): {'status': 'available'}) self.db.backup_update(context, backup_id, {'status': 'error', - 'fail_reason': unicode(err)}) + 'fail_reason': six.text_type(err)}) self.db.volume_update(context, volume_id, {'status': 'available'}) backup = self.db.backup_update(context, backup_id, @@ -406,7 +407,7 @@ class BackupManager(manager.SchedulerDependentManager): self.db.backup_update(context, backup_id, {'status': 'error', 'fail_reason': - unicode(err)}) + six.text_type(err)}) LOG.info(_LI('Delete backup started, backup: %s.'), backup_id) backup = self.db.backup_get(context, backup_id) @@ -446,7 +447,7 @@ class BackupManager(manager.SchedulerDependentManager): self.db.backup_update(context, backup_id, {'status': 'error', 'fail_reason': - unicode(err)}) + six.text_type(err)}) # Get reservations try: @@ -528,7 +529,7 @@ class BackupManager(manager.SchedulerDependentManager): backup_url = backup_service.export_record(backup) backup_record['backup_url'] = backup_url except Exception as err: - msg = unicode(err) + msg = six.text_type(err) raise exception.InvalidBackup(reason=msg) LOG.info(_LI('Export record finished, backup %s exported.'), backup_id) @@ -579,7 +580,7 @@ class BackupManager(manager.SchedulerDependentManager): backup_service = self.service.get_backup_driver(context) backup_options = backup_service.import_record(backup_url) except Exception as err: - msg = unicode(err) + msg = six.text_type(err) self.db.backup_update(context, backup_id, {'status': 'error', @@ -627,7 +628,7 @@ class BackupManager(manager.SchedulerDependentManager): self.db.backup_update(context, backup_id, {'status': 'error', 'fail_reason': - unicode(err)}) + six.text_type(err)}) LOG.info(_LI('Import record id %s metadata from driver ' 'finished.') % backup_id) diff --git a/cinder/brick/exception.py b/cinder/brick/exception.py index 0283c156717..235793c1713 100644 --- a/cinder/brick/exception.py +++ b/cinder/brick/exception.py @@ -15,6 +15,7 @@ """Exceptions for the Brick library.""" from oslo_log import log as logging +import six from cinder.i18n import _ @@ -65,7 +66,7 @@ class BrickException(Exception): super(BrickException, self).__init__(message) def __unicode__(self): - return unicode(self.msg) + return six.text_type(self.msg) class NotFound(BrickException): diff --git a/cinder/exception.py b/cinder/exception.py index 84cfd236b16..9e53667354c 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -112,7 +112,7 @@ class CinderException(Exception): return self.kwargs['message'] is None or '%(message)' in self.message def __unicode__(self): - return unicode(self.msg) + return six.text_type(self.msg) class VolumeBackendAPIException(CinderException): diff --git a/cinder/hacking/checks.py b/cinder/hacking/checks.py index 05c585d7d6e..999e1057a9b 100644 --- a/cinder/hacking/checks.py +++ b/cinder/hacking/checks.py @@ -198,6 +198,16 @@ def check_datetime_now(logical_line, noqa): yield(0, msg) +def check_unicode_usage(logical_line, noqa): + if noqa: + return + + msg = "C302: Found unicode() call. Please use six.text_type()." + + if 'unicode(' in logical_line: + yield(0, msg) + + def factory(register): register(no_vi_headers) register(no_translate_debug_logs) @@ -209,3 +219,4 @@ def factory(register): register(check_no_contextlib_nested) register(check_datetime_now) register(validate_log_translations) + register(check_unicode_usage) diff --git a/cinder/objects/fields.py b/cinder/objects/fields.py index 168b8677e85..39986dbcf0a 100644 --- a/cinder/objects/fields.py +++ b/cinder/objects/fields.py @@ -241,7 +241,7 @@ class String(FieldType): # FIXME(danms): We should really try to avoid the need to do this if isinstance(value, (six.string_types, int, long, float, datetime.datetime)): - return unicode(value) + return six.text_type(value) else: raise ValueError(_('A string is required here, not %s') % value.__class__.__name__) diff --git a/cinder/tests/brick/test_brick_connector.py b/cinder/tests/brick/test_brick_connector.py index 4a55cb5e15e..ff14e3865fd 100644 --- a/cinder/tests/brick/test_brick_connector.py +++ b/cinder/tests/brick/test_brick_connector.py @@ -22,6 +22,7 @@ import mock from oslo_concurrency import processutils as putils from oslo_config import cfg from oslo_log import log as logging +import six from cinder.brick import exception from cinder.brick.initiator import connector @@ -715,7 +716,7 @@ class FibreChannelConnectorTestCase(ConnectorTestCase): name = 'volume-00000001' vol = {'id': 1, 'name': name} # Should work for string, unicode, and list - wwns = ['1234567890123456', unicode('1234567890123456'), + wwns = ['1234567890123456', six.text_type('1234567890123456'), ['1234567890123456', '1234567890123457']] for wwn in wwns: connection_info = self.fibrechan_connection(vol, location, wwn) diff --git a/cinder/tests/brick/test_brick_exception.py b/cinder/tests/brick/test_brick_exception.py index b6bc939a9e8..9799b80467b 100644 --- a/cinder/tests/brick/test_brick_exception.py +++ b/cinder/tests/brick/test_brick_exception.py @@ -18,6 +18,8 @@ from cinder.brick import exception from cinder import test +import six + class BrickExceptionTestCase(test.TestCase): def test_default_error_msg(self): @@ -25,17 +27,18 @@ class BrickExceptionTestCase(test.TestCase): message = "default message" exc = FakeBrickException() - self.assertEqual(unicode(exc), 'default message') + self.assertEqual(six.text_type(exc), 'default message') def test_error_msg(self): - self.assertEqual(unicode(exception.BrickException('test')), 'test') + self.assertEqual(six.text_type(exception.BrickException('test')), + 'test') def test_default_error_msg_with_kwargs(self): class FakeBrickException(exception.BrickException): message = "default message: %(code)s" exc = FakeBrickException(code=500) - self.assertEqual(unicode(exc), 'default message: 500') + self.assertEqual(six.text_type(exc), 'default message: 500') def test_error_msg_exception_with_kwargs(self): # NOTE(dprince): disable format errors for this test @@ -45,7 +48,8 @@ class BrickExceptionTestCase(test.TestCase): message = "default message: %(mispelled_code)s" exc = FakeBrickException(code=500) - self.assertEqual(unicode(exc), 'default message: %(mispelled_code)s') + self.assertEqual(six.text_type(exc), + 'default message: %(mispelled_code)s') def test_default_error_code(self): class FakeBrickException(exception.BrickException): diff --git a/cinder/tests/test_exception.py b/cinder/tests/test_exception.py index d5712459fec..00bbc198842 100644 --- a/cinder/tests/test_exception.py +++ b/cinder/tests/test_exception.py @@ -18,6 +18,8 @@ from cinder import exception from cinder import test +import six + class FakeNotifier(object): """Acts like the cinder.openstack.common.notifier.api module.""" @@ -54,17 +56,18 @@ class CinderExceptionTestCase(test.TestCase): message = "default message" exc = FakeCinderException() - self.assertEqual(unicode(exc), 'default message') + self.assertEqual(six.text_type(exc), 'default message') def test_error_msg(self): - self.assertEqual(unicode(exception.CinderException('test')), 'test') + self.assertEqual(six.text_type(exception.CinderException('test')), + 'test') def test_default_error_msg_with_kwargs(self): class FakeCinderException(exception.CinderException): message = "default message: %(code)s" exc = FakeCinderException(code=500) - self.assertEqual(unicode(exc), 'default message: 500') + self.assertEqual(six.text_type(exc), 'default message: 500') def test_error_msg_exception_with_kwargs(self): # NOTE(dprince): disable format errors for this test @@ -74,7 +77,8 @@ class CinderExceptionTestCase(test.TestCase): message = "default message: %(misspelled_code)s" exc = FakeCinderException(code=500) - self.assertEqual(unicode(exc), 'default message: %(misspelled_code)s') + self.assertEqual(six.text_type(exc), + 'default message: %(misspelled_code)s') def test_default_error_code(self): class FakeCinderException(exception.CinderException): @@ -107,14 +111,14 @@ class CinderExceptionTestCase(test.TestCase): message = 'FakeCinderException: %(message)s' exc = FakeCinderException(message='message') - self.assertEqual(unicode(exc), 'FakeCinderException: message') + self.assertEqual(six.text_type(exc), 'FakeCinderException: message') def test_message_and_kwarg_in_format_string(self): class FakeCinderException(exception.CinderException): message = 'Error %(code)d: %(message)s' exc = FakeCinderException(message='message', code=404) - self.assertEqual(unicode(exc), 'Error 404: message') + self.assertEqual(six.text_type(exc), 'Error 404: message') def test_message_is_exception_in_format_string(self): class FakeCinderException(exception.CinderException): @@ -123,4 +127,4 @@ class CinderExceptionTestCase(test.TestCase): msg = 'test message' exc1 = Exception(msg) exc2 = FakeCinderException(message=exc1) - self.assertEqual(unicode(exc2), 'Exception: test message') + self.assertEqual(six.text_type(exc2), 'Exception: test message') diff --git a/cinder/tests/test_hacking.py b/cinder/tests/test_hacking.py index db69b8a1a14..338a6019ea0 100644 --- a/cinder/tests/test_hacking.py +++ b/cinder/tests/test_hacking.py @@ -199,3 +199,9 @@ class HackingTestCase(test.TestCase): "LOG.error(_LE('foo')", "foo.py")))) self.assertEqual(0, len(list(checks.validate_log_translations( "LOG.exception(_LE('foo')", "foo.py")))) + + def test_check_unicode_usage(self): + self.assertEqual(1, len(list(checks.check_unicode_usage( + "unicode(msg)", False)))) + self.assertEqual(0, len(list(checks.check_unicode_usage( + "unicode(msg) # noqa", True)))) diff --git a/cinder/tests/test_hplefthand.py b/cinder/tests/test_hplefthand.py index 3a7b8a99640..b239f8db08d 100644 --- a/cinder/tests/test_hplefthand.py +++ b/cinder/tests/test_hplefthand.py @@ -18,6 +18,7 @@ import mock from oslo_log import log as logging from oslo_utils import units +import six from cinder import context from cinder import exception @@ -331,7 +332,7 @@ class TestHPLeftHandCLIQISCSIDriver(HPLeftHandBaseDriver, test.TestCase): def test_paramiko_1_13_0(cliq_args): # paramiko 1.13.0 now returns unicode - output = unicode( + output = six.text_type( '\n' '\n\n