From fccd3128715a02a9ade74095d75ba18414bf997d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Beraud?= Date: Wed, 20 Nov 2019 19:37:26 +0100 Subject: [PATCH] Remove six and python 2.7 full support Six is in use to help us to keep support for python 2.7. Since the ussuri cycle we decide to remove the python 2.7 support so we can go ahead and also remove six usage from the python code. Review process and help ----------------------- Removing six introduce a lot of changes and an huge amount of modified files To simplify reviews we decided to split changes into several patches to avoid painful reviews and avoid mistakes. To review this patch you can use the six documentation [1] to obtain help and understand choices. Additional informations ----------------------- Changes related to 'six.b(data)' [2] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ six.b [2] encode the given datas in latin-1 in python3 so I did the same things in this patch. Latin-1 is equal to iso-8859-1 [3]. This encoding is the default encoding [4] of certain descriptive HTTP headers. I suggest to keep latin-1 for the moment and to move to another encoding in a follow-up patch if needed to move to most powerful encoding (utf8). HTML4 support utf8 charset and utf8 is the default charset for HTML5 [5]. Note that this commit message is autogenerated and not necesserly contains changes related to 'six.b' [1] https://six.readthedocs.io/ [2] https://six.readthedocs.io/#six.b [3] https://docs.python.org/3/library/codecs.html#standard-encodings [4] https://www.w3schools.com/charsets/ref_html_8859.asp [5] https://www.w3schools.com/html/html_charset.asp Patch 3 of a serie of 28 patches Change-Id: If6e66839c128dde5fb80d90155dedb598da8d53b --- heat/common/exception.py | 21 +++++++++------------ heat/common/grouputils.py | 4 +--- heat/common/i18n.py | 19 ------------------- heat/common/identifier.py | 2 +- heat/common/password_gen.py | 9 ++++----- heat/common/plugin_loader.py | 6 +++--- heat/common/pluginutils.py | 3 +-- heat/common/policy.py | 3 +-- heat/common/serializers.py | 9 ++++----- heat/common/short_id.py | 8 +++----- heat/engine/attributes.py | 2 -- heat/engine/dependencies.py | 3 --- heat/engine/rsrc_defn.py | 2 -- heat/engine/scheduler.py | 2 -- heat/engine/update.py | 2 -- heat/tests/engine/test_scheduler.py | 2 -- 16 files changed, 27 insertions(+), 70 deletions(-) diff --git a/heat/common/exception.py b/heat/common/exception.py index 401dad9b4e..ecb809eb53 100644 --- a/heat/common/exception.py +++ b/heat/common/exception.py @@ -21,8 +21,6 @@ import sys from oslo_log import log as logging from oslo_utils import excutils -import six - from heat.common.i18n import _ _FATAL_EXCEPTION_FORMAT_ERRORS = False @@ -38,7 +36,6 @@ ERROR_CODE_MAP = { } -@six.python_2_unicode_compatible class HeatException(Exception): """Base Heat Exception. @@ -71,7 +68,7 @@ class HeatException(Exception): # kwargs doesn't match a variable in the message # log the issue and the kwargs LOG.exception('Exception in string format operation') - for name, value in six.iteritems(kwargs): + for name, value in kwargs.items(): LOG.error("%(name)s: %(value)s", {'name': name, 'value': value}) # noqa @@ -222,7 +219,7 @@ class HeatExceptionWithPath(HeatException): if path is not None: if isinstance(path, list): self.path = path - elif isinstance(path, six.string_types): + elif isinstance(path, str): self.path = [path] result_path = '' @@ -247,7 +244,7 @@ class StackValidationFailed(HeatExceptionWithPath): resource=None): if path is None: path = [] - elif isinstance(path, six.string_types): + elif isinstance(path, str): path = [path] if resource is not None and not path: @@ -263,8 +260,8 @@ class StackValidationFailed(HeatExceptionWithPath): # oslo.messaging. self.args = error.args else: - str_error = six.text_type(type(error).__name__) - message = six.text_type(error) + str_error = str(type(error).__name__) + message = str(error) else: str_error = error @@ -331,8 +328,8 @@ class ResourceFailure(HeatExceptionWithPath): path = exception_or_error.path else: self.exc = exception_or_error - error = six.text_type(type(self.exc).__name__) - message = six.text_type(self.exc) + error = str(type(self.exc).__name__) + message = str(self.exc) path = res_path else: self.exc = None @@ -418,7 +415,7 @@ class UpdateReplace(Exception): """Raised when resource update requires replacement.""" def __init__(self, resource_name='Unknown'): msg = _("The Resource %s requires replacement.") % resource_name - super(Exception, self).__init__(six.text_type(msg)) + super(Exception, self).__init__(str(msg)) class ResourceUnknownStatus(HeatException): @@ -443,7 +440,7 @@ class ResourceInError(HeatException): class UpdateInProgress(Exception): def __init__(self, resource_name='Unknown'): msg = _("The resource %s is already being updated.") % resource_name - super(Exception, self).__init__(six.text_type(msg)) + super(Exception, self).__init__(str(msg)) class HTTPExceptionDisguise(Exception): diff --git a/heat/common/grouputils.py b/heat/common/grouputils.py index d62a20c827..69e3c53fdb 100644 --- a/heat/common/grouputils.py +++ b/heat/common/grouputils.py @@ -11,8 +11,6 @@ # License for the specific language governing permissions and limitations # under the License. -import six - from heat.common import exception from heat.common.i18n import _ from heat.engine import status @@ -122,7 +120,7 @@ def get_members(group, include_failed=False): """ resources = [] if group.nested(): - resources = [r for r in six.itervalues(group.nested()) + resources = [r for r in group.nested().values() if include_failed or r.status != r.FAILED] return sorted(resources, diff --git a/heat/common/i18n.py b/heat/common/i18n.py index e2c423cb08..2b3cc178ed 100644 --- a/heat/common/i18n.py +++ b/heat/common/i18n.py @@ -17,29 +17,10 @@ # recommendations from # https://docs.openstack.org/oslo.i18n/latest/user/usage.html -import six - import oslo_i18n as i18n -from oslo_utils import encodeutils _translators = i18n.TranslatorFactory(domain='heat') # The primary translation function using the well-known name "_" _ = _translators.primary - - -def repr_wrapper(klass): - """A decorator that defines __repr__ method under Python 2. - - Under Python 2 it will encode repr return value to str type. - Under Python 3 it does nothing. - """ - if six.PY2: - if '__repr__' not in klass.__dict__: - raise ValueError("@repr_wrapper cannot be applied " - "to %s because it doesn't define __repr__()." % - klass.__name__) - klass._repr = klass.__repr__ - klass.__repr__ = lambda self: encodeutils.safe_encode(self._repr()) - return klass diff --git a/heat/common/identifier.py b/heat/common/identifier.py index 6d39569a68..46323b25d7 100644 --- a/heat/common/identifier.py +++ b/heat/common/identifier.py @@ -15,7 +15,7 @@ import collections import re from oslo_utils import encodeutils -from six.moves.urllib import parse as urlparse +from urllib import parse as urlparse from heat.common.i18n import _ diff --git a/heat/common/password_gen.py b/heat/common/password_gen.py index 52d5a3a247..0a5c333846 100644 --- a/heat/common/password_gen.py +++ b/heat/common/password_gen.py @@ -12,11 +12,10 @@ # under the License. import collections +import io import random as random_module import string -import six - # NOTE(pas-ha) Heat officially supports only POSIX::Linux platform # where os.urandom() and random.SystemRandom() are available @@ -88,19 +87,19 @@ def generate_password(length, char_classes): :param char_classes: Iterable over classes of characters from which to generate a password """ - char_buffer = six.StringIO() + char_buffer = io.StringIO() all_allowed_chars = set() # Add the minimum number of chars from each char class for char_class in char_classes: all_allowed_chars |= char_class.allowed_chars allowed_chars = tuple(char_class.allowed_chars) - for i in six.moves.xrange(char_class.min_count): + for i in range(char_class.min_count): char_buffer.write(random.choice(allowed_chars)) # Fill up rest with random chars from provided classes combined_chars = tuple(all_allowed_chars) - for i in six.moves.xrange(max(0, length - char_buffer.tell())): + for i in range(max(0, length - char_buffer.tell())): char_buffer.write(random.choice(combined_chars)) # Shuffle string diff --git a/heat/common/plugin_loader.py b/heat/common/plugin_loader.py index 58f3736fc9..59f75df153 100644 --- a/heat/common/plugin_loader.py +++ b/heat/common/plugin_loader.py @@ -19,12 +19,12 @@ existing package tree, use create_subpackage() to dynamically create a package for them before loading them. """ +import functools import pkgutil import sys import types from oslo_log import log as logging -import six LOG = logging.getLogger(__name__) @@ -46,7 +46,7 @@ def create_subpackage(path, parent_package_name, subpackage_name="plugins"): package_name = _module_name(parent_package_name, subpackage_name) package = types.ModuleType(package_name) - package.__path__ = ([path] if isinstance(path, six.string_types) + package.__path__ = ([path] if isinstance(path, str) else list(path)) sys.modules[package_name] = package @@ -75,7 +75,7 @@ def _import_module(importer, module_name, package): # Make this accessible through the parent package for static imports local_name = module_name.partition(package.__name__ + '.')[2] module_components = local_name.split('.') - parent = six.moves.reduce(getattr, module_components[:-1], package) + parent = functools.reduce(getattr, module_components[:-1], package) setattr(parent, module_components[-1], module) return module diff --git a/heat/common/pluginutils.py b/heat/common/pluginutils.py index 4820a69bb7..e3c4bdf4e3 100644 --- a/heat/common/pluginutils.py +++ b/heat/common/pluginutils.py @@ -12,7 +12,6 @@ # under the License. from oslo_log import log as logging -import six LOG = logging.getLogger(__name__) @@ -23,5 +22,5 @@ def log_fail_msg(manager, entrypoint, exception): '"%(message)s". Not using %(name)s.', {'module_name': entrypoint.module_name, 'message': getattr(exception, 'message', - six.text_type(exception)), + str(exception)), 'name': entrypoint.name}) diff --git a/heat/common/policy.py b/heat/common/policy.py index 312608c935..86e26dd5ca 100644 --- a/heat/common/policy.py +++ b/heat/common/policy.py @@ -21,7 +21,6 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_policy import policy from oslo_utils import excutils -import six from heat.common import exception from heat.common.i18n import _ @@ -151,7 +150,7 @@ class ResourceEnforcer(Enforcer): except policy.PolicyNotRegistered: result = True except self.exc as ex: - LOG.info(six.text_type(ex)) + LOG.info(str(ex)) raise if not result: if self.exc: diff --git a/heat/common/serializers.py b/heat/common/serializers.py index 3125ba98ba..a9ccd9576a 100644 --- a/heat/common/serializers.py +++ b/heat/common/serializers.py @@ -23,7 +23,6 @@ import datetime from lxml import etree from oslo_log import log as logging from oslo_serialization import jsonutils -import six LOG = logging.getLogger(__name__) @@ -34,7 +33,7 @@ class JSONResponseSerializer(object): def sanitizer(obj): if isinstance(obj, datetime.datetime): return obj.isoformat() - return six.text_type(obj) + return str(obj) response = jsonutils.dumps(data, default=sanitizer) @@ -46,7 +45,7 @@ class JSONResponseSerializer(object): def default(self, response, result): response.content_type = 'application/json' - response.body = six.b(self.to_json(result)) + response.body = self.to_json(result).encode('latin-1') # Escape XML serialization for these keys, as the AWS API defines them as @@ -75,11 +74,11 @@ class XMLResponseSerializer(object): else: self.object_to_element(value, subelement) else: - element.text = six.text_type(obj) + element.text = str(obj) def to_xml(self, data): # Assumption : root node is dict with single key - root = next(six.iterkeys(data)) + root = next(iter(data.keys())) eltree = etree.Element(root) self.object_to_element(data.get(root), eltree) response = etree.tostring(eltree) diff --git a/heat/common/short_id.py b/heat/common/short_id.py index ef4acd0bb1..54221d3366 100644 --- a/heat/common/short_id.py +++ b/heat/common/short_id.py @@ -19,8 +19,6 @@ The IDs each comprise 12 (lower-case) alphanumeric characters. import base64 import uuid -import six - from heat.common.i18n import _ @@ -30,12 +28,12 @@ def _to_byte_string(value, num_bits): Padding is added at the end (i.e. after the least-significant bit) if required. """ - shifts = six.moves.xrange(num_bits - 8, -8, -8) + shifts = range(num_bits - 8, -8, -8) def byte_at(off): return (value >> off if off >= 0 else value << -off) & 0xff - return b''.join(six.int2byte(byte_at(offset)) for offset in shifts) + return b''.join(bytes((byte_at(offset),)) for offset in shifts) def get_id(source_uuid): @@ -43,7 +41,7 @@ def get_id(source_uuid): The supplied UUID must be a version 4 UUID object. """ - if isinstance(source_uuid, six.string_types): + if isinstance(source_uuid, str): source_uuid = uuid.UUID(source_uuid) if source_uuid.version != 4: raise ValueError(_('Invalid UUID version (%d)') % source_uuid.version) diff --git a/heat/engine/attributes.py b/heat/engine/attributes.py index f5fcdf2655..07d3abbdfd 100644 --- a/heat/engine/attributes.py +++ b/heat/engine/attributes.py @@ -17,7 +17,6 @@ from oslo_utils import strutils import six from heat.common.i18n import _ -from heat.common.i18n import repr_wrapper from heat.engine import constraints as constr from heat.engine import support @@ -139,7 +138,6 @@ BASE_ATTRIBUTES = (SHOW_ATTR, ) = ('show', ) ALL_ATTRIBUTES = '*' -@repr_wrapper class Attributes(collections.Mapping): """Models a collection of Resource Attributes.""" diff --git a/heat/engine/dependencies.py b/heat/engine/dependencies.py index 6015670a23..3c84b9e6d0 100644 --- a/heat/engine/dependencies.py +++ b/heat/engine/dependencies.py @@ -18,14 +18,12 @@ import six from heat.common import exception from heat.common.i18n import _ -from heat.common.i18n import repr_wrapper class CircularDependencyException(exception.HeatException): msg_fmt = _("Circular Dependency Found: %(cycle)s") -@repr_wrapper @six.python_2_unicode_compatible class Node(object): """A node in a dependency graph.""" @@ -172,7 +170,6 @@ class Graph(collections.defaultdict): raise CircularDependencyException(cycle=six.text_type(graph)) -@repr_wrapper @six.python_2_unicode_compatible class Dependencies(object): """Helper class for calculating a dependency graph.""" diff --git a/heat/engine/rsrc_defn.py b/heat/engine/rsrc_defn.py index 2933631e9b..1453d5b4d5 100644 --- a/heat/engine/rsrc_defn.py +++ b/heat/engine/rsrc_defn.py @@ -18,7 +18,6 @@ import operator import six from heat.common import exception -from heat.common.i18n import repr_wrapper from heat.engine import function from heat.engine import properties @@ -37,7 +36,6 @@ FIELDS = ( ) -@repr_wrapper class ResourceDefinition(object): """A definition of a resource, independent of any template format.""" diff --git a/heat/engine/scheduler.py b/heat/engine/scheduler.py index 8b7e8032cb..b9408366e0 100644 --- a/heat/engine/scheduler.py +++ b/heat/engine/scheduler.py @@ -21,7 +21,6 @@ from oslo_utils import excutils import six from heat.common.i18n import _ -from heat.common.i18n import repr_wrapper from heat.common import timeutils LOG = logging.getLogger(__name__) @@ -365,7 +364,6 @@ def wrappertask(task): # noqa: C901 return wrapper -@repr_wrapper class DependencyTaskGroup(object): """Task which manages group of subtasks that have ordering dependencies.""" diff --git a/heat/engine/update.py b/heat/engine/update.py index a3cf926962..2c9dc6a479 100644 --- a/heat/engine/update.py +++ b/heat/engine/update.py @@ -15,7 +15,6 @@ from oslo_log import log as logging import six from heat.common import exception -from heat.common.i18n import repr_wrapper from heat.engine import dependencies from heat.engine import resource from heat.engine import scheduler @@ -25,7 +24,6 @@ from heat.objects import resource as resource_objects LOG = logging.getLogger(__name__) -@repr_wrapper class StackUpdate(object): """A Task to perform the update of an existing stack to a new template.""" diff --git a/heat/tests/engine/test_scheduler.py b/heat/tests/engine/test_scheduler.py index 229834cdeb..4a7766aa15 100644 --- a/heat/tests/engine/test_scheduler.py +++ b/heat/tests/engine/test_scheduler.py @@ -18,7 +18,6 @@ import eventlet import mock import six -from heat.common.i18n import repr_wrapper from heat.common import timeutils from heat.engine import dependencies from heat.engine import scheduler @@ -1273,7 +1272,6 @@ class DescriptionTest(common.HeatTestCase): self.assertEqual('o', scheduler.task_description(C())) def test_unicode(self): - @repr_wrapper @six.python_2_unicode_compatible class C(object): def __str__(self):