From 0e01f0735cc29b74a8756dbe6c20bc8c1263883f Mon Sep 17 00:00:00 2001 From: Riccardo Pittau Date: Mon, 2 Dec 2019 14:54:30 +0100 Subject: [PATCH] Stop using six library Since we've dropped support for Python 2.7, it's time to look at the bright future that Python 3.x will bring and stop forcing compatibility with older versions. This patch removes the six library from requirements, not looking back. Change-Id: I4bf885bc7d1ccdf46dde3e0b10a8dbec304aaf9b --- ironic_lib/disk_utils.py | 4 ++-- ironic_lib/exception.py | 24 ++---------------------- ironic_lib/mdns.py | 4 ++-- ironic_lib/metrics.py | 18 ++++++++---------- ironic_lib/metrics_utils.py | 3 +-- ironic_lib/tests/test_exception.py | 18 ++---------------- ironic_lib/tests/test_metrics.py | 12 ++++++------ ironic_lib/utils.py | 13 ++++++------- lower-constraints.txt | 1 - requirements.txt | 1 - 10 files changed, 29 insertions(+), 69 deletions(-) diff --git a/ironic_lib/disk_utils.py b/ironic_lib/disk_utils.py index 365148a9..1b9b8bb4 100644 --- a/ironic_lib/disk_utils.py +++ b/ironic_lib/disk_utils.py @@ -14,6 +14,7 @@ # under the License. import gzip +import io import logging import math import os @@ -31,7 +32,6 @@ from oslo_utils import excutils from oslo_utils import imageutils from oslo_utils import units import requests -import six from ironic_lib.common.i18n import _ from ironic_lib import disk_partitioner @@ -519,7 +519,7 @@ def _get_configdrive(configdrive, node_uuid, tempdir=None): data = configdrive try: - data = six.BytesIO(base64.decode_as_bytes(data)) + data = io.BytesIO(base64.decode_as_bytes(data)) except TypeError: error_msg = (_('Config drive for node %s is not base64 encoded ' 'or the content is malformed.') % node_uuid) diff --git a/ironic_lib/exception.py b/ironic_lib/exception.py index 072a41d8..f9f30849 100644 --- a/ironic_lib/exception.py +++ b/ironic_lib/exception.py @@ -28,7 +28,6 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_serialization import jsonutils from oslo_utils import excutils -import six from ironic_lib.common.i18n import _ @@ -68,7 +67,7 @@ def _ensure_exception_kwargs_serializable(exc_class_name, kwargs): :returns: a dictionary of serializable keyword arguments. """ serializers = [(jsonutils.dumps, _('when converting to JSON')), - (six.text_type, _('when converting to string'))] + (str, _('when converting to string'))] exceptions = collections.defaultdict(list) serializable_kwargs = {} for k, v in kwargs.items(): @@ -108,7 +107,7 @@ class IronicException(Exception): with the keyword arguments provided to the constructor. If you need to access the message from an exception you should use - six.text_type(exc) + str(exc) """ @@ -148,25 +147,6 @@ class IronicException(Exception): super(IronicException, self).__init__(message) - def __str__(self): - """Encode to utf-8 then wsme api can consume it as well.""" - value = self.__unicode__() - if six.PY3: - # On Python 3 unicode is the same as str - return value - else: - return value.encode('utf-8') - - def __unicode__(self): - """Return a unicode representation of the exception message.""" - return six.text_type(self.args[0]) - - def format_message(self): - if self.__class__.__name__.endswith('_Remote'): - return self.args[0] - else: - return six.text_type(self) - class InstanceDeployFailure(IronicException): _msg_fmt = _("Failed to deploy instance: %(reason)s") diff --git a/ironic_lib/mdns.py b/ironic_lib/mdns.py index a31283c8..1109c5d4 100644 --- a/ironic_lib/mdns.py +++ b/ironic_lib/mdns.py @@ -20,11 +20,11 @@ import collections import ipaddress import socket import time +from urllib import parse as urlparse from oslo_config import cfg from oslo_config import types as cfg_types from oslo_log import log as logging -from six.moves.urllib import parse import zeroconf from ironic_lib.common.i18n import _ @@ -261,7 +261,7 @@ def get_endpoint(service_type): def _parse_endpoint(endpoint, service_type=None): params = {} - url = parse.urlparse(endpoint) + url = urlparse.urlparse(endpoint) port = url.port if port is None: diff --git a/ironic_lib/metrics.py b/ironic_lib/metrics.py index fa79f9e3..afca1354 100644 --- a/ironic_lib/metrics.py +++ b/ironic_lib/metrics.py @@ -14,11 +14,10 @@ # under the License. import abc +import functools import random import time -import six - from ironic_lib.common.i18n import _ @@ -46,7 +45,7 @@ class Timer(object): :param metrics: The metric logger :param name: The metric name """ - if not isinstance(name, six.string_types): + if not isinstance(name, str): raise TypeError(_("The metric name is expected to be a string. " "Value is %s") % name) self.metrics = metrics @@ -54,7 +53,7 @@ class Timer(object): self._start = None def __call__(self, f): - @six.wraps(f) + @functools.wraps(f) def wrapped(*args, **kwargs): start = _time() result = f(*args, **kwargs) @@ -101,7 +100,7 @@ class Counter(object): :param name: The metric name :param sample_rate: Probabilistic rate at which the values will be sent """ - if not isinstance(name, six.string_types): + if not isinstance(name, str): raise TypeError(_("The metric name is expected to be a string. " "Value is %s") % name) @@ -116,7 +115,7 @@ class Counter(object): self.sample_rate = sample_rate def __call__(self, f): - @six.wraps(f) + @functools.wraps(f) def wrapped(*args, **kwargs): self.metrics.send_counter( self.metrics.get_metric_name(self.name), @@ -156,14 +155,14 @@ class Gauge(object): :param metrics: The metric logger :param name: The metric name """ - if not isinstance(name, six.string_types): + if not isinstance(name, str): raise TypeError(_("The metric name is expected to be a string. " "Value is %s") % name) self.metrics = metrics self.name = name def __call__(self, f): - @six.wraps(f) + @functools.wraps(f) def wrapped(*args, **kwargs): result = f(*args, **kwargs) self.metrics.send_gauge(self.metrics.get_metric_name(self.name), @@ -178,8 +177,7 @@ def _time(): return time.time() -@six.add_metaclass(abc.ABCMeta) -class MetricLogger(object): +class MetricLogger(object, metaclass=abc.ABCMeta): """Abstract class representing a metrics logger. A MetricLogger sends data to a backend (noop or statsd). diff --git a/ironic_lib/metrics_utils.py b/ironic_lib/metrics_utils.py index 0b479448..4ed8d0d4 100644 --- a/ironic_lib/metrics_utils.py +++ b/ironic_lib/metrics_utils.py @@ -14,7 +14,6 @@ # under the License. from oslo_config import cfg -import six from ironic_lib.common.i18n import _ from ironic_lib import exception @@ -62,7 +61,7 @@ def get_metrics_logger(prefix='', backend=None, host=None, delimiter='.'): :param delimiter: Delimiter to use for the metrics name. :return: The new MetricLogger. """ - if not isinstance(prefix, six.string_types): + if not isinstance(prefix, str): msg = (_("This metric prefix (%s) is of unsupported type. " "Value should be a string or None") % str(prefix)) diff --git a/ironic_lib/tests/test_exception.py b/ironic_lib/tests/test_exception.py index b37f81cc..e3fa4eaa 100644 --- a/ironic_lib/tests/test_exception.py +++ b/ironic_lib/tests/test_exception.py @@ -16,7 +16,6 @@ import re import mock from oslo_config import cfg -import six from ironic_lib import exception from ironic_lib.tests import base @@ -34,22 +33,9 @@ class TestException(exception.IronicException): class TestIronicException(base.IronicLibTestCase): - def test___str__encoding(self): - expected = b'\xc3\xa9\xe0\xaf\xb2\xe0\xbe\x84' - if six.PY3: - expected = expected.decode('utf-8') - message = six.unichr(233) + six.unichr(0x0bf2) + six.unichr(3972) - exc = exception.IronicException(message) - self.assertEqual(expected, exc.__str__()) - - def test___str__non_string(self): - exc = exception.IronicException(42) - self.assertEqual("42", exc.__str__()) - self.assertEqual(u"42", exc.__unicode__()) - def test___init___json_serializable(self): exc = TestException(spam=[1, 2, 3], ham='eggs') - self.assertIn('[1, 2, 3]', six.text_type(exc)) + self.assertIn('[1, 2, 3]', str(exc)) self.assertEqual('[1, 2, 3]', exc.kwargs['spam']) def test___init___string_serializable(self): @@ -57,7 +43,7 @@ class TestIronicException(base.IronicLibTestCase): spam=type('ni', (object,), dict(a=1, b=2))(), ham='eggs' ) check_str = 'ni object at' - self.assertIn(check_str, six.text_type(exc)) + self.assertIn(check_str, str(exc)) self.assertIn(check_str, exc.kwargs['spam']) @mock.patch.object(exception.LOG, 'error', autospec=True) diff --git a/ironic_lib/tests/test_metrics.py b/ironic_lib/tests/test_metrics.py index dc75bc41..ced08bba 100644 --- a/ironic_lib/tests/test_metrics.py +++ b/ironic_lib/tests/test_metrics.py @@ -49,24 +49,24 @@ class MockedMetricLogger(metricslib.MetricLogger): class TestMetricReflection(base.IronicLibTestCase): def test_timer_reflection(self): - # Ensure our decorator is done correctly (six.wraps) and we can get the - # arguments of our decorated function. + # Ensure our decorator is done correctly (functools.wraps) and we can + # get the arguments of our decorated function. expected = ['run', 'timer'] signature = reflection.get_signature(timer_check) parameters = list(signature.parameters) self.assertEqual(expected, parameters) def test_counter_reflection(self): - # Ensure our decorator is done correctly (six.wraps) and we can get the - # arguments of our decorated function. + # Ensure our decorator is done correctly (functools.wraps) and we can + # get the arguments of our decorated function. expected = ['run', 'counter'] signature = reflection.get_signature(counter_check) parameters = list(signature.parameters) self.assertEqual(expected, parameters) def test_gauge_reflection(self): - # Ensure our decorator is done correctly (six.wraps) and we can get the - # arguments of our decorated function. + # Ensure our decorator is done correctly (functools.wraps) and we can + # get the arguments of our decorated function. expected = ['run', 'gauge'] signature = reflection.get_signature(gauge_check) parameters = list(signature.parameters) diff --git a/ironic_lib/utils.py b/ironic_lib/utils.py index d6ff8e21..983781ad 100644 --- a/ironic_lib/utils.py +++ b/ironic_lib/utils.py @@ -24,6 +24,7 @@ import ipaddress import logging import os import re +from urllib import parse as urlparse from oslo_concurrency import processutils from oslo_config import cfg @@ -32,8 +33,6 @@ from oslo_utils import excutils from oslo_utils import specs_matcher from oslo_utils import strutils from oslo_utils import units -import six -from six.moves.urllib import parse from ironic_lib.common.i18n import _ from ironic_lib import exception @@ -195,7 +194,7 @@ def _extract_hint_operator_and_values(hint_expression, hint_name): :op: The operator. An empty string in case of None. :values: A list of values stripped and converted to lowercase. """ - expression = six.text_type(hint_expression).strip().lower() + expression = str(hint_expression).strip().lower() if not expression: raise ValueError( _('Root device hint "%s" expression is empty') % hint_name) @@ -228,7 +227,7 @@ def _normalize_hint_expression(hint_expression, hint_name): :returns: A normalized string. """ hdict = _extract_hint_operator_and_values(hint_expression, hint_name) - result = hdict['op'].join([' %s ' % parse.quote(t) + result = hdict['op'].join([' %s ' % urlparse.quote(t) for t in hdict['values']]) return (hdict['op'] + result).strip() @@ -249,7 +248,7 @@ def _append_operator_to_hints(root_device): if VALID_ROOT_DEVICE_HINTS[name] is bool: continue - expression = six.text_type(expression) + expression = str(expression) ast = ROOT_DEVICE_HINTS_GRAMMAR.parseString(expression) if len(ast) > 1: continue @@ -290,7 +289,7 @@ def parse_root_device_hints(root_device): for name, expression in root_device.items(): hint_type = VALID_ROOT_DEVICE_HINTS[name] if hint_type is str: - if not isinstance(expression, six.string_types): + if not isinstance(expression, str): raise ValueError( _('Root device hint "%(name)s" is not a string value. ' 'Hint expression: %(expression)s') % @@ -517,7 +516,7 @@ def get_route_source(dest, ignore_link_local=True): try: source = out.strip().split('\n')[0].split('src')[1].split()[0] - if (ipaddress.ip_address(six.u(source)).is_link_local + if (ipaddress.ip_address(source).is_link_local and ignore_link_local): LOG.debug('Ignoring link-local source to %(dest)s: %(rec)s', {'dest': dest, 'rec': out}) diff --git a/lower-constraints.txt b/lower-constraints.txt index c67f1377..6179aa6e 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -61,7 +61,6 @@ requestsexceptions==1.2.0 restructuredtext-lint==1.1.1 rfc3986==0.3.1 Routes==2.3.1 -six==1.10.0 snowballstemmer==1.2.1 Sphinx==1.6.2 sphinxcontrib-websupport==1.0.1 diff --git a/requirements.txt b/requirements.txt index 313d2e29..dc388a57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,5 @@ oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 oslo.service!=1.28.1,>=1.24.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 requests>=2.14.2 # Apache-2.0 -six>=1.10.0 # MIT oslo.log>=3.36.0 # Apache-2.0 zeroconf>=0.24.0;python_version>='3.0' # LGPL