From d870b40583b2b735e43a061110380717929598ed Mon Sep 17 00:00:00 2001 From: Ivan Kolodyazhny Date: Thu, 9 Jan 2020 16:49:18 +0200 Subject: [PATCH] Remove six usage from openstack_dashboard package We don't support Python 2 anymore so we don't need this compatibility library. six.reraise usages are left as is until it'll be moved to some base lib like oslo.utils to not re-implenent this method in Horizon. This patch also removes Python2-specific base test case methods assertItemsEqual and assertNotRegexpMatches in flavor of new Python 3 analogues. Change-Id: I26a59176be9e9f213128e4945a58b9459334b626 --- openstack_dashboard/api/base.py | 16 +++--------- openstack_dashboard/api/glance.py | 23 +++++------------ openstack_dashboard/api/keystone.py | 8 +++--- openstack_dashboard/api/neutron.py | 16 +++--------- openstack_dashboard/api/rest/glance.py | 3 +-- openstack_dashboard/api/rest/json_encoder.py | 9 ------- openstack_dashboard/api/rest/swift.py | 3 --- openstack_dashboard/api/swift.py | 4 +-- .../contrib/developer/profiler/api.py | 8 +++--- .../contrib/developer/profiler/middleware.py | 3 +-- .../admin/group_types/specs/tables.py | 3 ++- .../dashboards/admin/images/views.py | 2 +- .../dashboards/admin/metadata_defs/tests.py | 9 ++----- .../admin/volume_types/qos_specs/tables.py | 3 ++- .../identity/application_credentials/tests.py | 5 ++-- .../dashboards/project/api_access/tests.py | 6 ++--- .../dashboards/project/floating_ips/tests.py | 6 ++--- .../dashboards/project/images/images/forms.py | 7 +++--- .../dashboards/project/images/images/tests.py | 15 ++++------- .../dashboards/project/images/tests.py | 4 +-- .../dashboards/project/instances/forms.py | 3 +-- .../dashboards/project/instances/tests.py | 4 +-- .../dashboards/project/instances/utils.py | 3 +-- .../instances/workflows/create_instance.py | 5 ++-- .../dashboards/project/key_pairs/tables.py | 3 ++- .../dashboards/project/key_pairs/tests.py | 8 +++--- .../dashboards/project/networks/tests.py | 10 +++----- .../dashboards/project/routers/tests.py | 4 +-- .../project/security_groups/forms.py | 6 +---- .../project/security_groups/tables.py | 5 ++-- .../project/security_groups/tests.py | 3 +-- .../dashboards/project/volumes/tests.py | 7 ++---- .../dashboards/settings/password/tests.py | 3 ++- .../management/commands/horizon.wsgi.template | 4 --- .../management/commands/make_web_conf.py | 6 +---- openstack_dashboard/templatetags/themes.py | 2 +- openstack_dashboard/test/helpers.py | 25 ++++++++----------- .../test/integration_tests/helpers.py | 4 +-- .../integration_tests/pages/navigation.py | 17 +++++-------- .../integration_tests/pages/pageobject.py | 4 +-- .../test/integration_tests/regions/forms.py | 9 +++---- .../test/test_data/exceptions.py | 5 ---- .../test/unit/api/test_keystone.py | 5 ++-- .../test/unit/api/test_neutron.py | 5 ++-- openstack_dashboard/test/unit/test_views.py | 10 +++----- openstack_dashboard/utils/config.py | 4 +-- openstack_dashboard/utils/config_types.py | 14 +++++------ openstack_dashboard/views.py | 2 +- 48 files changed, 111 insertions(+), 222 deletions(-) diff --git a/openstack_dashboard/api/base.py b/openstack_dashboard/api/base.py index 833dd48cba..43ec3f9388 100644 --- a/openstack_dashboard/api/base.py +++ b/openstack_dashboard/api/base.py @@ -16,24 +16,14 @@ # License for the specific language governing permissions and limitations # under the License. -import collections +from collections import abc as collections import functools from django.conf import settings import semantic_version -import six from horizon import exceptions -# Python 3.8 removes the ability to import the abstract base classes from -# 'collections', but 'collections.abc' is not present in Python 2.7 -# TODO(stephenfin): Remove when we drop support for Python 2.7 -# pylint: disable=ungrouped-imports -if hasattr(collections, 'abc'): - from collections.abc import Sequence -else: - from collections import Sequence - __all__ = ('APIResourceWrapper', 'APIDictWrapper', 'get_service_from_catalog', 'url_for',) @@ -121,7 +111,7 @@ class APIVersionManager(object): # Provide a helpful error message if the specified version isn't in the # supported list. if version not in self.supported: - choices = ", ".join(str(k) for k in six.iterkeys(self.supported)) + choices = ", ".join(str(k) for k in self.supported) msg = ('%s is not a supported API version for the %s service, ' ' choices are: %s' % (version, self.service_type, choices)) raise exceptions.ConfigurationError(msg) @@ -230,7 +220,7 @@ class Quota(object): return "" % (self.name, self.limit) -class QuotaSet(Sequence): +class QuotaSet(collections.Sequence): """Wrapper for client QuotaSet objects. This turns the individual quotas into Quota objects diff --git a/openstack_dashboard/api/glance.py b/openstack_dashboard/api/glance.py index 6233bf1a28..7dd56ff3fc 100644 --- a/openstack_dashboard/api/glance.py +++ b/openstack_dashboard/api/glance.py @@ -19,7 +19,9 @@ from __future__ import absolute_import from __future__ import division +import _thread as thread import collections +from collections import abc import itertools import json import logging @@ -32,8 +34,7 @@ from django.core.files.uploadedfile import TemporaryUploadedFile from django.utils.translation import ugettext_lazy as _ from glanceclient.v2 import client -import six -from six.moves import _thread as thread + from horizon import messages from horizon.utils.memoized import memoized @@ -41,15 +42,6 @@ from openstack_dashboard.api import base from openstack_dashboard.contrib.developer.profiler import api as profiler from openstack_dashboard.utils import settings as utils -# Python 3.8 removes the ability to import the abstract base classes from -# 'collections', but 'collections.abc' is not present in Python 2.7 -# TODO(stephenfin): Remove when we drop support for Python 2.7 -# pylint: disable=ungrouped-imports -if hasattr(collections, 'abc'): - from collections.abc import Iterable -else: - from collections import Iterable - LOG = logging.getLogger(__name__) VERSIONS = base.APIVersionManager("image", preferred_version=2) @@ -119,7 +111,7 @@ class Image(base.APIResourceWrapper): return prop_name not in (self._attrs | self._ext_attrs) def to_dict(self, show_ext_attrs=False): - if not isinstance(self._apiresource, Iterable): + if not isinstance(self._apiresource, abc.Iterable): return self._apiresource.to_dict() image_dict = super(Image, self).to_dict() image_dict['is_public'] = self.is_public @@ -501,16 +493,13 @@ def image_create(request, **kwargs): glanceclient(request).images.add_location(image.id, location, {}) if data: - if isinstance(data, six.string_types): + if isinstance(data, str): # The image data is meant to be uploaded externally, return a # special wrapper to bypass the web server in a subsequent upload return ExternallyUploadedImage(image, request) elif isinstance(data, TemporaryUploadedFile): # Hack to fool Django, so we can keep file open in the new thread. - if six.PY2: - data.file.close_called = True - else: - data.file._closer.close_called = True + data.file._closer.close_called = True elif isinstance(data, InMemoryUploadedFile): # Clone a new file for InMemeoryUploadedFile. # Because the old one will be closed by Django. diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index 55e592c1ac..96d6dd455c 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -19,11 +19,10 @@ import collections import logging +from urllib import parse from django.conf import settings from django.utils.translation import ugettext_lazy as _ -import six -import six.moves.urllib.parse as urlparse from keystoneauth1 import session from keystoneauth1 import token_endpoint @@ -70,7 +69,6 @@ except ImportError: pass -@six.python_2_unicode_compatible class Service(base.APIDictWrapper): """Wrapper for a dict based on the service data from keystone.""" _attrs = ['id', 'type', 'name'] @@ -81,7 +79,7 @@ class Service(base.APIDictWrapper): 'publicURL') self.url = base.get_url_for_service(service, region, 'internalURL') if self.url: - self.host = urlparse.urlparse(self.url).hostname + self.host = parse.urlparse(self.url).hostname else: self.host = None self.disabled = None @@ -95,7 +93,7 @@ class Service(base.APIDictWrapper): return self.type def __repr__(self): - return "" % six.text_type(self) + return "" % self def _get_endpoint_url(request, endpoint_type, catalog=None): diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index c51ef9e932..ca0443d71f 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -20,6 +20,7 @@ from __future__ import absolute_import import collections +from collections.abc import Sequence import copy import logging @@ -30,7 +31,6 @@ from django.utils.translation import ugettext_lazy as _ from neutronclient.common import exceptions as neutron_exc from neutronclient.v2_0 import client as neutron_client from novaclient import exceptions as nova_exc -import six from horizon import exceptions from horizon import messages @@ -41,15 +41,6 @@ from openstack_dashboard.contrib.developer.profiler import api as profiler from openstack_dashboard import policy from openstack_dashboard.utils import settings as setting_utils -# Python 3.8 removes the ability to import the abstract base classes from -# 'collections', but 'collections.abc' is not present in Python 2.7 -# TODO(stephenfin): Remove when we drop support for Python 2.7 -# pylint: disable=ungrouped-imports -if hasattr(collections, 'abc'): - from collections.abc import Sequence -else: - from collections import Sequence - LOG = logging.getLogger(__name__) @@ -255,7 +246,6 @@ class SecurityGroup(NeutronAPIDictWrapper): return {k: self._apidict[k] for k in self._apidict if k != 'rules'} -@six.python_2_unicode_compatible class SecurityGroupRule(NeutronAPIDictWrapper): # Required attributes: # id, parent_group_id @@ -864,7 +854,7 @@ def list_resources_with_long_filters(list_method, # filter_values) and do not consider other filter conditions # which may be specified in **params. - if isinstance(filter_values, six.string_types): + if isinstance(filter_values, str): filter_values = [filter_values] elif not isinstance(filter_values, Sequence): filter_values = list(filter_values) @@ -1762,7 +1752,7 @@ def servers_update_addresses(request, servers, all_tenants=False): ports_floating_ips, network_names) except Exception as e: - LOG.error(six.text_type(e)) + LOG.error(str(e)) else: server.addresses = addresses diff --git a/openstack_dashboard/api/rest/glance.py b/openstack_dashboard/api/rest/glance.py index 85bb789444..90368ddf0e 100644 --- a/openstack_dashboard/api/rest/glance.py +++ b/openstack_dashboard/api/rest/glance.py @@ -16,7 +16,6 @@ from django import forms from django.views.decorators.csrf import csrf_exempt from django.views import generic -from six.moves import zip as izip from openstack_dashboard import api from openstack_dashboard.api.rest import urls @@ -278,7 +277,7 @@ class MetadefsNamespaces(generic.View): ) names = ('items', 'has_more_data', 'has_prev_data') - return dict(izip(names, api.glance.metadefs_namespace_full_list( + return dict(zip(names, api.glance.metadefs_namespace_full_list( request, filters=filters, **kwargs ))) diff --git a/openstack_dashboard/api/rest/json_encoder.py b/openstack_dashboard/api/rest/json_encoder.py index 789c937747..50cf8d3586 100644 --- a/openstack_dashboard/api/rest/json_encoder.py +++ b/openstack_dashboard/api/rest/json_encoder.py @@ -15,7 +15,6 @@ import json import json.encoder as encoder from django.utils.translation import ugettext_lazy as _ -import six class NaNJSONEncoder(json.JSONEncoder): @@ -44,14 +43,6 @@ class NaNJSONEncoder(json.JSONEncoder): else: _encoder = encoder.encode_basestring - # On Python 3, JSONEncoder has no more encoding attribute, it produces - # an Unicode string - if six.PY2 and self.encoding != 'utf-8': - def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): - if isinstance(o, str): - o = o.decode(_encoding) - return _orig_encoder(o) - def floatstr(o, allow_nan=self.allow_nan, _repr=float.__repr__, _inf=encoder.INFINITY, _neginf=-encoder.INFINITY): # Check for specials. Note that this type of test is processor diff --git a/openstack_dashboard/api/rest/swift.py b/openstack_dashboard/api/rest/swift.py index 273ec7bc38..457084e41e 100644 --- a/openstack_dashboard/api/rest/swift.py +++ b/openstack_dashboard/api/rest/swift.py @@ -20,7 +20,6 @@ from django.http import StreamingHttpResponse from django.utils.http import urlunquote from django.views.decorators.csrf import csrf_exempt from django.views import generic -import six from horizon import exceptions from openstack_dashboard import api @@ -227,8 +226,6 @@ class Object(generic.View): filename = "%s%s" % (filename, ext) response = StreamingHttpResponse(obj.data) safe = filename.replace(",", "") - if six.PY2: - safe = safe.encode('utf-8') response['Content-Disposition'] = 'attachment; filename="%s"' % safe response['Content-Type'] = 'application/octet-stream' response['Content-Length'] = obj.bytes diff --git a/openstack_dashboard/api/swift.py b/openstack_dashboard/api/swift.py index 5d10fc4456..0fad7f97c5 100644 --- a/openstack_dashboard/api/swift.py +++ b/openstack_dashboard/api/swift.py @@ -17,10 +17,10 @@ # under the License. from datetime import datetime +from urllib import parse import functools -import six.moves.urllib.parse as urlparse import swiftclient from django.conf import settings @@ -181,7 +181,7 @@ def swift_get_container(request, container_name, with_data=True): swift_endpoint = base.url_for(request, 'object-store', endpoint_type='publicURL') - parameters = urlparse.quote(container_name.encode('utf8')) + parameters = parse.quote(container_name.encode('utf8')) public_url = swift_endpoint + '/' + parameters ts_float = float(headers.get('x-timestamp')) timestamp = datetime.utcfromtimestamp(ts_float).isoformat() diff --git a/openstack_dashboard/contrib/developer/profiler/api.py b/openstack_dashboard/contrib/developer/profiler/api.py index 9c49754f65..8055bf558f 100644 --- a/openstack_dashboard/contrib/developer/profiler/api.py +++ b/openstack_dashboard/contrib/developer/profiler/api.py @@ -15,6 +15,7 @@ import contextlib import json +from urllib.parse import urlparse from django.conf import settings from osprofiler import _utils as utils @@ -22,8 +23,6 @@ from osprofiler.drivers.base import get_driver as profiler_get_driver from osprofiler import notifier from osprofiler import profiler from osprofiler import web -import six -from six.moves.urllib.parse import urlparse from horizon.utils import settings as horizon_settings @@ -119,9 +118,8 @@ def update_trace_headers(keys, **kwargs): trace_info.update(kwargs) p = profiler.get() trace_data = utils.signed_pack(trace_info, p.hmac_key) - if six.PY3: - trace_data = [key.decode() if isinstance(key, six.binary_type) - else key for key in trace_data] + trace_data = [key.decode() if isinstance(key, bytes) + else key for key in trace_data] return json.dumps({web.X_TRACE_INFO: trace_data[0], web.X_TRACE_HMAC: trace_data[1]}) diff --git a/openstack_dashboard/contrib/developer/profiler/middleware.py b/openstack_dashboard/contrib/developer/profiler/middleware.py index 0baaacda87..dfd2056e04 100644 --- a/openstack_dashboard/contrib/developer/profiler/middleware.py +++ b/openstack_dashboard/contrib/developer/profiler/middleware.py @@ -21,7 +21,6 @@ from django.utils.translation import ugettext_lazy as _ from osprofiler import _utils as profiler_utils from osprofiler import profiler from osprofiler import web -import six from horizon import messages from horizon.utils import settings as horizon_settings @@ -98,7 +97,7 @@ class ProfilerMiddleware(object): def _trace_is_valid(trace_info): if not isinstance(trace_info, dict): return False - trace_keys = set(six.iterkeys(trace_info)) + trace_keys = trace_info.keys() if not all(k in trace_keys for k in _REQUIRED_KEYS): return False if trace_keys.difference(_REQUIRED_KEYS + _OPTIONAL_KEYS): diff --git a/openstack_dashboard/dashboards/admin/group_types/specs/tables.py b/openstack_dashboard/dashboards/admin/group_types/specs/tables.py index e0b68a211e..a5cabed775 100644 --- a/openstack_dashboard/dashboards/admin/group_types/specs/tables.py +++ b/openstack_dashboard/dashboards/admin/group_types/specs/tables.py @@ -10,10 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib import parse + from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy -from six.moves.urllib import parse from horizon import tables diff --git a/openstack_dashboard/dashboards/admin/images/views.py b/openstack_dashboard/dashboards/admin/images/views.py index 41fd2f3cd0..f22dca6420 100644 --- a/openstack_dashboard/dashboards/admin/images/views.py +++ b/openstack_dashboard/dashboards/admin/images/views.py @@ -16,10 +16,10 @@ # License for the specific language governing permissions and limitations # under the License. +import builtins import logging from oslo_utils import units -from six.moves import builtins from django.urls import reverse from django.urls import reverse_lazy diff --git a/openstack_dashboard/dashboards/admin/metadata_defs/tests.py b/openstack_dashboard/dashboards/admin/metadata_defs/tests.py index 59a3169826..31b216b676 100644 --- a/openstack_dashboard/dashboards/admin/metadata_defs/tests.py +++ b/openstack_dashboard/dashboards/admin/metadata_defs/tests.py @@ -19,7 +19,6 @@ import json from django.urls import reverse import mock -import six from openstack_dashboard import api from openstack_dashboard.dashboards.admin.metadata_defs \ @@ -258,12 +257,8 @@ class MetadataDefinitionsCreateViewTest(test.BaseAdminViewTests): res = self.client.post(reverse(constants.METADATA_CREATE_URL), form_data) - if six.PY3: - err_msg = ('There was a problem loading the namespace: ' - 'Expecting value: line 1 column 1 (char 0).') - else: - err_msg = ('There was a problem loading the namespace: ' - 'No JSON object could be decoded.') + err_msg = ('There was a problem loading the namespace: ' + 'Expecting value: line 1 column 1 (char 0).') self.assertFormError(res, "form", None, [err_msg]) def test_admin_metadata_defs_create_namespace_empty_json_post_raw(self): diff --git a/openstack_dashboard/dashboards/admin/volume_types/qos_specs/tables.py b/openstack_dashboard/dashboards/admin/volume_types/qos_specs/tables.py index aaa8354334..edd60dab06 100644 --- a/openstack_dashboard/dashboards/admin/volume_types/qos_specs/tables.py +++ b/openstack_dashboard/dashboards/admin/volume_types/qos_specs/tables.py @@ -10,10 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib import parse + from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy -from six.moves.urllib import parse from horizon import tables diff --git a/openstack_dashboard/dashboards/identity/application_credentials/tests.py b/openstack_dashboard/dashboards/identity/application_credentials/tests.py index d3b849b4ed..f5e0d5b589 100644 --- a/openstack_dashboard/dashboards/identity/application_credentials/tests.py +++ b/openstack_dashboard/dashboards/identity/application_credentials/tests.py @@ -13,7 +13,6 @@ # under the License. import mock -import six from django.urls import reverse @@ -80,7 +79,7 @@ class ApplicationCredentialViewTests(test.TestCase): self.assertEqual(res.context['application_credential'].name, app_cred.name) mock_app_cred_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(app_cred.id)) + str(app_cred.id)) @mock.patch.object(api.keystone, 'application_credential_get') def test_application_credential_detail_get_with_exception( @@ -94,7 +93,7 @@ class ApplicationCredentialViewTests(test.TestCase): res = self.client.get(url) self.assertRedirectsNoFollow(res, APP_CREDS_INDEX_URL) mock_app_cred_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(app_cred.id)) + app_cred.id) @mock.patch.object(api.keystone, 'application_credential_create') @mock.patch.object(api.keystone, 'get_identity_api_version') diff --git a/openstack_dashboard/dashboards/project/api_access/tests.py b/openstack_dashboard/dashboards/project/api_access/tests.py index b5f5aaff8d..875e1c8127 100644 --- a/openstack_dashboard/dashboards/project/api_access/tests.py +++ b/openstack_dashboard/dashboards/project/api_access/tests.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -import six import yaml from django import template @@ -150,9 +149,8 @@ class UnicodeTenantNameRCTests(test.TestCase): result_content_disposition = res['content-disposition'] - if six.PY3: - result_content_disposition = result_content_disposition.\ - encode('latin-1') + result_content_disposition = result_content_disposition.\ + encode('latin-1') self.assertEqual(expected, result_content_disposition) diff --git a/openstack_dashboard/dashboards/project/floating_ips/tests.py b/openstack_dashboard/dashboards/project/floating_ips/tests.py index e2c8059ec2..4664d11a18 100644 --- a/openstack_dashboard/dashboards/project/floating_ips/tests.py +++ b/openstack_dashboard/dashboards/project/floating_ips/tests.py @@ -21,7 +21,6 @@ from django.urls import reverse from django.utils.http import urlencode import mock -import six from openstack_dashboard import api from openstack_dashboard.test import helpers as test @@ -293,8 +292,7 @@ class FloatingIpViewTests(test.TestCase): allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') self.assertEqual(set(['ajax-modal']), set(allocate_action.classes)) - self.assertEqual('Allocate IP To Project', - six.text_type(allocate_action.verbose_name)) + self.assertEqual('Allocate IP To Project', allocate_action.verbose_name) self.assertIsNone(allocate_action.policy_rules) url = 'horizon:project:floating_ips:allocate' @@ -337,7 +335,7 @@ class FloatingIpViewTests(test.TestCase): self.assertIn('disabled', allocate_action.classes, 'The create button should be disabled') self.assertEqual('Allocate IP To Project (Quota exceeded)', - six.text_type(allocate_action.verbose_name)) + allocate_action.verbose_name) self.mock_tenant_floating_ip_list.assert_called_once_with( test.IsHttpRequest()) diff --git a/openstack_dashboard/dashboards/project/images/images/forms.py b/openstack_dashboard/dashboards/project/images/images/forms.py index 0665db1add..94401edb6e 100644 --- a/openstack_dashboard/dashboards/project/images/images/forms.py +++ b/openstack_dashboard/dashboards/project/images/images/forms.py @@ -26,7 +26,6 @@ from django.forms import ValidationError from django.forms.widgets import HiddenInput from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ -import six from horizon import exceptions from horizon import forms @@ -46,8 +45,10 @@ class ImageURLField(forms.URLField): if api.glance.get_image_upload_mode() == 'direct': FileField = forms.ExternalFileField - CreateParent = six.with_metaclass(forms.ExternalUploadMeta, - forms.SelfHandlingForm) + + class CreateParent(forms.SelfHandlingForm, + metaclass=forms.ExternalUploadMeta): + pass else: FileField = forms.FileField CreateParent = forms.SelfHandlingForm diff --git a/openstack_dashboard/dashboards/project/images/images/tests.py b/openstack_dashboard/dashboards/project/images/images/tests.py index 66f21363a4..b450c596f3 100644 --- a/openstack_dashboard/dashboards/project/images/images/tests.py +++ b/openstack_dashboard/dashboards/project/images/images/tests.py @@ -24,7 +24,6 @@ from django.test.utils import override_settings from django.urls import reverse import mock -import six from horizon import tables as horizon_tables from openstack_dashboard import api @@ -265,8 +264,7 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase): 'horizon/common/_detail.html') self.assertEqual(res.context['image'].name, image.name) self.assertEqual(res.context['image'].protected, image.protected) - mock_image_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(image.id)) + mock_image_get.assert_called_once_with(test.IsHttpRequest(), image.id) def test_image_detail_get_v2(self): image = self.imagesV2.first() @@ -296,8 +294,7 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase): self.assertContains(res, '
foo
') self.assertContains(res, '
foo val
') - mock_image_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(image.id)) + mock_image_get.assert_called_once_with(test.IsHttpRequest(), image.id) def test_image_detail_custom_props_get_v2(self): image = self.imagesV2.list()[2] @@ -316,7 +313,7 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase): self.assertEqual(res.context['image'].protected, image.protected) mock_image_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(image.id)) + image.id) def test_protected_image_detail_get_v2(self): image = self.imagesV2.list()[1] @@ -333,8 +330,7 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase): args=[image.id]) res = self.client.get(url) self.assertRedirectsNoFollow(res, IMAGES_INDEX_URL) - mock_image_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(image.id)) + mock_image_get.assert_called_once_with(test.IsHttpRequest(), image.id) @mock.patch.object(api.glance, 'image_get') def test_image_update_get(self, mock_image_get): @@ -353,8 +349,7 @@ class ImageViewTests(test.ResetImageAPIVersionMixin, test.TestCase): " name='is_public' checked='checked'>", html=True, msg_prefix="The is_public checkbox is not checked") - mock_image_get.assert_called_once_with(test.IsHttpRequest(), - six.text_type(image.id)) + mock_image_get.assert_called_once_with(test.IsHttpRequest(), image.id) class OwnerFilterTests(test.TestCase): diff --git a/openstack_dashboard/dashboards/project/images/tests.py b/openstack_dashboard/dashboards/project/images/tests.py index 2768aeda49..07413808fa 100644 --- a/openstack_dashboard/dashboards/project/images/tests.py +++ b/openstack_dashboard/dashboards/project/images/tests.py @@ -25,7 +25,6 @@ import unittest from django.urls import reverse import mock -import six from horizon import exceptions @@ -133,8 +132,7 @@ class ImagesAndSnapshotsTests(BaseImagesTestCase): row_actions = snaps.get_row_actions(snaps.data[2]) # third instance - status queued, only delete is available self.assertEqual(len(row_actions), 1) - self.assertEqual(six.text_type(row_actions[0].verbose_name), - u"Delete Image") + self.assertEqual(row_actions[0].verbose_name, u"Delete Image") self.assertEqual(str(row_actions[0]), "") self.mock_image_list.assert_called_once_with(test.IsHttpRequest(), diff --git a/openstack_dashboard/dashboards/project/instances/forms.py b/openstack_dashboard/dashboards/project/instances/forms.py index 7b4703efd6..9f9ee85049 100644 --- a/openstack_dashboard/dashboards/project/instances/forms.py +++ b/openstack_dashboard/dashboards/project/instances/forms.py @@ -18,7 +18,6 @@ from django.urls import reverse from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ from django.views.decorators.debug import sensitive_variables -import six from horizon import exceptions from horizon import forms @@ -239,7 +238,7 @@ class AttachVolume(forms.SelfHandlingForm): redirect = reverse('horizon:project:instances:index') if isinstance(ex, api.nova.VolumeMultiattachNotSupported): # Use the specific error from the specific message. - msg = six.text_type(ex) + msg = str(ex) else: # Use a generic error message. msg = _('Unable to attach volume: %s') % ex diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 49e9e933d3..7b9df1fbb1 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -21,7 +21,6 @@ import json import logging import sys -import django from django.conf import settings from django.forms import widgets from django import http @@ -31,7 +30,6 @@ from django.urls import reverse from django.utils.http import urlencode import mock from novaclient import api_versions -import six from horizon import exceptions from horizon import forms @@ -4287,7 +4285,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase, self.assertIn('disabled', launch_action.classes, 'The launch button should be disabled') self.assertEqual('Launch Instance (Quota exceeded)', - six.text_type(launch_action.verbose_name)) + launch_action.verbose_name) self._check_extension_supported({'AdminActions': 20, 'Shelve': 5}) diff --git a/openstack_dashboard/dashboards/project/instances/utils.py b/openstack_dashboard/dashboards/project/instances/utils.py index 2b2352ef1f..961cca9fcc 100644 --- a/openstack_dashboard/dashboards/project/instances/utils.py +++ b/openstack_dashboard/dashboards/project/instances/utils.py @@ -15,7 +15,6 @@ from operator import itemgetter from django.conf import settings from django.utils.translation import ugettext_lazy as _ -import six from horizon import exceptions @@ -103,7 +102,7 @@ def network_field_data(request, include_empty_option=False, with_cidr=False, networks = api.neutron.network_list_for_tenant( request, tenant_id, **extra_params) except Exception as e: - msg = _('Failed to get network list {0}').format(six.text_type(e)) + msg = _('Failed to get network list {0}').format(e) exceptions.handle(request, msg) _networks = [] diff --git a/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py b/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py index aab3e719db..acd23c87bb 100644 --- a/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py +++ b/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py @@ -21,7 +21,6 @@ import logging import operator from oslo_utils import units -import six from django.template.defaultfilters import filesizeformat from django.utils.text import normalize_newlines @@ -690,14 +689,14 @@ class CustomizeAction(workflows.Action): script = upload_file.read() if script != "": try: - if not isinstance(script, six.text_type): + if not isinstance(script, str): script = script.decode() normalize_newlines(script) except Exception as e: msg = _('There was a problem parsing the' ' %(prefix)s: %(error)s') msg = msg % {'prefix': prefix, - 'error': six.text_type(e)} + 'error': e} raise forms.ValidationError(msg) return script else: diff --git a/openstack_dashboard/dashboards/project/key_pairs/tables.py b/openstack_dashboard/dashboards/project/key_pairs/tables.py index b94e20ca66..468e386ad3 100644 --- a/openstack_dashboard/dashboards/project/key_pairs/tables.py +++ b/openstack_dashboard/dashboards/project/key_pairs/tables.py @@ -12,11 +12,12 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib import parse + from django import urls from django.utils.text import format_lazy from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy -from six.moves.urllib import parse from horizon import tables diff --git a/openstack_dashboard/dashboards/project/key_pairs/tests.py b/openstack_dashboard/dashboards/project/key_pairs/tests.py index 8b52f92244..0f5ce7391a 100644 --- a/openstack_dashboard/dashboards/project/key_pairs/tests.py +++ b/openstack_dashboard/dashboards/project/key_pairs/tests.py @@ -16,10 +16,10 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib import parse + from django.urls import reverse import mock -import six -from six.moves.urllib import parse from openstack_dashboard import api from openstack_dashboard.dashboards.project.key_pairs.forms \ @@ -156,7 +156,7 @@ class KeyPairTests(test.TestCase): url = reverse('horizon:project:key_pairs:import') res = self.client.post(url, formData, follow=True) self.assertEqual(res.redirect_chain, []) - msg = six.text_type(KEYPAIR_ERROR_MESSAGES['invalid']) + msg = str(KEYPAIR_ERROR_MESSAGES['invalid']) self.assertFormErrors(res, count=1, message=msg) def test_import_keypair_space_key_name(self): @@ -171,7 +171,7 @@ class KeyPairTests(test.TestCase): url = reverse('horizon:project:key_pairs:import') res = self.client.post(url, formData, follow=True) self.assertEqual(res.redirect_chain, []) - msg = six.text_type(KEYPAIR_ERROR_MESSAGES['invalid']) + msg = str(KEYPAIR_ERROR_MESSAGES['invalid']) self.assertFormErrors(res, count=1, message=msg) @test.create_mocks({api.nova: ('keypair_import',)}) diff --git a/openstack_dashboard/dashboards/project/networks/tests.py b/openstack_dashboard/dashboards/project/networks/tests.py index ffe42d3017..69db99346f 100644 --- a/openstack_dashboard/dashboards/project/networks/tests.py +++ b/openstack_dashboard/dashboards/project/networks/tests.py @@ -18,7 +18,6 @@ from django.urls import reverse from django.utils.html import escape from django.utils.http import urlunquote import mock -import six from horizon.workflows import views @@ -1260,8 +1259,7 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self.assertEqual(set(['ajax-modal']), set(create_action.classes)) self.assertEqual('horizon:project:networks:create', create_action.url) - self.assertEqual('Create Network', - six.text_type(create_action.verbose_name)) + self.assertEqual('Create Network', create_action.verbose_name) self.assertEqual((('network', 'create_network'),), create_action.policy_rules) @@ -1273,8 +1271,7 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self.assertEqual(set(['ajax-modal']), set(create_action.classes)) self.assertEqual('horizon:project:networks:createsubnet', create_action.url) - self.assertEqual('Create Subnet', - six.text_type(create_action.verbose_name)) + self.assertEqual('Create Subnet', create_action.verbose_name) self.assertEqual((('network', 'create_subnet'),), create_action.policy_rules) @@ -1335,7 +1332,6 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin): self.assertEqual(set(['ajax-modal']), set(create_action.classes)) self.assertEqual('horizon:project:networks:addport', create_action.url) - self.assertEqual('Create Port', - six.text_type(create_action.verbose_name)) + self.assertEqual('Create Port', create_action.verbose_name) self.assertEqual((('network', 'create_port'),), create_action.policy_rules) diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py index cc8882c0a3..08374fa544 100644 --- a/openstack_dashboard/dashboards/project/routers/tests.py +++ b/openstack_dashboard/dashboards/project/routers/tests.py @@ -16,7 +16,6 @@ import copy from django.urls import reverse import mock -import six from openstack_dashboard import api from openstack_dashboard.test import helpers as test @@ -1258,8 +1257,7 @@ class RouterViewTests(RouterMixin, test.TestCase): create_action = self.getAndAssertTableAction(res, 'routers', 'create') self.assertEqual(set(['ajax-modal']), set(create_action.classes)) - self.assertEqual('Create Router', - six.text_type(create_action.verbose_name)) + self.assertEqual('Create Router', create_action.verbose_name) self.assertEqual('horizon:project:routers:create', create_action.url) self.assertEqual((('network', 'create_router'),), create_action.policy_rules) diff --git a/openstack_dashboard/dashboards/project/security_groups/forms.py b/openstack_dashboard/dashboards/project/security_groups/forms.py index 1441a12979..ab461f2c05 100644 --- a/openstack_dashboard/dashboards/project/security_groups/forms.py +++ b/openstack_dashboard/dashboards/project/security_groups/forms.py @@ -23,8 +23,6 @@ from django.forms import ValidationError from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -import six - from horizon import exceptions from horizon import forms from horizon import messages @@ -484,9 +482,7 @@ class AddRule(forms.SelfHandlingForm): data['cidr'], data['security_group'], **params) - messages.success(request, - _('Successfully added rule: %s') - % six.text_type(rule)) + messages.success(request, _('Successfully added rule: %s') % rule) return rule except exceptions.Conflict as error: exceptions.handle(request, error, redirect=redirect) diff --git a/openstack_dashboard/dashboards/project/security_groups/tables.py b/openstack_dashboard/dashboards/project/security_groups/tables.py index d04abfaaae..50501fd1a7 100644 --- a/openstack_dashboard/dashboards/project/security_groups/tables.py +++ b/openstack_dashboard/dashboards/project/security_groups/tables.py @@ -19,7 +19,6 @@ from django.template import defaultfilters from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy -import six from horizon import exceptions from horizon import tables @@ -213,7 +212,7 @@ def filter_direction(direction): def filter_protocol(protocol): if protocol is None: return _('Any') - return six.text_type.upper(protocol) + return protocol.upper() def check_rule_template(port, ip_proto): @@ -269,7 +268,7 @@ class RulesTable(tables.DataTable): return filters.get_int_or_uuid(obj_id) def get_object_display(self, rule): - return six.text_type(rule) + return str(rule) class Meta(object): name = "rules" diff --git a/openstack_dashboard/dashboards/project/security_groups/tests.py b/openstack_dashboard/dashboards/project/security_groups/tests.py index 27dcf45dff..4351ff2901 100644 --- a/openstack_dashboard/dashboards/project/security_groups/tests.py +++ b/openstack_dashboard/dashboards/project/security_groups/tests.py @@ -17,7 +17,6 @@ # under the License. import mock -import six from django.conf import settings from django.urls import reverse @@ -113,7 +112,7 @@ class SecurityGroupsViewTests(test.TestCase): 'create') self.assertEqual('Create Security Group', - six.text_type(create_action.verbose_name)) + create_action.verbose_name) self.assertIsNone(create_action.policy_rules) self.assertEqual(set(['ajax-modal']), set(create_action.classes)) diff --git a/openstack_dashboard/dashboards/project/volumes/tests.py b/openstack_dashboard/dashboards/project/volumes/tests.py index 64a601121f..0c3c3c4535 100644 --- a/openstack_dashboard/dashboards/project/volumes/tests.py +++ b/openstack_dashboard/dashboards/project/volumes/tests.py @@ -15,7 +15,6 @@ import copy import mock -import six from django.conf import settings from django.forms import widgets @@ -1354,10 +1353,8 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase): self.assertEqual(set(['ajax-modal', 'ajax-update', 'btn-create']), set(create_action.classes)) - self.assertEqual('Create Volume', - six.text_type(create_action.verbose_name)) - self.assertEqual('horizon:project:volumes:create', - create_action.url) + self.assertEqual('Create Volume', create_action.verbose_name) + self.assertEqual('horizon:project:volumes:create', create_action.url) self.assertEqual((('volume', 'volume:create'),), create_action.policy_rules) self.assertEqual(5, self.mock_volume_backup_supported.call_count) diff --git a/openstack_dashboard/dashboards/settings/password/tests.py b/openstack_dashboard/dashboards/settings/password/tests.py index 22d808172f..78b2358119 100644 --- a/openstack_dashboard/dashboards/settings/password/tests.py +++ b/openstack_dashboard/dashboards/settings/password/tests.py @@ -12,10 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib.parse import urlsplit + from django.conf import settings from django import http from django.urls import reverse -from django.utils.six.moves.urllib.parse import urlsplit import mock diff --git a/openstack_dashboard/management/commands/horizon.wsgi.template b/openstack_dashboard/management/commands/horizon.wsgi.template index c079c57052..82a0b203ef 100644 --- a/openstack_dashboard/management/commands/horizon.wsgi.template +++ b/openstack_dashboard/management/commands/horizon.wsgi.template @@ -13,14 +13,10 @@ {% if ACTIVATE_THIS %} activate_this = '{{ ACTIVATE_THIS }}' -{% if PY2 %} -execfile(activate_this, dict(__file__=activate_this)) -{% elif PY3 %} exec( compile(open(activate_this, "rb").read(), activate_this, 'exec'), dict(__file__=activate_this) ) -{% endif %} # We import now instead of at the top of the module to use the virtual env {% endif %} import os diff --git a/openstack_dashboard/management/commands/make_web_conf.py b/openstack_dashboard/management/commands/make_web_conf.py index 8501fba410..d644fb65d9 100644 --- a/openstack_dashboard/management/commands/make_web_conf.py +++ b/openstack_dashboard/management/commands/make_web_conf.py @@ -20,8 +20,6 @@ import subprocess import sys import warnings -import six - from django.conf import settings from django.core.management import base from django import template @@ -78,8 +76,6 @@ context = template.Context({ 'SSLKEY': '/etc/pki/tls/private/ca.key', 'CACERT': None, 'PROCESSES': multiprocessing.cpu_count() + 1, - 'PY2': six.PY2, - 'PY3': six.PY3, 'PYTHON_EXEC': sys.executable, }) @@ -120,7 +116,7 @@ for cmd in APACHE2_VERSION_CMDS: try: reg = re.compile(cmd[1]) output = subprocess.check_output(cmd[0], stderr=subprocess.STDOUT) - if isinstance(output, six.binary_type): + if isinstance(output, bytes): output = output.decode() res = reg.search(output) if res: diff --git a/openstack_dashboard/templatetags/themes.py b/openstack_dashboard/templatetags/themes.py index c2d779a41c..30ab7fba7e 100644 --- a/openstack_dashboard/templatetags/themes.py +++ b/openstack_dashboard/templatetags/themes.py @@ -17,7 +17,7 @@ from __future__ import absolute_import import os -from six.moves.urllib.request import pathname2url +from urllib.request import pathname2url from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage diff --git a/openstack_dashboard/test/helpers.py b/openstack_dashboard/test/helpers.py index b68a6297f2..cc55d45303 100644 --- a/openstack_dashboard/test/helpers.py +++ b/openstack_dashboard/test/helpers.py @@ -17,7 +17,7 @@ # under the License. from functools import wraps -from importlib import import_module +import importlib import logging import os import traceback @@ -34,8 +34,6 @@ import mock from openstack_auth import user from openstack_auth import utils from requests.packages.urllib3.connection import HTTPConnection -import six -from six import moves from horizon import base from horizon import conf @@ -273,7 +271,7 @@ class TestCase(horizon_helpers.TestCase): Asserts that the given response issued a 302 redirect without processing the view which is redirected to. """ - loc = six.text_type(response._headers.get('location', None)[1]) + loc = str(response._headers.get('location', None)[1]) loc = http.urlunquote(loc) expected_url = http.urlunquote(expected_url) self.assertEqual(loc, expected_url) @@ -308,7 +306,7 @@ class TestCase(horizon_helpers.TestCase): assert len(errors) == count, \ "%d errors were found on the form, %d expected" % \ (len(errors), count) - if message and message not in six.text_type(errors): + if message and message not in str(errors): self.fail("Expected message not found, instead found: %s" % ["%s: %s" % (key, [e for e in field_errors]) for (key, field_errors) in errors.items()]) @@ -332,13 +330,11 @@ class TestCase(horizon_helpers.TestCase): def getAndAssertTableRowAction(self, response, table_name, action_name, row_id): table = response.context[table_name + '_table'] - rows = list(moves.filter(lambda x: x.id == row_id, - table.data)) + rows = list(filter(lambda x: x.id == row_id, table.data)) self.assertEqual(1, len(rows), "Did not find a row matching id '%s'" % row_id) row_actions = table.get_row_actions(rows[0]) - actions = list(moves.filter(lambda x: x.name == action_name, - row_actions)) + actions = list(filter(lambda x: x.name == action_name, row_actions)) msg_args = (action_name, table_name, row_id) self.assertGreater( @@ -356,8 +352,7 @@ class TestCase(horizon_helpers.TestCase): table = response.context[table_name + '_table'] table_actions = table.get_table_actions() - actions = list(moves.filter(lambda x: x.name == action_name, - table_actions)) + actions = list(filter(lambda x: x.name == action_name, table_actions)) msg_args = (action_name, table_name) self.assertGreater( len(actions), 0, @@ -419,7 +414,7 @@ class TestCase(horizon_helpers.TestCase): count, len(errors), "%d errors were found on the workflow, %d expected" % (len(errors), count)) - if message and message not in six.text_type(errors): + if message and message not in str(errors): self.fail("Expected message not found, instead found: %s" % ["%s: %s" % (key, [e for e in field_errors]) for (key, field_errors) in errors.items()]) @@ -441,7 +436,7 @@ class BaseAdminViewTests(TestCase): def setSessionValues(self, **kwargs): settings.SESSION_ENGINE = 'django.contrib.sessions.backends.file' - engine = import_module(settings.SESSION_ENGINE) + engine = importlib.import_module(settings.SESSION_ENGINE) store = engine.SessionStore() for key in kwargs: store[key] = kwargs[key] @@ -572,7 +567,7 @@ class PluginTestCase(TestCase): del base.Horizon base.Horizon = base.HorizonSite() # Reload the convenience references to Horizon stored in __init__ - moves.reload_module(import_module("horizon")) + importlib.reload(importlib.import_module("horizon")) # Re-register our original dashboards and panels. # This is necessary because autodiscovery only works on the first # import, and calling reload introduces innumerable additional @@ -592,7 +587,7 @@ class PluginTestCase(TestCase): only for testing and should never be used on a live site. """ urls.clear_url_caches() - moves.reload_module(import_module(settings.ROOT_URLCONF)) + importlib.reload(importlib.import_module(settings.ROOT_URLCONF)) base.Horizon._urls() diff --git a/openstack_dashboard/test/integration_tests/helpers.py b/openstack_dashboard/test/integration_tests/helpers.py index 7a3d01a1a1..bb1046f9aa 100644 --- a/openstack_dashboard/test/integration_tests/helpers.py +++ b/openstack_dashboard/test/integration_tests/helpers.py @@ -11,6 +11,7 @@ # under the License. import contextlib +import io import logging import os import shutil @@ -25,7 +26,6 @@ from oslo_utils import uuidutils from selenium.webdriver.common import action_chains from selenium.webdriver.common import by from selenium.webdriver.common import keys -from six import StringIO import testtools import xvfbwrapper @@ -210,7 +210,7 @@ class BaseTestCase(testtools.TestCase): """ # clear other handlers to set target handler ROOT_LOGGER.handlers[:] = [] - self._log_buffer = StringIO() + self._log_buffer = io.StringIO() stream_handler = logging.StreamHandler(stream=self._log_buffer) stream_handler.setLevel(logging.DEBUG) formatter = logging.Formatter( diff --git a/openstack_dashboard/test/integration_tests/pages/navigation.py b/openstack_dashboard/test/integration_tests/pages/navigation.py index 04fb760d73..68fb4dbe30 100644 --- a/openstack_dashboard/test/integration_tests/pages/navigation.py +++ b/openstack_dashboard/test/integration_tests/pages/navigation.py @@ -13,9 +13,9 @@ import functools import importlib import json +import types from selenium.webdriver.common import by -import six from openstack_dashboard.test.integration_tests import config @@ -316,18 +316,13 @@ class Navigation(object): @classmethod def _create_go_to_method(cls, path, class_name=None): go_to_method = Navigation.GoToMethodFactory(path, class_name) - inst_method = six.create_unbound_method(go_to_method, Navigation) + inst_method = types.MethodType(go_to_method, Navigation) - # TODO(e0ne): remove python2 support once all integration jobs - # will be switched to python3. - if six.PY3: - def _go_to_page(self, path): - return Navigation._go_to_page(self, path) + def _go_to_page(self, path): + return Navigation._go_to_page(self, path) - wrapped_go_to = functools.partialmethod(_go_to_page, path) - setattr(Navigation, inst_method.name, wrapped_go_to) - else: - setattr(Navigation, inst_method.name, inst_method) + wrapped_go_to = functools.partialmethod(_go_to_page, path) + setattr(Navigation, inst_method.name, wrapped_go_to) @classmethod def unify_page_path(cls, path, preserve_spaces=True): diff --git a/openstack_dashboard/test/integration_tests/pages/pageobject.py b/openstack_dashboard/test/integration_tests/pages/pageobject.py index 26948162d1..058ab20d07 100644 --- a/openstack_dashboard/test/integration_tests/pages/pageobject.py +++ b/openstack_dashboard/test/integration_tests/pages/pageobject.py @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. -import six.moves.urllib.parse as urlparse +from urllib import parse from openstack_dashboard.test.integration_tests import basewebobject @@ -43,7 +43,7 @@ class PageObject(basewebobject.BaseWebObject): base_url = self.conf.dashboard.dashboard_url if not base_url.endswith('/'): base_url += '/' - return urlparse.urljoin(base_url, self.PARTIAL_LOGIN_URL) + return parse.urljoin(base_url, self.PARTIAL_LOGIN_URL) def get_url_current_page(self): return self.driver.current_url diff --git a/openstack_dashboard/test/integration_tests/regions/forms.py b/openstack_dashboard/test/integration_tests/regions/forms.py index ece5eff5e9..7b276a2737 100644 --- a/openstack_dashboard/test/integration_tests/regions/forms.py +++ b/openstack_dashboard/test/integration_tests/regions/forms.py @@ -17,7 +17,6 @@ from django.utils import html from selenium.common import exceptions from selenium.webdriver.common import by import selenium.webdriver.support.ui as Support -import six from openstack_dashboard.test.integration_tests.regions import baseregion from openstack_dashboard.test.integration_tests.regions import menus @@ -59,8 +58,8 @@ class MetaBaseFormFieldRegion(type): super(MetaBaseFormFieldRegion, cls).__init__(name, bases, dct) -@six.add_metaclass(MetaBaseFormFieldRegion) -class BaseFormFieldRegion(baseregion.BaseRegion): +class BaseFormFieldRegion(baseregion.BaseRegion, + metaclass=MetaBaseFormFieldRegion): """Base class for form fields classes.""" _label_locator = None @@ -352,7 +351,7 @@ class FormRegion(BaseFormRegion): self.fields_src_elem = self._get_element(*self._fields_locator) fields = self._get_form_fields() for accessor_name, accessor_expr in self.field_mappings.items(): - if isinstance(accessor_expr, six.string_types): + if isinstance(accessor_expr, str): self._dynamic_properties[accessor_name] = fields[accessor_expr] else: # it is a class self._dynamic_properties[accessor_name] = accessor_expr( @@ -449,7 +448,7 @@ class TabbedFormRegion(FormRegion): fields = self._get_form_fields() current_tab_mappings = self.field_mappings[tab_index] for accessor_name, accessor_expr in current_tab_mappings.items(): - if isinstance(accessor_expr, six.string_types): + if isinstance(accessor_expr, str): self._dynamic_properties[accessor_name] = fields[accessor_expr] else: # it is a class self._dynamic_properties[accessor_name] = accessor_expr( diff --git a/openstack_dashboard/test/test_data/exceptions.py b/openstack_dashboard/test/test_data/exceptions.py index 9364d6379c..9defeb3e2e 100644 --- a/openstack_dashboard/test/test_data/exceptions.py +++ b/openstack_dashboard/test/test_data/exceptions.py @@ -17,7 +17,6 @@ import glanceclient.exc as glance_exceptions from keystoneclient import exceptions as keystone_exceptions from neutronclient.common import exceptions as neutron_exceptions from novaclient import exceptions as nova_exceptions -import six from swiftclient import client as swift_exceptions from openstack_dashboard.test.test_data import utils @@ -44,12 +43,8 @@ def create_stubbed_exception(cls, status_code=500): def fake_str(self): return str(self.message) - def fake_unicode(self): - return six.text_type(self.message) - cls.__init__ = fake_init_exception cls.__str__ = fake_str - cls.__unicode__ = fake_unicode cls.silence_logging = True return cls(status_code, msg) diff --git a/openstack_dashboard/test/unit/api/test_keystone.py b/openstack_dashboard/test/unit/api/test_keystone.py index 280428422a..5ed2aa420d 100644 --- a/openstack_dashboard/test/unit/api/test_keystone.py +++ b/openstack_dashboard/test/unit/api/test_keystone.py @@ -19,7 +19,6 @@ from __future__ import absolute_import import mock -import six from openstack_dashboard import api from openstack_dashboard.test import helpers as test @@ -78,7 +77,7 @@ class ServiceAPITests(test.APIMockTestCase): identity_data['id'] = 1 region = identity_data["endpoints"][0]["region"] service = api.keystone.Service(identity_data, region) - self.assertEqual(u"identity (native backend)", six.text_type(service)) + self.assertEqual(u"identity (native backend)", str(service)) self.assertEqual(identity_data["endpoints"][0]["region"], service.region) self.assertEqual("http://int.keystone.example.com/identity/v3", @@ -93,7 +92,7 @@ class ServiceAPITests(test.APIMockTestCase): compute_data['id'] = 1 region = compute_data["endpoints"][1]["region"] service = api.keystone.Service(compute_data, region) - self.assertEqual(u"compute", six.text_type(service)) + self.assertEqual(u"compute", str(service)) self.assertEqual(compute_data["endpoints"][1]["region"], service.region) self.assertEqual("http://int.nova2.example.com:8774/v2", diff --git a/openstack_dashboard/test/unit/api/test_neutron.py b/openstack_dashboard/test/unit/api/test_neutron.py index 5b122a479f..959e0924f4 100644 --- a/openstack_dashboard/test/unit/api/test_neutron.py +++ b/openstack_dashboard/test/unit/api/test_neutron.py @@ -17,7 +17,6 @@ import mock import netaddr from neutronclient.common import exceptions as neutron_exc from oslo_utils import uuidutils -import six from django.test.utils import override_settings @@ -1154,7 +1153,7 @@ class NeutronApiSecurityGroupTests(test.APIMockTestCase): # 'security_group_rules' field, so .get() method needs to be used. exp_rules = exp_sg.get('security_group_rules', []) self.assertEqual(len(exp_rules), len(ret_sg.rules)) - for (exprule, retrule) in six.moves.zip(exp_rules, ret_sg.rules): + for (exprule, retrule) in zip(exp_rules, ret_sg.rules): self._cmp_sg_rule(exprule, retrule) def _test_security_group_list(self, **params): @@ -1168,7 +1167,7 @@ class NeutronApiSecurityGroupTests(test.APIMockTestCase): rets = api.neutron.security_group_list(self.request, **params) self.assertEqual(len(sgs), len(rets)) - for (exp, ret) in six.moves.zip(sgs, rets): + for (exp, ret) in zip(sgs, rets): self._cmp_sg(exp, ret) self.qclient.list_security_groups.assert_called_once_with(**q_params) diff --git a/openstack_dashboard/test/unit/test_views.py b/openstack_dashboard/test/unit/test_views.py index ea23e4a6b7..6f43764430 100644 --- a/openstack_dashboard/test/unit/test_views.py +++ b/openstack_dashboard/test/unit/test_views.py @@ -10,8 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import six - from openstack_dashboard.test import helpers as test from openstack_dashboard import views @@ -21,13 +19,13 @@ class DashboardViewsTest(test.TestCase): req = self.request url_string = 'horizon:project:instances:index' url = views.get_url_with_pagination(req, None, None, url_string, None) - self.assertEqual(six.text_type('/project/instances/'), url) + self.assertEqual('/project/instances/', url) def test_get_url_with_pagination_with_if(self): req = self.request url_string = 'horizon:project:instances:detail' url = views.get_url_with_pagination(req, None, None, url_string, 'id') - self.assertEqual(six.text_type('/project/instances/id/'), url) + self.assertEqual('/project/instances/id/', url) def test_get_url_with_pagination_next(self): req = self.request @@ -35,7 +33,7 @@ class DashboardViewsTest(test.TestCase): req.GET.update({'next': 'id'}) url = views.get_url_with_pagination( req, 'next', None, url_string, None) - self.assertEqual(six.text_type('/project/instances/?next=id'), url) + self.assertEqual('/project/instances/?next=id', url) def test_get_url_with_pagination_prev(self): req = self.request @@ -43,7 +41,7 @@ class DashboardViewsTest(test.TestCase): req.GET.update({'prev': 'id'}) url = views.get_url_with_pagination( req, None, 'prev', url_string, None) - self.assertEqual(six.text_type('/project/instances/?prev=id'), url) + self.assertEqual('/project/instances/?prev=id', url) def test_urls_ngdetails(self): resp = self.client.get("/ngdetails/") diff --git a/openstack_dashboard/utils/config.py b/openstack_dashboard/utils/config.py index 32d4566179..5ab1479246 100644 --- a/openstack_dashboard/utils/config.py +++ b/openstack_dashboard/utils/config.py @@ -15,8 +15,6 @@ This module contains utility functions for loading Horizon's configuration from .ini files using the oslo.config library. """ -import six - from oslo_config import cfg # XXX import the actual config groups here @@ -45,7 +43,7 @@ def apply_config(config, target): def apply_config_group(config_group, target, prefix=None): - for key, value in six.iteritems(config_group): + for key, value in config_group.items(): name = key.upper() if prefix: name = '_'.join([prefix.upper(), name]) diff --git a/openstack_dashboard/utils/config_types.py b/openstack_dashboard/utils/config_types.py index 2a85bbec12..4205d5608f 100644 --- a/openstack_dashboard/utils/config_types.py +++ b/openstack_dashboard/utils/config_types.py @@ -55,7 +55,7 @@ class URL(types.ConfigType): super(URL, self).__init__('web URL') def __call__(self, value): - if not isinstance(value, six.string_types): + if not isinstance(value, str): raise ValueError("Expected URL.") value = re.sub(self.CLEAN_SLASH_RE, '/', value) if not value.endswith('/'): @@ -73,7 +73,7 @@ class Path(types.ConfigType): super(Path, self).__init__('filesystem path') def __call__(self, value): - if not isinstance(value, six.string_types): + if not isinstance(value, str): raise ValueError("Expected file path.") return os.path.normpath(value) @@ -89,7 +89,7 @@ class Translate(types.ConfigType): super(Translate, self).__init__('translatable string') def __call__(self, value): - if not isinstance(value, six.string_types): + if not isinstance(value, str): return value return pgettext_lazy(value, self.hint) @@ -106,7 +106,7 @@ class Literal(types.ConfigType): super(Literal, self).__init__('python literal') def __call__(self, value): - if isinstance(value, six.string_types): + if isinstance(value, str): try: value = ast.literal_eval(value) except SyntaxError as e: @@ -143,8 +143,8 @@ class Literal(types.ConfigType): (len(spec), result)) for s, value in zip(spec, result): self.validate(value, s) - if isinstance(spec, six.string_types): - if not isinstance(result, six.string_types): + if isinstance(spec, str): + if not isinstance(result, str): raise ValueError('String expected, but %r found.' % result) if isinstance(spec, int): if not isinstance(result, int): @@ -199,7 +199,7 @@ class Importable(types.ConfigType): super(Importable, self).__init__('importable python object') def __call__(self, value): - if not isinstance(value, six.string_types): + if not isinstance(value, str): # Already imported. return value try: diff --git a/openstack_dashboard/views.py b/openstack_dashboard/views.py index 39e462d3bb..4d980115bb 100644 --- a/openstack_dashboard/views.py +++ b/openstack_dashboard/views.py @@ -14,6 +14,7 @@ from importlib import import_module import logging +import urllib from django.conf import settings from django import http @@ -23,7 +24,6 @@ from django.utils.encoding import smart_text from django.utils.translation import ugettext as _ import django.views.decorators.vary from django.views.generic import TemplateView -from six.moves import urllib import horizon from horizon import exceptions