From 33741138d92b7806700c843de9a885ae821db663 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 21 Dec 2021 12:36:37 +0000 Subject: [PATCH] Remove final six usage We also update docs since guidance has necessarily changed here. Change-Id: I7c24a1aa3545f3499a7a2ce30b73e2656666c764 Signed-off-by: Stephen Finucane --- doc/source/contributor/gerrit.rst | 35 +++------------------------ glance/api/middleware/cache.py | 4 +-- glance/api/v2/tasks.py | 3 --- glance/cmd/replicator.py | 7 +----- glance/common/client.py | 11 ++------- glance/common/crypt.py | 9 +++---- glance/common/utils.py | 3 --- glance/common/wsgi.py | 28 +-------------------- glance/image_cache/drivers/xattr.py | 5 +--- glance/tests/unit/common/test_wsgi.py | 16 +++--------- glance/tests/unit/test_misc.py | 6 +---- requirements.txt | 2 -- 12 files changed, 17 insertions(+), 112 deletions(-) diff --git a/doc/source/contributor/gerrit.rst b/doc/source/contributor/gerrit.rst index 6ca243a647..ec0ee8568d 100644 --- a/doc/source/contributor/gerrit.rst +++ b/doc/source/contributor/gerrit.rst @@ -26,38 +26,9 @@ The Great Change With the demise of Python 2.7 in January 2020, beginning with the Ussuri development cycle, Glance only needs to support Python 3 runtimes (in -particular, 3.6 and 3.7). Thus we can begin to incorporate Python 3 -language features and remove Python 2 compatibility code. At the same -time, however, we are still supporting stable branches that must support -Python 2. Our biggest interaction with the stable branches is backporting -bugfixes, where in the ideal case, we're just doing a simple cherry-pick of -a commit from master to the stable branches. You can see that there's some -tension here. - -With that in mind, here are some guidelines for reviewers and developers -that the Glance community has agreed on during this phase where we want to -write pure Python 3 but still must support Python 2 code. - -.. _transition-guidelines: - -Python 2 to Python 3 transition guidelines -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* We need to be checking the code coverage of test cases very carefully so - that new code has excellent coverage. The idea is that we want these - tests to fail when a backport is proposed to a stable branch and the - tests are run under Python 2 (if the code is using any Python-3-only - language features). -* New features can use Python-3-only language constructs, but bugfixes - likely to be backported should be more conservative and write for - Python 2 compatibility. -* The code for drivers may continue to use the six compatibility library at - their discretion. -* We will not remove six from mainline Cinder code that impacts the drivers - (for example, classes they inherit from). -* We can remove six from code that doesn't impact drivers, keeping in mind - that backports may be more problematic, and hence making sure that we have - really good test coverage. +particular, 3.6 and 3.7). There was a four cycle transition period, but +starting in the Yoga development cycle, all Python 2 compatibility code +has been removed and only Python 3 is supposed. Unit Tests ---------- diff --git a/glance/api/middleware/cache.py b/glance/api/middleware/cache.py index 5d3f8a99d1..a77b2a1912 100644 --- a/glance/api/middleware/cache.py +++ b/glance/api/middleware/cache.py @@ -24,7 +24,6 @@ the local cached copy of the image file is returned. import http.client as http import re -import six from oslo_log import log as logging import webob @@ -220,8 +219,7 @@ class CacheFilter(wsgi.Middleware): # https://github.com/Pylons/webob/issues/86 response.headers['Content-Type'] = 'application/octet-stream' if image.checksum: - response.headers['Content-MD5'] = (image.checksum.encode('utf-8') - if six.PY2 else image.checksum) + response.headers['Content-MD5'] = image.checksum response.headers['Content-Length'] = str(image.size) return response diff --git a/glance/api/v2/tasks.py b/glance/api/v2/tasks.py index 84a7194ba1..9e19b45495 100644 --- a/glance/api/v2/tasks.py +++ b/glance/api/v2/tasks.py @@ -25,7 +25,6 @@ from oslo_log import log as logging import oslo_serialization.jsonutils as json from oslo_utils import encodeutils from oslo_utils import uuidutils -import six import webob.exc from glance.api import common @@ -270,8 +269,6 @@ class ResponseSerializer(wsgi.JSONResponseSerializer): def _inject_location_header(self, response, task): location = self._get_task_location(task) - if six.PY2: - location = location.encode('utf-8') response.headers['Location'] = location def _get_task_location(self, task): diff --git a/glance/cmd/replicator.py b/glance/cmd/replicator.py index 489ed7c2b0..86d3923589 100644 --- a/glance/cmd/replicator.py +++ b/glance/cmd/replicator.py @@ -26,7 +26,6 @@ from oslo_log import log as logging from oslo_serialization import jsonutils from oslo_utils import encodeutils from oslo_utils import uuidutils -import six from webob import exc from glance.common import config @@ -395,11 +394,7 @@ def replication_dump(options, args): 'data_filename': data_filename}) # Dump glance information - if six.PY3: - f = open(data_path, 'w', encoding='utf-8') - else: - f = open(data_path, 'w') - with f: + with open(data_path, 'w', encoding='utf-8') as f: f.write(jsonutils.dumps(image)) if image['status'] == 'active' and not options.metaonly: diff --git a/glance/common/client.py b/glance/common/client.py index 119be7dd44..2de1618813 100644 --- a/glance/common/client.py +++ b/glance/common/client.py @@ -44,7 +44,6 @@ except ImportError: from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import netutils -import six from glance.common import auth from glance.common import exception @@ -411,11 +410,7 @@ class BaseClient(object): :returns: Dictionary with encoded headers' names and values """ - if six.PY3: - to_str = str - else: - to_str = encodeutils.safe_encode - return {to_str(h): to_str(v) for h, v in headers.items()} + return {str(h): str(v) for h, v in headers.items()} @handle_redirects def _do_request(self, method, url, body, headers): @@ -512,9 +507,7 @@ class BaseClient(object): return res.getheader('Retry-After') def read_body(res): - body = res.read() - if six.PY3: - body = body.decode('utf-8') + body = res.read().decode('utf-8') return body status_code = self.get_status_code(res) diff --git a/glance/common/crypt.py b/glance/common/crypt.py index f8f4539c3b..27c4c5c5e8 100644 --- a/glance/common/crypt.py +++ b/glance/common/crypt.py @@ -26,7 +26,6 @@ from cryptography.hazmat.primitives.ciphers import algorithms from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers import modes from oslo_utils import encodeutils -import six def urlsafe_encrypt(key, plaintext, blocksize=16): @@ -48,7 +47,7 @@ def urlsafe_encrypt(key, plaintext, blocksize=16): # NOTE(rosmaita): I know this looks stupid, but we can't just # use os.urandom() to get the bytes because we use char(0) as # a delimiter - pad = b''.join(six.int2byte(random.SystemRandom().randint(1, 0xFF)) + pad = b''.join(bytes((random.SystemRandom().randint(1, 0xFF),)) for i in range(pad_length - 1)) # We use chr(0) as a delimiter between text and padding return text + b'\0' + pad @@ -63,8 +62,7 @@ def urlsafe_encrypt(key, plaintext, blocksize=16): encryptor = cypher.encryptor() padded = encryptor.update(pad(plaintext)) + encryptor.finalize() encoded = base64.urlsafe_b64encode(init_vector + padded) - if six.PY3: - encoded = encoded.decode('ascii') + encoded = encoded.decode('ascii') return encoded @@ -88,6 +86,5 @@ def urlsafe_decrypt(key, ciphertext): decryptor = cypher.decryptor() padded = decryptor.update(ciphertext[16:]) + decryptor.finalize() text = padded[:padded.rfind(b'\0')] - if six.PY3: - text = text.decode('utf-8') + text = text.decode('utf-8') return text diff --git a/glance/common/utils.py b/glance/common/utils.py index eb4ac43e1a..6eabe21aee 100644 --- a/glance/common/utils.py +++ b/glance/common/utils.py @@ -39,7 +39,6 @@ from oslo_log import log as logging from oslo_utils import excutils from oslo_utils import netutils from oslo_utils import strutils -import six from webob import exc from glance.common import exception @@ -443,8 +442,6 @@ def get_test_suite_socket(): if GLANCE_TEST_SOCKET_FD_STR in os.environ: fd = int(os.environ[GLANCE_TEST_SOCKET_FD_STR]) sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM) - if six.PY2: - sock = socket.SocketType(_sock=sock) sock.listen(CONF.backlog) del os.environ[GLANCE_TEST_SOCKET_FD_STR] os.close(fd) diff --git a/glance/common/wsgi.py b/glance/common/wsgi.py index f1e4735328..0c16ce6204 100644 --- a/glance/common/wsgi.py +++ b/glance/common/wsgi.py @@ -45,7 +45,6 @@ from oslo_utils import encodeutils from oslo_utils import strutils from osprofiler import opts as profiler_opts import routes.middleware -import six import webob.dec import webob.exc from webob import multidict @@ -1104,26 +1103,6 @@ class Request(webob.Request): # not be inherited. webob.Request.body_file.fset(self, value) - @property - def params(self): - """Override params property of webob.request.BaseRequest. - - Added an 'encoded_params' attribute in case of PY2 to avoid - encoding values in next subsequent calls to the params property. - """ - if six.PY2: - encoded_params = getattr(self, 'encoded_params', None) - if encoded_params is None: - params = super(Request, self).params - params_dict = multidict.MultiDict() - for key, value in params.items(): - params_dict.add(key, encodeutils.safe_encode(value)) - - setattr(self, 'encoded_params', - multidict.NestedMultiDict(params_dict)) - return self.encoded_params - return super(Request, self).params - def best_match_content_type(self): """Determine the requested response content-type.""" supported = ('application/json',) @@ -1352,9 +1331,8 @@ class Resource(object): action_result = self.dispatch(self.controller, action, request, **action_args) except webob.exc.WSGIHTTPException as e: - exc_info = sys.exc_info() e = translate_exception(request, e) - six.reraise(type(e), e, exc_info[2]) + raise e.with_traceback(sys.exc_info()[2]) except UnicodeDecodeError: msg = _("Error decoding your request. Either the URL or the " "request body contained characters that could not be " @@ -1373,10 +1351,6 @@ class Resource(object): try: response = webob.Response(request=request) self.dispatch(self.serializer, action, response, action_result) - # encode all headers in response to utf-8 to prevent unicode errors - for name, value in list(response.headers.items()): - if six.PY2 and isinstance(value, str): - response.headers[name] = encodeutils.safe_encode(value) return response except webob.exc.WSGIHTTPException as e: return translate_exception(request, e) diff --git a/glance/image_cache/drivers/xattr.py b/glance/image_cache/drivers/xattr.py index 59aca36cf8..8fdf8a5f48 100644 --- a/glance/image_cache/drivers/xattr.py +++ b/glance/image_cache/drivers/xattr.py @@ -61,7 +61,6 @@ from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import excutils from oslo_utils import fileutils -import six import xattr from glance.common import exception @@ -477,9 +476,7 @@ def set_xattr(path, key, value): """ namespaced_key = _make_namespaced_xattr_key(key) if not isinstance(value, bytes): - value = str(value) - if six.PY3: - value = value.encode('utf-8') + value = str(value).encode('utf-8') xattr.setxattr(path, namespaced_key, value) diff --git a/glance/tests/unit/common/test_wsgi.py b/glance/tests/unit/common/test_wsgi.py index fb4e101c7e..4cf7e1749e 100644 --- a/glance/tests/unit/common/test_wsgi.py +++ b/glance/tests/unit/common/test_wsgi.py @@ -28,7 +28,6 @@ import fixtures from oslo_concurrency import processutils from oslo_serialization import jsonutils import routes -import six import webob from glance.api.v2 import router as router_v2 @@ -111,15 +110,9 @@ class RequestTest(test_utils.BaseTestCase): self.assertEqual("application/json", result) def test_params(self): - if six.PY2: - expected = webob.multidict.NestedMultiDict({ - 'limit': '20', 'name': - '\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82', - 'sort_key': 'name', 'sort_dir': 'asc'}) - else: - expected = webob.multidict.NestedMultiDict({ - 'limit': '20', 'name': 'Привет', 'sort_key': 'name', - 'sort_dir': 'asc'}) + expected = webob.multidict.NestedMultiDict({ + 'limit': '20', 'name': 'Привет', 'sort_key': 'name', + 'sort_dir': 'asc'}) request = wsgi.Request.blank("/?limit=20&name=%D0%9F%D1%80%D0%B8" "%D0%B2%D0%B5%D1%82&sort_key=name" @@ -414,8 +407,7 @@ class ResourceTest(test_utils.BaseTestCase): response = resource.__call__(request) # ensure it has been encoded correctly - value = (response.headers['unicode_test'].decode('utf-8') - if six.PY2 else response.headers['unicode_test']) + value = response.headers['unicode_test'] self.assertEqual(for_openstack_comrades, value) diff --git a/glance/tests/unit/test_misc.py b/glance/tests/unit/test_misc.py index b9822b204e..bfa3d79f6c 100644 --- a/glance/tests/unit/test_misc.py +++ b/glance/tests/unit/test_misc.py @@ -15,8 +15,6 @@ import os -import six - from glance.common import crypt from glance.common import utils from glance.tests import utils as test_utils @@ -33,9 +31,7 @@ class UtilsTestCase(test_utils.BaseTestCase): plaintext_list = [''] blocksize = 64 for i in range(3 * blocksize): - text = os.urandom(i) - if six.PY3: - text = text.decode('latin1') + text = os.urandom(i).decode('latin1') plaintext_list.append(text) for key in key_list: diff --git a/requirements.txt b/requirements.txt index 798746a22c..42778574cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,8 +33,6 @@ Paste>=2.0.2 # MIT jsonschema>=3.2.0 # MIT python-keystoneclient>=3.8.0 # Apache-2.0 pyOpenSSL>=17.1.0 # Apache-2.0 -# Required by openstack.common libraries -six>=1.11.0 # MIT oslo.db>=5.0.0 # Apache-2.0 oslo.i18n>=5.0.0 # Apache-2.0