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: I4b60638bb0268e5d1cf54fdf7d61964082536f4f
This commit is contained in:
Riccardo Pittau 2019-12-18 10:21:29 +01:00
parent 1cd9a65c07
commit a572ae21e7
21 changed files with 86 additions and 119 deletions

View File

@ -26,11 +26,10 @@ Base utilities to build API operation managers and objects on top of.
import abc
import copy
from http import client as http_client
from urllib import parse as urlparse
from oslo_utils import strutils
import six
from six.moves import http_client
from six.moves.urllib import parse
from ironicclient.common.apiclient import exceptions
from ironicclient.common.i18n import _
@ -212,8 +211,7 @@ class BaseManager(HookableMixin):
return self.client.delete(url)
@six.add_metaclass(abc.ABCMeta)
class ManagerWithFind(BaseManager):
class ManagerWithFind(BaseManager, metaclass=abc.ABCMeta):
"""Manager with additional `find()`/`findall()` methods."""
@abc.abstractmethod
@ -341,7 +339,7 @@ class CrudManager(BaseManager):
return self._list(
'%(base_url)s%(query)s' % {
'base_url': self.build_url(base_url=base_url, **kwargs),
'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
'query': '?%s' % urlparse.urlencode(kwargs) if kwargs else '',
},
self.collection_key)
@ -380,7 +378,7 @@ class CrudManager(BaseManager):
rl = self._list(
'%(base_url)s%(query)s' % {
'base_url': self.build_url(base_url=base_url, **kwargs),
'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
'query': '?%s' % urlparse.urlencode(kwargs) if kwargs else '',
},
self.collection_key)
num = len(rl)

View File

@ -20,13 +20,10 @@
Exception definitions.
"""
from http import client as http_client
import inspect
import sys
import six
from six.moves import http_client
from ironicclient.common.i18n import _
@ -450,7 +447,7 @@ def from_response(response, method, url):
kwargs["message"] = (error.get("message") or
error.get("faultstring"))
kwargs["details"] = (error.get("details") or
six.text_type(body))
str(body))
elif content_type.startswith("text/"):
kwargs["details"] = getattr(response, 'text', '')

View File

@ -19,9 +19,7 @@ Base utilities to build API operation managers and objects on top of.
import abc
import copy
import six
import six.moves.urllib.parse as urlparse
from urllib import parse as urlparse
from ironicclient.common.apiclient import base
from ironicclient import exc
@ -39,8 +37,7 @@ def getid(obj):
return obj
@six.add_metaclass(abc.ABCMeta)
class Manager(object):
class Manager(object, metaclass=abc.ABCMeta):
"""Provides CRUD operations with a particular API."""
def __init__(self, api):
@ -55,13 +52,15 @@ class Manager(object):
return ('/v1/%s/%s' % (self._resource_name, resource_id)
if resource_id else '/v1/%s' % self._resource_name)
@abc.abstractproperty
@property
@abc.abstractmethod
def resource_class(self):
"""The resource class
"""
@abc.abstractproperty
@property
@abc.abstractmethod
def _resource_name(self):
"""The resource name.
@ -259,11 +258,11 @@ class Manager(object):
self.api.raw_request('DELETE', self._path(resource_id))
@six.add_metaclass(abc.ABCMeta)
class CreateManager(Manager):
class CreateManager(Manager, metaclass=abc.ABCMeta):
"""Provides creation operations with a particular API."""
@abc.abstractproperty
@property
@abc.abstractmethod
def _creation_attributes(self):
"""A list of required creation attributes for a resource type.

View File

@ -14,6 +14,8 @@
# under the License.
from distutils.version import StrictVersion
import functools
from http import client as http_client
import logging
import os
import re
@ -21,13 +23,11 @@ import socket
import ssl
import textwrap
import time
from urllib import parse as urlparse
from keystoneauth1 import adapter
from keystoneauth1 import exceptions as kexc
from oslo_serialization import jsonutils
import six
from six.moves import http_client
import six.moves.urllib.parse as urlparse
from ironicclient.common import filecache
from ironicclient.common.i18n import _
@ -196,7 +196,7 @@ class VersionNegotiationMixin(object):
% {'req': requested_version,
'min': min_ver, 'max': max_ver}))
if isinstance(requested_version, six.string_types):
if isinstance(requested_version, str):
if requested_version == 'latest':
negotiated_ver = max_ver
else:
@ -276,7 +276,7 @@ _RETRY_EXCEPTIONS = (exc.Conflict, exc.ServiceUnavailable,
def with_retries(func):
"""Wrapper for _http_request adding support for retries."""
@six.wraps(func)
@functools.wraps(func)
def wrapper(self, url, method, **kwargs):
if self.conflict_max_retries is None:
self.conflict_max_retries = DEFAULT_MAX_RETRIES
@ -303,7 +303,7 @@ def with_retries(func):
return wrapper
class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection):
class VerifiedHTTPSConnection(http_client.HTTPSConnection):
"""httplib-compatible connection using client-side SSL authentication
:see http://code.activestate.com/recipes/
@ -312,9 +312,9 @@ class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection):
def __init__(self, host, port, key_file=None, cert_file=None,
ca_file=None, timeout=None, insecure=False):
six.moves.http_client.HTTPSConnection.__init__(self, host, port,
key_file=key_file,
cert_file=cert_file)
http_client.HTTPSConnection.__init__(self, host, port,
key_file=key_file,
cert_file=cert_file)
self.key_file = key_file
self.cert_file = cert_file
if ca_file is not None:
@ -380,7 +380,7 @@ class SessionClient(VersionNegotiationMixin, adapter.LegacyJsonAdapter):
self.api_version_select_state = api_version_select_state
self.conflict_max_retries = max_retries
self.conflict_retry_interval = retry_interval
if isinstance(kwargs.get('endpoint_override'), six.string_types):
if isinstance(kwargs.get('endpoint_override'), str):
kwargs['endpoint_override'] = _trim_endpoint_api_version(
kwargs['endpoint_override'])
@ -421,7 +421,7 @@ class SessionClient(VersionNegotiationMixin, adapter.LegacyJsonAdapter):
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('auth', self.auth)
if isinstance(self.endpoint_override, six.string_types):
if isinstance(self.endpoint_override, str):
kwargs.setdefault('endpoint_override', self.endpoint_override)
if getattr(self, 'os_ironic_api_version', None):

View File

@ -28,7 +28,6 @@ import time
from oslo_serialization import base64
from oslo_utils import strutils
import six
from ironicclient.common.i18n import _
from ironicclient import exc
@ -163,7 +162,7 @@ def convert_list_props_to_comma_separated(data, props=None):
for prop in props:
val = data.get(prop, None)
if isinstance(val, list):
result[prop] = ', '.join(map(six.text_type, val))
result[prop] = ', '.join(map(str, val))
return result

View File

@ -12,10 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import configparser
import os
import six
import six.moves.configparser as config_parser
from tempest.lib.cli import base
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
@ -60,16 +59,12 @@ class FunctionalTestBase(base.ClientTestBase):
def _get_config(self):
config_file = os.environ.get('IRONICCLIENT_TEST_CONFIG',
DEFAULT_CONFIG_FILE)
# SafeConfigParser was deprecated in Python 3.2
if six.PY3:
config = config_parser.ConfigParser()
else:
config = config_parser.SafeConfigParser()
config = configparser.ConfigParser()
if not config.read(config_file):
self.skipTest('Skipping, no test config found @ %s' % config_file)
try:
auth_strategy = config.get('functional', 'auth_strategy')
except config_parser.NoOptionError:
except configparser.NoOptionError:
auth_strategy = 'keystone'
if auth_strategy not in ['keystone', 'noauth']:
raise self.fail(
@ -92,7 +87,7 @@ class FunctionalTestBase(base.ClientTestBase):
for c in conf_settings + keystone_v3_conf_settings:
try:
cli_flags[c] = config.get('functional', c)
except config_parser.NoOptionError:
except configparser.NoOptionError:
# NOTE(vdrok): Here we ignore the absence of KS v3 options as
# v2 may be used. Keystone client will do the actual check of
# the parameters' correctness.

View File

@ -13,7 +13,6 @@
import json
import ddt
import six
from tempest.lib.common.utils import data_utils
from tempest.lib import exceptions
@ -160,9 +159,7 @@ class BaremetalDeployTemplateTests(base.TestCase):
@ddt.data(
('--uuid', '', 'expected one argument'),
('--uuid', '!@#$^*&%^', 'Expected a UUID'),
('', '',
'too few arguments' if six.PY2
else 'the following arguments are required'),
('', '', 'the following arguments are required'),
('', 'not/a/name', 'Deploy template name must be a valid trait'),
('', 'foo', 'Deploy template name must be a valid trait'),
('--steps', '', 'expected one argument'),

View File

@ -13,7 +13,6 @@
# under the License.
import ddt
import six
from tempest.lib import exceptions
from ironicclient.tests.functional.osc.v1 import base
@ -44,5 +43,5 @@ class BaremetalNodeCreateNegativeTests(base.TestCase):
def test_baremetal_node_create(self, argument, value, ex_text):
base_cmd = 'baremetal node create --driver %s' % self.driver_name
command = self.construct_cmd(base_cmd, argument, value)
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
from tempest.lib import exceptions
from ironicclient.tests.functional.osc.v1 import base
@ -44,8 +43,7 @@ class TestNodeListFields(base.TestCase):
fields = ['instance_uuid', 'name', 'uuid']
node_list = self.openstack(
'baremetal node list --fields {}'
.format(' '.join(fields)))
'baremetal node list --fields {}'.format(' '.join(fields)))
nodes_list_headers = self._get_table_headers(node_list)
self.assertEqual(headers, nodes_list_headers)
@ -53,14 +51,14 @@ class TestNodeListFields(base.TestCase):
def test_list_no_fields(self):
command = 'baremetal node list --fields'
ex_text = 'expected at least one argument'
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
def test_list_wrong_field(self):
command = 'baremetal node list --fields ABC'
ex_text = 'invalid choice'
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
class TestNodeShowFields(base.TestCase):
@ -117,8 +115,8 @@ class TestNodeShowFields(base.TestCase):
'uuid']
node_show = self.openstack(
'baremetal node show {} --fields {} {}'
.format(self.node['uuid'], ' '.join(rows), self.api_version))
'baremetal node show {} --fields {} {}'.format(
self.node['uuid'], ' '.join(rows), self.api_version))
nodes_show_rows = self._get_table_rows(node_show)
self.assertEqual(set(rows), set(nodes_show_rows))
@ -127,12 +125,12 @@ class TestNodeShowFields(base.TestCase):
command = 'baremetal node show {} --fields {}'.format(
self.node['uuid'], self.api_version)
ex_text = 'expected at least one argument'
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
def test_show_wrong_field(self):
command = 'baremetal node show {} --fields ABC {}'.format(
self.node['uuid'], self.api_version)
ex_text = 'invalid choice'
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)

View File

@ -13,7 +13,6 @@
# under the License.
import ddt
import six
from tempest.lib import exceptions
from ironicclient.tests.functional.osc.v1 import base
@ -28,9 +27,7 @@ class BaremetalNodeNegativeTests(base.TestCase):
self.node = self.node_create()
@ddt.data(
('', '',
'error: argument --driver is required' if six.PY2
else 'error: the following arguments are required: --driver'),
('', '', 'error: the following arguments are required: --driver'),
('--driver', 'wrongdriver',
'No valid host was found. Reason: No conductor service '
'registered which supports driver wrongdriver.')
@ -40,29 +37,26 @@ class BaremetalNodeNegativeTests(base.TestCase):
"""Negative test for baremetal node driver options."""
base_cmd = 'baremetal node create'
command = self.construct_cmd(base_cmd, argument, value)
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
def test_delete_no_node(self):
"""Test for baremetal node delete without node specified."""
command = 'baremetal node delete'
ex_text = 'error: too few arguments'
if six.PY3:
ex_text = ''
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
ex_text = ''
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
def test_list_wrong_argument(self):
"""Test for baremetal node list with wrong argument."""
command = 'baremetal node list --wrong_arg'
ex_text = 'error: unrecognized arguments: --wrong_arg'
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
@ddt.data(
('--property', '',
'error: too few arguments' if six.PY2
else 'error: the following arguments are required: <node>'),
'error: the following arguments are required: <node>'),
('--property', 'prop', 'Attributes must be a list of PATH=VALUE')
)
@ddt.unpack
@ -71,13 +65,12 @@ class BaremetalNodeNegativeTests(base.TestCase):
base_cmd = 'baremetal node set'
command = self.construct_cmd(base_cmd, argument, value,
self.node['uuid'])
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)
@ddt.data(
('--property', '',
'error: too few arguments' if six.PY2
else 'error: the following arguments are required: <node>'),
'error: the following arguments are required: <node>'),
('--property', 'prop', "Reason: can't remove non-existent object")
)
@ddt.unpack
@ -86,5 +79,5 @@ class BaremetalNodeNegativeTests(base.TestCase):
base_cmd = 'baremetal node unset'
command = self.construct_cmd(base_cmd, argument, value,
self.node['uuid'])
six.assertRaisesRegex(self, exceptions.CommandFailed, ex_text,
self.openstack, command)
self.assertRaisesRegex(exceptions.CommandFailed, ex_text,
self.openstack, command)

View File

@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
def get_dict_from_output(output):
"""Parse list of dictionaries, return a dictionary.
@ -22,7 +20,7 @@ def get_dict_from_output(output):
"""
obj = {}
for item in output:
obj[item['Property']] = six.text_type(item['Value'])
obj[item['Property']] = str(item['Value'])
return obj

View File

@ -13,9 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from http import client as http_client
from oslotest import base as test_base
import six
from six.moves import http_client
from ironicclient.common.apiclient import exceptions
@ -89,17 +89,17 @@ class ExceptionsArgsTest(test_base.BaseTestCase):
json_data1 = {"error_message": {"debuginfo": None,
"faultcode": "Client",
"faultstring": "fake message"}}
message = six.text_type(
message = str(
json_data1["error_message"]["faultstring"])
details = six.text_type(json_data1)
details = str(json_data1)
self.assert_exception(
exceptions.BadRequest, method, url, status_code, json_data1,
message, details)
json_data2 = {"badRequest": {"message": "fake message",
"code": http_client.BAD_REQUEST}}
message = six.text_type(json_data2["badRequest"]["message"])
details = six.text_type(json_data2)
message = str(json_data2["badRequest"]["message"])
details = str(json_data2)
self.assert_exception(
exceptions.BadRequest, method, url, status_code, json_data2,
message, details)

View File

@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
from http import client as http_client
import time
import mock
from oslo_serialization import jsonutils
from six.moves import http_client
from keystoneauth1 import exceptions as kexc

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import builtins
import json
import os
import subprocess
@ -20,7 +21,6 @@ import sys
import tempfile
import mock
import six.moves.builtins as __builtin__
from ironicclient.common import utils
from ironicclient import exc
@ -355,7 +355,7 @@ class HandleJsonFileTest(test_utils.BaseTestCase):
self.assertEqual(json.loads(contents), steps)
@mock.patch.object(__builtin__, 'open', autospec=True)
@mock.patch.object(builtins, 'open', autospec=True)
def test_handle_json_or_file_arg_file_fail(self, mock_open):
mock_file_object = mock.MagicMock()
mock_file_handle = mock.MagicMock()

View File

@ -13,8 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from http import client as http_client
import mock
from six.moves import http_client
from ironicclient.common.apiclient import exceptions
from ironicclient import exc

View File

@ -14,13 +14,13 @@
# under the License.
import copy
import io
import os
import fixtures
import mock
from oslo_utils import strutils
import requests
import six
import testtools
@ -58,7 +58,7 @@ class FakeAPI(object):
def raw_request(self, *args, **kwargs):
response = self._request(*args, **kwargs)
body_iter = iter(six.StringIO(response[1]))
body_iter = iter(io.StringIO(response[1]))
return FakeResponse(response[0]), body_iter
def json_request(self, *args, **kwargs):

View File

@ -10,10 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import builtins
import jsonschema
import mock
import six
import six.moves.builtins as __builtin__
from ironicclient import exc
from ironicclient.tests.unit import utils
@ -193,14 +192,14 @@ class CreateResourcesTest(utils.BaseTestCase):
class LoadFromFileTest(utils.BaseTestCase):
@mock.patch.object(__builtin__, 'open',
@mock.patch.object(builtins, 'open',
mock.mock_open(read_data='{"a": "b"}'))
def test_load_json(self):
fname = 'abc.json'
res = create_resources.load_from_file(fname)
self.assertEqual({'a': 'b'}, res)
@mock.patch.object(__builtin__, 'open',
@mock.patch.object(builtins, 'open',
mock.mock_open(read_data='{"a": "b"}'))
def test_load_unknown_extension(self):
fname = 'abc'
@ -208,7 +207,7 @@ class LoadFromFileTest(utils.BaseTestCase):
'must have .json or .yaml extension',
create_resources.load_from_file, fname)
@mock.patch.object(__builtin__, 'open', autospec=True)
@mock.patch.object(builtins, 'open', autospec=True)
def test_load_ioerror(self, mock_open):
mock_open.side_effect = IOError('file does not exist')
fname = 'abc.json'
@ -216,7 +215,7 @@ class LoadFromFileTest(utils.BaseTestCase):
'Cannot read file',
create_resources.load_from_file, fname)
@mock.patch.object(__builtin__, 'open',
@mock.patch.object(builtins, 'open',
mock.mock_open(read_data='{{bbb'))
def test_load_incorrect_json(self):
fname = 'abc.json'
@ -224,14 +223,14 @@ class LoadFromFileTest(utils.BaseTestCase):
exc.ClientException, 'File "%s" is invalid' % fname,
create_resources.load_from_file, fname)
@mock.patch.object(__builtin__, 'open',
@mock.patch.object(builtins, 'open',
mock.mock_open(read_data='---\na: b'))
def test_load_yaml(self):
fname = 'abc.yaml'
res = create_resources.load_from_file(fname)
self.assertEqual({'a': 'b'}, res)
@mock.patch.object(__builtin__, 'open',
@mock.patch.object(builtins, 'open',
mock.mock_open(read_data='---\na-: - b'))
def test_load_incorrect_yaml(self):
fname = 'abc.yaml'
@ -365,7 +364,7 @@ class CreateMethodsTest(utils.BaseTestCase):
'node-uuid-1', 'pg-uuid-2')
self.assertEqual(1, len(errs))
self.assertIsInstance(errs[0], exc.ClientException)
self.assertIn('port group', six.text_type(errs[0]))
self.assertIn('port group', str(errs[0]))
self.assertFalse(self.client.port.create.called)
@mock.patch.object(create_resources, 'create_portgroups', autospec=True)

View File

@ -17,7 +17,6 @@ import tempfile
import time
import mock
import six
import testtools
from testtools.matchers import HasLength
@ -28,9 +27,6 @@ from ironicclient.v1 import node
from ironicclient.v1 import volume_connector
from ironicclient.v1 import volume_target
if six.PY3:
import io
file = io.BytesIO
NODE1 = {'uuid': '66666666-7777-8888-9999-000000000000',
'chassis_uuid': 'aaaaaaaa-1111-bbbb-2222-cccccccccccc',

View File

@ -10,10 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
import json
import jsonschema
import six
import yaml
from ironicclient import exc
@ -61,14 +61,14 @@ def create_resources(client, filenames):
if errors:
raise exc.ClientException('While validating the resources file(s), the'
' following error(s) were encountered:\n%s' %
'\n'.join(six.text_type(e) for e in errors))
'\n'.join(str(e) for e in errors))
for r in resources:
errors.extend(create_chassis(client, r.get('chassis', [])))
errors.extend(create_nodes(client, r.get('nodes', [])))
if errors:
raise exc.ClientException('During resources creation, the following '
'error(s) were encountered:\n%s' %
'\n'.join(six.text_type(e) for e in errors))
'\n'.join(str(e) for e in errors))
def load_from_file(filename):
@ -113,7 +113,7 @@ def create_single_handler(resource_type):
"""
def outer_wrapper(create_method):
@six.wraps(create_method)
@functools.wraps(create_method)
def wrapper(client, **params):
uuid = None
error = None

View File

@ -85,7 +85,6 @@ requestsexceptions==1.2.0
restructuredtext-lint==1.1.1
rfc3986==0.3.1
simplejson==3.5.1
six==1.10.0
snowballstemmer==1.2.1
Sphinx==1.6.2
sphinxcontrib-websupport==1.0.1

View File

@ -13,4 +13,3 @@ oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
PyYAML>=3.12 # MIT
requests>=2.14.2 # Apache-2.0
six>=1.10.0 # MIT