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
This commit is contained in:
Ivan Kolodyazhny 2020-01-09 16:49:18 +02:00
parent e976461d85
commit d870b40583
48 changed files with 111 additions and 222 deletions

View File

@ -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 "<Quota: (%s, %s)>" % (self.name, self.limit)
class QuotaSet(Sequence):
class QuotaSet(collections.Sequence):
"""Wrapper for client QuotaSet objects.
This turns the individual quotas into Quota objects

View File

@ -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.

View File

@ -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 "<Service: %s>" % six.text_type(self)
return "<Service: %s>" % self
def _get_endpoint_url(request, endpoint_type, catalog=None):

View File

@ -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

View File

@ -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
)))

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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]})

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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')

View File

@ -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)

View File

@ -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())

View File

@ -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

View File

@ -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, '<dt title="foo">foo</dt>')
self.assertContains(res, '<dd>foo val</dd>')
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):

View File

@ -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]), "<DeleteImage: delete>")
self.mock_image_list.assert_called_once_with(test.IsHttpRequest(),

View File

@ -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

View File

@ -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})

View File

@ -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 = []

View File

@ -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:

View File

@ -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

View File

@ -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',)})

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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))

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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()

View File

@ -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(

View File

@ -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):

View File

@ -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

View File

@ -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(

View File

@ -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)

View File

@ -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",

View File

@ -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)

View File

@ -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/")

View File

@ -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])

View File

@ -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:

View File

@ -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