diff --git a/doc/source/development_middleware.rst b/doc/source/development_middleware.rst index 6ee1d099b9..41e6ace20c 100644 --- a/doc/source/development_middleware.rst +++ b/doc/source/development_middleware.rst @@ -80,11 +80,7 @@ presented below:: from swift.common.request_helpers import get_sys_meta_prefix from swift.proxy.controllers.base import get_container_info from eventlet import Timeout - import six - if six.PY3: - from eventlet.green.urllib import request as urllib2 - else: - from eventlet.green import urllib2 + from eventlet.green.urllib import urllib_request # x-container-sysmeta-webhook SYSMETA_WEBHOOK = get_sys_meta_prefix('container') + 'webhook' @@ -119,10 +115,10 @@ presented below:: webhook = container_info['sysmeta'].get('webhook') if webhook: # create a POST request with obj name as body - webhook_req = urllib2.Request(webhook, data=obj) + webhook_req = urllib_request.Request(webhook, data=obj) with Timeout(20): try: - urllib2.urlopen(webhook_req).read() + urllib_request.urlopen(webhook_req).read() except (Exception, Timeout): self.logger.exception( 'failed POST to webhook %s' % webhook) diff --git a/lower-constraints.txt b/lower-constraints.txt index 19f2345159..3cee276cfa 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -65,7 +65,6 @@ PyYAML==3.12 requests==2.14.2 requests-mock==1.2.0 rfc3986==1.1.0 -six==1.10.0 smmap2==2.0.3 snowballstemmer==1.2.1 stestr==2.0.0 diff --git a/py3-constraints.txt b/py3-constraints.txt index 9b9f1e6572..6271838c0d 100644 --- a/py3-constraints.txt +++ b/py3-constraints.txt @@ -192,7 +192,6 @@ s3transfer===0.10.4;python_version>='3.8' s3transfer===0.8.2;python_version=='3.7' s3transfer===0.5.2;python_version=='3.6' setuptools===75.3.0;python_version>='3.12' -six===1.16.0 smmap===5.0.1;python_version>='3.7' smmap===5.0.0;python_version=='3.6' stestr===4.1.0 diff --git a/requirements.txt b/requirements.txt index b78a1ac12e..6105b8e4a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,6 @@ greenlet>=0.3.3 PasteDeploy>=2.0.0 lxml>=4.2.3 requests>=2.14.2 # Apache-2.0 -six>=1.10.0 xattr>=0.7.2;sys_platform!='win32' # MIT PyECLib>=1.3.1,!=1.6.2,!=1.6.3 # BSD cryptography>=2.0.2 # BSD/Apache-2.0 diff --git a/swift/account/backend.py b/swift/account/backend.py index ec1de03d15..d0241a2708 100644 --- a/swift/account/backend.py +++ b/swift/account/backend.py @@ -19,10 +19,8 @@ import sqlite3 -import six - from swift.common.utils import Timestamp, RESERVED_BYTE -from swift.common.db import DatabaseBroker, utf8encode, zero_like +from swift.common.db import DatabaseBroker, zero_like DATADIR = 'accounts' @@ -372,9 +370,6 @@ def list_containers_iter(self, limit, marker, end_marker, prefix, put_timestamp, 0) """ delim_force_gte = False - if six.PY2: - (marker, end_marker, prefix, delimiter) = utf8encode( - marker, end_marker, prefix, delimiter) if reverse: # Reverse the markers if we are reversing the listing. marker, end_marker = end_marker, marker diff --git a/swift/account/reaper.py b/swift/account/reaper.py index 41f7a440b7..3323ade720 100644 --- a/swift/account/reaper.py +++ b/swift/account/reaper.py @@ -22,7 +22,6 @@ import itertools from eventlet import GreenPool, sleep, Timeout -import six import swift.common.db from swift.account.backend import AccountBroker, DATADIR @@ -267,12 +266,9 @@ def reap_account(self, broker, partition, nodes, container_shard=None): while containers: try: for (container, _junk, _junk, _junk, _junk) in containers: - if six.PY3: - container_ = container.encode('utf-8') - else: - container_ = container this_shard = ( - int(md5(container_, usedforsecurity=False) + int(md5(container.encode('utf-8'), + usedforsecurity=False) .hexdigest(), 16) % len(nodes)) if container_shard not in (this_shard, None): continue diff --git a/swift/account/utils.py b/swift/account/utils.py index 89fb26f841..ac7bc3a4e9 100644 --- a/swift/account/utils.py +++ b/swift/account/utils.py @@ -15,8 +15,6 @@ import json -import six - from swift.common import constraints from swift.common.middleware import listing_formats from swift.common.swob import HTTPOk, HTTPNoContent, str_to_wsgi @@ -86,12 +84,11 @@ def account_listing_response(account, req, response_content_type, broker=None, data = [] for (name, object_count, bytes_used, put_timestamp, is_subdir) \ in account_list: - name_ = name.decode('utf8') if six.PY2 else name if is_subdir: - data.append({'subdir': name_}) + data.append({'subdir': name}) else: data.append( - {'name': name_, 'count': object_count, 'bytes': bytes_used, + {'name': name, 'count': object_count, 'bytes': bytes_used, 'last_modified': Timestamp(put_timestamp).isoformat}) if response_content_type.endswith('/xml'): account_list = listing_formats.account_to_xml(data, account) diff --git a/swift/cli/account_audit.py b/swift/cli/account_audit.py index b809f0c7e3..5d7ff589ea 100755 --- a/swift/cli/account_audit.py +++ b/swift/cli/account_audit.py @@ -23,7 +23,7 @@ import json from eventlet.greenpool import GreenPool from eventlet.event import Event -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift.common.ring import Ring from swift.common.utils import split_path diff --git a/swift/cli/container_deleter.py b/swift/cli/container_deleter.py index ecd8657d14..7b3ae95892 100644 --- a/swift/cli/container_deleter.py +++ b/swift/cli/container_deleter.py @@ -28,7 +28,6 @@ import io import itertools import json -import six import time from swift.common.internal_client import InternalClient @@ -50,17 +49,11 @@ def make_delete_jobs(account, container, objects, timestamp): :returns: list of dicts appropriate for an UPDATE request to an expiring-object queue ''' - if six.PY2: - if isinstance(account, str): - account = account.decode('utf8') - if isinstance(container, str): - container = container.decode('utf8') return [ { 'name': build_task_obj( timestamp, account, container, - obj.decode('utf8') if six.PY2 and isinstance(obj, str) - else obj, high_precision=True), + obj, high_precision=True), 'deleted': 0, 'created_at': timestamp.internal, 'etag': MD5_OF_EMPTY_STRING, diff --git a/swift/cli/dispersion_populate.py b/swift/cli/dispersion_populate.py index 7ed6b5a41a..a54b155b5f 100755 --- a/swift/cli/dispersion_populate.py +++ b/swift/cli/dispersion_populate.py @@ -23,9 +23,7 @@ from eventlet import GreenPool, patcher, sleep from eventlet.pools import Pool -import six -from six.moves import range -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from swift.common.internal_client import SimpleClient from swift.common.ring import Ring @@ -53,7 +51,7 @@ def put_object(connpool, container, obj, report): global retries_done try: with connpool.item() as conn: - data = io.BytesIO(obj if six.PY2 else obj.encode('utf8')) + data = io.BytesIO(obj.encode('utf8')) conn.put_object(container, obj, data, headers={'x-object-meta-dispersion': obj}) retries_done += conn.attempts - 1 diff --git a/swift/cli/dispersion_report.py b/swift/cli/dispersion_report.py index 605e1281b5..270d1a0180 100644 --- a/swift/cli/dispersion_report.py +++ b/swift/cli/dispersion_report.py @@ -17,7 +17,7 @@ from __future__ import print_function import json from collections import defaultdict -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from optparse import OptionParser from sys import exit, stdout, stderr from time import time diff --git a/swift/cli/drive_audit.py b/swift/cli/drive_audit.py index 5c74e52c3a..fa8367895c 100755 --- a/swift/cli/drive_audit.py +++ b/swift/cli/drive_audit.py @@ -24,8 +24,7 @@ import sys -import six -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from swift.common.utils import backward, get_logger, dump_recon_cache, \ config_true_value @@ -128,8 +127,7 @@ def get_errors(error_re, log_file_pattern, minutes, logger, print("Unable to open " + path) sys.exit(1) for line in backward(f): - if not six.PY2: - line = line.decode(log_file_encoding, 'surrogateescape') + line = line.decode(log_file_encoding, 'surrogateescape') if '[ 0.000000]' in line \ or 'KERNEL supported cpus:' in line \ or 'BIOS-provided physical RAM map:' in line: diff --git a/swift/cli/form_signature.py b/swift/cli/form_signature.py index ab0d12f00a..f9c5bf1e00 100644 --- a/swift/cli/form_signature.py +++ b/swift/cli/form_signature.py @@ -17,7 +17,6 @@ """ from __future__ import print_function import hmac -import six from hashlib import sha1 from os.path import basename from time import time @@ -95,11 +94,9 @@ def main(argv): return 1 data = '%s\n%s\n%s\n%s\n%s' % (path, redirect, max_file_size, max_file_count, expires) - if six.PY3: - data = data if isinstance(data, six.binary_type) else \ - data.encode('utf8') - key = key if isinstance(key, six.binary_type) else \ - key.encode('utf8') + data = data.encode('utf8') + key = key if isinstance(key, bytes) else \ + key.encode('utf8') sig = hmac.new(key, data, sha1).hexdigest() print(' Expires:', expires) diff --git a/swift/cli/info.py b/swift/cli/info.py index 6c4952ef99..065b53d46c 100644 --- a/swift/cli/info.py +++ b/swift/cli/info.py @@ -21,8 +21,7 @@ import sys from collections import defaultdict -import six -from six.moves import urllib +import urllib from swift.common.exceptions import LockTimeout from swift.common.utils import hash_path, storage_directory, \ @@ -722,10 +721,9 @@ def print_item_locations(ring, ring_name=None, account=None, container=None, def obj_main(): - if not six.PY2: - # Make stdout able to write escaped bytes - sys.stdout = codecs.getwriter("utf-8")( - sys.stdout.detach(), errors='surrogateescape') + # Make stdout able to write escaped bytes + sys.stdout = codecs.getwriter("utf-8")( + sys.stdout.detach(), errors='surrogateescape') parser = OptionParser('%prog [options] OBJECT_FILE') parser.add_option( diff --git a/swift/cli/manage_shard_ranges.py b/swift/cli/manage_shard_ranges.py index 1977e7af39..0a8b7f1ce5 100644 --- a/swift/cli/manage_shard_ranges.py +++ b/swift/cli/manage_shard_ranges.py @@ -163,9 +163,6 @@ import time from contextlib import contextmanager -from six.moves import input - - from swift.common.utils import Timestamp, get_logger, ShardRange, readconf, \ ShardRangeList, non_negative_int, config_positive_int_value from swift.container.backend import ContainerBroker, UNSHARDED diff --git a/swift/cli/recon.py b/swift/cli/recon.py index dbf0edba4a..f17db3c5c5 100644 --- a/swift/cli/recon.py +++ b/swift/cli/recon.py @@ -18,8 +18,7 @@ from __future__ import print_function from eventlet.green import socket -from six import string_types -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from swift.common.utils import ( SWIFT_CONF_FILE, md5_hash_for_file, set_swift_dir) @@ -30,13 +29,9 @@ import optparse import time import sys -import six import os -if six.PY3: - from eventlet.green.urllib import request as urllib2 -else: - from eventlet.green import urllib2 +from eventlet.green.urllib import request as urllib_request def seconds2timeunit(seconds): @@ -86,19 +81,19 @@ def scout_host(self, base_url, recon_type): """ url = base_url + recon_type try: - body = urllib2.urlopen(url, timeout=self.timeout).read() - if six.PY3 and isinstance(body, six.binary_type): + body = urllib_request.urlopen(url, timeout=self.timeout).read() + if isinstance(body, bytes): body = body.decode('utf8') content = json.loads(body) if self.verbose: print("-> %s: %s" % (url, content)) status = 200 - except urllib2.HTTPError as err: + except urllib_request.HTTPError as err: if not self.suppress_errors or self.verbose: print("-> %s: %s" % (url, err)) content = err status = err.code - except (urllib2.URLError, socket.timeout) as err: + except (urllib_request.URLError, socket.timeout) as err: if not self.suppress_errors or self.verbose: print("-> %s: %s" % (url, err)) content = err @@ -128,19 +123,19 @@ def scout_server_type(self, host): """ try: url = "http://%s:%s/" % (host[0], host[1]) - req = urllib2.Request(url) + req = urllib_request.Request(url) req.get_method = lambda: 'OPTIONS' - conn = urllib2.urlopen(req) + conn = urllib_request.urlopen(req) header = conn.info().get('Server') server_header = header.split('/') content = server_header[0] status = 200 - except urllib2.HTTPError as err: + except urllib_request.HTTPError as err: if not self.suppress_errors or self.verbose: print("-> %s: %s" % (url, err)) content = err status = err.code - except (urllib2.URLError, socket.timeout) as err: + except (urllib_request.URLError, socket.timeout) as err: if not self.suppress_errors or self.verbose: print("-> %s: %s" % (url, err)) content = err @@ -1074,7 +1069,7 @@ def _get_ring_names(self, policy=None): ring_names = [p.ring_name for p in POLICIES if ( p.name == policy or not policy or ( policy.isdigit() and int(policy) == int(p) or - (isinstance(policy, string_types) + (isinstance(policy, str) and policy in p.aliases)))] else: ring_names = [self.server_type] diff --git a/swift/cli/ringbuilder.py b/swift/cli/ringbuilder.py index 374f462356..5cbb70c30c 100644 --- a/swift/cli/ringbuilder.py +++ b/swift/cli/ringbuilder.py @@ -31,9 +31,6 @@ import optparse import math -from six.moves import zip as izip -from six.moves import input - from swift.common import exceptions from swift.common.ring import RingBuilder, Ring, RingData from swift.common.ring.builder import MAX_BALANCE @@ -156,8 +153,8 @@ def _parse_add_values(argvish): print(Commands.add.__doc__.strip()) exit(EXIT_ERROR) - devs_and_weights = izip(islice(args, 0, len(args), 2), - islice(args, 1, len(args), 2)) + devs_and_weights = zip(islice(args, 0, len(args), 2), + islice(args, 1, len(args), 2)) for devstr, weightstr in devs_and_weights: dev_dict = parse_add_value(devstr) @@ -257,8 +254,8 @@ def _parse_set_weight_values(argvish): print(Commands.set_weight.__doc__.strip()) exit(EXIT_ERROR) - devs_and_weights = izip(islice(argvish, 0, len(argvish), 2), - islice(argvish, 1, len(argvish), 2)) + devs_and_weights = zip(islice(argvish, 0, len(argvish), 2), + islice(argvish, 1, len(argvish), 2)) for devstr, weightstr in devs_and_weights: devs = (builder.search_devs( parse_search_value(devstr)) or []) @@ -347,8 +344,8 @@ def _parse_set_region_values(argvish): print(Commands.set_region.__doc__.strip()) exit(EXIT_ERROR) - devs_and_regions = izip(islice(argvish, 0, len(argvish), 2), - islice(argvish, 1, len(argvish), 2)) + devs_and_regions = zip(islice(argvish, 0, len(argvish), 2), + islice(argvish, 1, len(argvish), 2)) for devstr, regionstr in devs_and_regions: devs.extend(builder.search_devs( parse_search_value(devstr)) or []) @@ -382,8 +379,8 @@ def _parse_set_zone_values(argvish): print(Commands.set_zone.__doc__.strip()) exit(EXIT_ERROR) - devs_and_zones = izip(islice(argvish, 0, len(argvish), 2), - islice(argvish, 1, len(argvish), 2)) + devs_and_zones = zip(islice(argvish, 0, len(argvish), 2), + islice(argvish, 1, len(argvish), 2)) for devstr, zonestr in devs_and_zones: devs.extend(builder.search_devs( parse_search_value(devstr)) or []) @@ -415,8 +412,8 @@ def _parse_set_info_values(argvish): print(Commands.search.__doc__.strip()) exit(EXIT_ERROR) - searches_and_changes = izip(islice(argvish, 0, len(argvish), 2), - islice(argvish, 1, len(argvish), 2)) + searches_and_changes = zip(islice(argvish, 0, len(argvish), 2), + islice(argvish, 1, len(argvish), 2)) for search_value, change_value in searches_and_changes: devs = builder.search_devs(parse_search_value(search_value)) diff --git a/swift/common/bufferedhttp.py b/swift/common/bufferedhttp.py index c0aa259b3d..491adabfca 100644 --- a/swift/common/bufferedhttp.py +++ b/swift/common/bufferedhttp.py @@ -27,28 +27,22 @@ """ from swift.common import constraints +import http.client import logging import time import socket -import eventlet -from eventlet.green.httplib import CONTINUE, HTTPConnection, HTTPMessage, \ +from eventlet.green.http.client import CONTINUE, HTTPConnection, \ HTTPResponse, HTTPSConnection, _UNKNOWN, ImproperConnectionState -from six.moves.urllib.parse import quote, parse_qsl, urlencode -import six +from urllib.parse import quote, parse_qsl, urlencode -if six.PY2: - httplib = eventlet.import_patched('httplib') - from eventlet.green import httplib as green_httplib -else: - httplib = eventlet.import_patched('http.client') - from eventlet.green.http import client as green_httplib +from eventlet.green.http import client as green_http_client # Apparently http.server uses this to decide when/whether to send a 431. # Give it some slack, so the app is more likely to get the chance to reject # with a 400 instead. -httplib._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6 -green_httplib._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6 +http.client._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6 +green_http_client._MAXHEADERS = constraints.MAX_HEADER_COUNT * 1.6 class BufferedHTTPResponse(HTTPResponse): @@ -65,11 +59,6 @@ def __init__(self, sock, debuglevel=0, strict=0, # No socket means no file-like -- set it to None like in # HTTPResponse.close() self.fp = None - elif six.PY2: - # sock.fd is a socket._socketobject - # sock.fd._sock is a _socket.socket object, which is what we want. - self._real_socket = sock.fd._sock - self.fp = sock.makefile('rb') else: # sock.fd is a socket.socket, which should have a _real_close self._real_socket = sock.fd @@ -91,24 +80,23 @@ def __init__(self, sock, debuglevel=0, strict=0, self.will_close = _UNKNOWN # conn will close at end of response self._readline_buffer = b'' - if not six.PY2: - def begin(self): - HTTPResponse.begin(self) - header_payload = self.headers.get_payload() - if isinstance(header_payload, list) and len(header_payload) == 1: - header_payload = header_payload[0].get_payload() - if header_payload: - # This shouldn't be here. We must've bumped up against - # https://bugs.python.org/issue37093 - for line in header_payload.rstrip('\r\n').split('\n'): - if ':' not in line or line[:1] in ' \t': - # Well, we're no more broken than we were before... - # Should we support line folding? - # How can/should we handle a bad header line? - break - header, value = line.split(':', 1) - value = value.strip(' \t\n\r') - self.headers.add_header(header, value) + def begin(self): + HTTPResponse.begin(self) + header_payload = self.headers.get_payload() + if isinstance(header_payload, list) and len(header_payload) == 1: + header_payload = header_payload[0].get_payload() + if header_payload: + # This shouldn't be here. We must've bumped up against + # https://bugs.python.org/issue37093 + for line in header_payload.rstrip('\r\n').split('\n'): + if ':' not in line or line[:1] in ' \t': + # Well, we're no more broken than we were before... + # Should we support line folding? + # How can/should we handle a bad header line? + break + header, value = line.split(':', 1) + value = value.strip(' \t\n\r') + self.headers.add_header(header, value) def expect_response(self): if self.fp: @@ -125,15 +113,7 @@ def expect_response(self): self.status = status self.reason = reason.strip() self.version = 11 - if six.PY2: - # Under py2, HTTPMessage.__init__ reads the headers - # which advances fp - self.msg = HTTPMessage(self.fp, 0) - # immediately kill msg.fp to make sure it isn't read again - self.msg.fp = None - else: - # py3 has a separate helper for it - self.headers = self.msg = httplib.parse_headers(self.fp) + self.headers = self.msg = http.client.parse_headers(self.fp) def read(self, amt=None): if not self._readline_buffer: @@ -157,26 +137,6 @@ def read(self, amt=None): self._readline_buffer = b'' return buf + HTTPResponse.read(self, smaller_amt) - def readline(self, size=1024): - # You'd think Python's httplib would provide this, but it doesn't. - # It does, however, provide a comment in the HTTPResponse class: - # - # # XXX It would be nice to have readline and __iter__ for this, - # # too. - # - # Yes, it certainly would. - while (b'\n' not in self._readline_buffer - and len(self._readline_buffer) < size): - read_size = size - len(self._readline_buffer) - chunk = HTTPResponse.read(self, read_size) - if not chunk: - break - self._readline_buffer += chunk - - line, newline, rest = self._readline_buffer.partition(b'\n') - self._readline_buffer = rest - return line + newline - def nuke_from_orbit(self): """ Terminate the socket with extreme prejudice. @@ -186,14 +146,9 @@ def nuke_from_orbit(self): you care about has a reference to this socket. """ if self._real_socket: - if six.PY2: - # this is idempotent; see sock_close in Modules/socketmodule.c - # in the Python source for details. - self._real_socket.close() - else: - # Hopefully this is equivalent? - # TODO: verify that this does everything ^^^^ does for py2 - self._real_socket._real_close() + # Hopefully this is equivalent to py2's _real_socket.close()? + # TODO: verify that this does everything ^^^^ does for py2 + self._real_socket._real_close() self._real_socket = None self.close() @@ -268,13 +223,13 @@ def http_connect(ipaddr, port, device, partition, method, path, :param ssl: set True if SSL should be used (default: False) :returns: HTTPConnection object """ - if isinstance(path, six.text_type): + if isinstance(path, str): path = path.encode("utf-8") - if isinstance(device, six.text_type): + if isinstance(device, str): device = device.encode("utf-8") - if isinstance(partition, six.text_type): + if isinstance(partition, str): partition = partition.encode('utf-8') - elif isinstance(partition, six.integer_types): + elif isinstance(partition, int): partition = str(partition).encode('ascii') path = quote(b'/' + device + b'/' + partition + path) return http_connect_raw( @@ -305,14 +260,10 @@ def http_connect_raw(ipaddr, port, method, path, headers=None, conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port)) if query_string: # Round trip to ensure proper quoting - if six.PY2: - query_string = urlencode(parse_qsl( - query_string, keep_blank_values=True)) - else: - query_string = urlencode( - parse_qsl(query_string, keep_blank_values=True, - encoding='latin1'), - encoding='latin1') + query_string = urlencode( + parse_qsl(query_string, keep_blank_values=True, + encoding='latin1'), + encoding='latin1') path += '?' + query_string conn.path = path conn.putrequest(method, path, skip_host=(headers and 'Host' in headers)) diff --git a/swift/common/constraints.py b/swift/common/constraints.py index f572107b84..7b9a5f9e74 100644 --- a/swift/common/constraints.py +++ b/swift/common/constraints.py @@ -17,9 +17,8 @@ import os from os.path import isdir # tighter scoped import for mocking -import six -from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError -from six.moves import urllib +from configparser import ConfigParser, NoSectionError, NoOptionError +import urllib from swift.common import utils, exceptions from swift.common.swob import HTTPBadRequest, HTTPLengthRequired, \ @@ -130,7 +129,7 @@ def check_metadata(req, target_type): meta_count = 0 meta_size = 0 for key, value in req.headers.items(): - if (isinstance(value, six.string_types) + if (isinstance(value, str) and len(value) > MAX_HEADER_SIZE): return HTTPBadRequest(body=b'Header value too long: %s' % @@ -364,7 +363,7 @@ def check_utf8(string, internal=False): if not string: return False try: - if isinstance(string, six.text_type): + if isinstance(string, str): encoded = string.encode('utf-8') decoded = string else: @@ -412,9 +411,6 @@ def check_name_format(req, name, target_type): raise HTTPPreconditionFailed( request=req, body='%s name cannot be empty' % target_type) - if six.PY2: - if isinstance(name, six.text_type): - name = name.encode('utf-8') if '/' in name: raise HTTPPreconditionFailed( request=req, diff --git a/swift/common/container_sync_realms.py b/swift/common/container_sync_realms.py index 3fc437bcea..51adcddf34 100644 --- a/swift/common/container_sync_realms.py +++ b/swift/common/container_sync_realms.py @@ -19,8 +19,7 @@ import os import time -import six -from six.moves import configparser +import configparser from swift.common.utils import get_valid_utf8_str @@ -158,7 +157,7 @@ def get_sig(self, request_method, path, x_timestamp, nonce, realm_key, user_key = get_valid_utf8_str(user_key) # XXX We don't know what is the best here yet; wait for container # sync to be tested. - if isinstance(path, six.text_type): + if isinstance(path, str): path = path.encode('utf-8') return hmac.new( realm_key, diff --git a/swift/common/db.py b/swift/common/db.py index 7c80dc1fa5..f8c0648379 100644 --- a/swift/common/db.py +++ b/swift/common/db.py @@ -21,11 +21,9 @@ import logging import os from uuid import uuid4 -import sys import time import errno -import six -import six.moves.cPickle as pickle +import pickle # nosec: B403 from tempfile import mkstemp from eventlet import sleep, Timeout @@ -55,28 +53,14 @@ RECLAIM_PAGE_SIZE = 10000 -def utf8encode(*args): - return [(s.encode('utf8') if isinstance(s, six.text_type) else s) - for s in args] - - def native_str_keys_and_values(metadata): - if six.PY2: - uni_keys = [k for k in metadata if isinstance(k, six.text_type)] - for k in uni_keys: - sv = metadata[k] - del metadata[k] - metadata[k.encode('utf-8')] = [ - x.encode('utf-8') if isinstance(x, six.text_type) else x - for x in sv] - else: - bin_keys = [k for k in metadata if isinstance(k, six.binary_type)] - for k in bin_keys: - sv = metadata[k] - del metadata[k] - metadata[k.decode('utf-8')] = [ - x.decode('utf-8') if isinstance(x, six.binary_type) else x - for x in sv] + bin_keys = [k for k in metadata if isinstance(k, bytes)] + for k in bin_keys: + sv = metadata[k] + del metadata[k] + metadata[k.decode('utf-8')] = [ + x.decode('utf-8') if isinstance(x, bytes) else x + for x in sv] ZERO_LIKE_VALUES = {None, '', 0, '0'} @@ -219,7 +203,7 @@ def get_db_connection(path, timeout=30, logger=None, okay_to_create=False): connect_time = time.time() conn = sqlite3.connect(path, check_same_thread=False, factory=GreenDBConnection, timeout=timeout) - if QUERY_LOGGING and logger and not six.PY2: + if QUERY_LOGGING and logger: conn.set_trace_callback(logger.debug) if not okay_to_create: # attempt to detect and fail when connect creates the db file @@ -380,7 +364,7 @@ def initialize(self, put_timestamp=None, storage_policy_index=None): os.close(fd) conn = sqlite3.connect(tmp_db_file, check_same_thread=False, factory=GreenDBConnection, timeout=0) - if QUERY_LOGGING and not six.PY2: + if QUERY_LOGGING: conn.set_trace_callback(self.logger.debug) # creating dbs implicitly does a lot of transactions, so we # pick fast, unsafe options here and do a big fsync at the end. @@ -505,25 +489,25 @@ def quarantine(self, reason): self.logger.error(detail) raise sqlite3.DatabaseError(detail) - def possibly_quarantine(self, exc_type, exc_value, exc_traceback): + def possibly_quarantine(self, err): """ Checks the exception info to see if it indicates a quarantine situation (malformed or corrupted database). If not, the original exception will be reraised. If so, the database will be quarantined and a new sqlite3.DatabaseError will be raised indicating the action taken. """ - if 'database disk image is malformed' in str(exc_value): + if 'database disk image is malformed' in str(err): exc_hint = 'malformed database' - elif 'malformed database schema' in str(exc_value): + elif 'malformed database schema' in str(err): exc_hint = 'malformed database' - elif ' is not a database' in str(exc_value): + elif ' is not a database' in str(err): # older versions said 'file is not a database' # now 'file is encrypted or is not a database' exc_hint = 'corrupted database' - elif 'disk I/O error' in str(exc_value): + elif 'disk I/O error' in str(err): exc_hint = 'disk error while accessing database' else: - six.reraise(exc_type, exc_value, exc_traceback) + raise err self.quarantine(exc_hint) @@ -557,8 +541,8 @@ def get(self): try: self.conn = get_db_connection(self.db_file, self.timeout, self.logger) - except (sqlite3.DatabaseError, DatabaseConnectionError): - self.possibly_quarantine(*sys.exc_info()) + except (sqlite3.DatabaseError, DatabaseConnectionError) as e: + self.possibly_quarantine(e) else: raise DatabaseConnectionError(self.db_file, "DB doesn't exist") conn = self.conn @@ -567,12 +551,12 @@ def get(self): yield conn conn.rollback() self.conn = conn - except sqlite3.DatabaseError: + except sqlite3.DatabaseError as e: try: conn.close() except Exception: pass - self.possibly_quarantine(*sys.exc_info()) + self.possibly_quarantine(e) except (Exception, Timeout): conn.close() raise @@ -848,11 +832,8 @@ def _commit_puts(self, item_list=None): for entry in fp.read().split(b':'): if entry: try: - if six.PY2: - data = pickle.loads(base64.b64decode(entry)) - else: - data = pickle.loads(base64.b64decode(entry), - encoding='utf8') + data = pickle.loads(base64.b64decode(entry), + encoding='utf8') # nosec: B301 self._commit_puts_load(item_list, data) except Exception: self.logger.exception( diff --git a/swift/common/digest.py b/swift/common/digest.py index 34db19409b..36bc47a9bd 100644 --- a/swift/common/digest.py +++ b/swift/common/digest.py @@ -13,9 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import binascii -import hashlib import hmac -import six from swift.common.utils import strict_b64decode @@ -55,17 +53,14 @@ def get_hmac(request_method, path, expires, key, digest="sha1", parts.insert(0, ip_range) formats.insert(0, b"ip=%s") - if not isinstance(key, six.binary_type): + if isinstance(key, str): key = key.encode('utf8') message = b'\n'.join( - fmt % (part if isinstance(part, six.binary_type) + fmt % (part if isinstance(part, bytes) else part.encode("utf-8")) for fmt, part in zip(formats, parts)) - if six.PY2 and isinstance(digest, six.string_types): - digest = getattr(hashlib, digest) - return hmac.new(key, message, digest).hexdigest() @@ -132,15 +127,10 @@ def extract_digest_and_algorithm(value): if ('-' in value or '_' in value) and not ( '+' in value or '/' in value): value = value.replace('-', '+').replace('_', '/') - value = binascii.hexlify(strict_b64decode(value + '==')) - if not six.PY2: - value = value.decode('ascii') + value = binascii.hexlify( + strict_b64decode(value + '==')).decode('ascii') else: - try: - binascii.unhexlify(value) # make sure it decodes - except TypeError: - # This is just for py2 - raise ValueError('Non-hexadecimal digit found') + binascii.unhexlify(value) # make sure it decodes algo = { 40: 'sha1', 64: 'sha256', diff --git a/swift/common/direct_client.py b/swift/common/direct_client.py index f2097d9fe0..94a4558384 100644 --- a/swift/common/direct_client.py +++ b/swift/common/direct_client.py @@ -23,9 +23,8 @@ import socket from eventlet import sleep, Timeout -import six -import six.moves.cPickle as pickle -from six.moves.http_client import HTTPException +import pickle # nosec: B403 +from http.client import HTTPException from swift.common.bufferedhttp import http_connect, http_connect_raw from swift.common.exceptions import ClientException @@ -44,7 +43,7 @@ def __init__(self, stype, method, node, part, path, resp, host=None): # host can be used to override the node ip and port reported in # the exception host = host if host is not None else node - if not isinstance(path, six.text_type): + if isinstance(path, bytes): path = path.decode("utf-8") full_path = quote('/%s/%s%s' % (node['device'], part, path)) msg = '%s server %s:%s direct %s %r gave status %s' % ( @@ -59,7 +58,7 @@ def __init__(self, stype, method, node, part, path, resp, host=None): class DirectClientReconException(ClientException): def __init__(self, method, node, path, resp): - if not isinstance(path, six.text_type): + if isinstance(path, bytes): path = path.decode("utf-8") msg = 'server %s:%s direct %s %r gave status %s' % ( node['ip'], node['port'], method, path, resp.status) @@ -72,7 +71,7 @@ def __init__(self, method, node, path, resp): def _make_path(*components): return u'/' + u'/'.join( - x.decode('utf-8') if isinstance(x, six.binary_type) else x + x.decode('utf-8') if isinstance(x, bytes) else x for x in components) @@ -111,7 +110,7 @@ def _make_req(node, part, method, path, headers, stype, content_length = int(v) if not contents: headers['Content-Length'] = '0' - if isinstance(contents, six.string_types): + if isinstance(contents, str): contents = [contents] if content_length is None: headers['Transfer-Encoding'] = 'chunked' @@ -657,7 +656,7 @@ def direct_get_suffix_hashes(node, part, suffixes, conn_timeout=5, host={'ip': node['replication_ip'], 'port': node['replication_port']} ) - return pickle.loads(resp.read()) + return pickle.loads(resp.read()) # nosec: B301 def retry(func, *args, **kwargs): diff --git a/swift/common/header_key_dict.py b/swift/common/header_key_dict.py index 6cabe1ef9e..f6b906a15e 100644 --- a/swift/common/header_key_dict.py +++ b/swift/common/header_key_dict.py @@ -13,8 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six - class HeaderKeyDict(dict): """ @@ -31,10 +29,7 @@ def __init__(self, base_headers=None, **kwargs): @staticmethod def _title(s): - if six.PY2: - return s.title() - else: - return s.encode('latin1').title().decode('latin1') + return s.encode('latin1').title().decode('latin1') def update(self, other): if hasattr(other, 'keys'): @@ -51,9 +46,7 @@ def __setitem__(self, key, value): key = self._title(key) if value is None: self.pop(key, None) - elif six.PY2 and isinstance(value, six.text_type): - return dict.__setitem__(self, key, value.encode('utf-8')) - elif six.PY3 and isinstance(value, six.binary_type): + elif isinstance(value, bytes): return dict.__setitem__(self, key, value.decode('latin-1')) else: return dict.__setitem__(self, key, str(value)) diff --git a/swift/common/http_protocol.py b/swift/common/http_protocol.py index 8147ad5597..c803cce05b 100644 --- a/swift/common/http_protocol.py +++ b/swift/common/http_protocol.py @@ -14,18 +14,13 @@ # limitations under the License. from eventlet import wsgi, websocket -import six from swift.common.utils import generate_trans_id from swift.common.http import HTTP_NO_CONTENT, HTTP_RESET_CONTENT, \ HTTP_NOT_MODIFIED -if six.PY2: - from eventlet.green import httplib as http_client - from cgi import escape -else: - from eventlet.green.http import client as http_client - from html import escape +from eventlet.green.http import client as http_client +from html import escape class SwiftHttpProtocol(wsgi.HttpProtocol): @@ -59,13 +54,6 @@ def log_message(self, f, *a): class MessageClass(wsgi.HttpProtocol.MessageClass): """Subclass to see when the client didn't provide a Content-Type""" - # for py2: - def parsetype(self): - if self.typeheader is None: - self.typeheader = '' - wsgi.HttpProtocol.MessageClass.parsetype(self) - - # for py3: def get_default_type(self): """If the client didn't provide a content type, leave it blank.""" return '' @@ -84,9 +72,7 @@ def parse_request(self): self.command = None # set in case of error on the first line self.request_version = version = self.default_request_version self.close_connection = True - requestline = self.raw_requestline - if not six.PY2: - requestline = requestline.decode('iso-8859-1') + requestline = self.raw_requestline.decode('iso-8859-1') requestline = requestline.rstrip('\r\n') self.requestline = requestline # Split off \x20 explicitly (see https://bugs.python.org/issue33973) @@ -147,26 +133,23 @@ def parse_request(self): self.command, self.path = command, path # Examine the headers and look for a Connection directive. - if six.PY2: - self.headers = self.MessageClass(self.rfile, 0) - else: - try: - self.headers = http_client.parse_headers( - self.rfile, - _class=self.MessageClass) - except http_client.LineTooLong as err: - self.send_error( - 431, - "Line too long", - str(err)) - return False - except http_client.HTTPException as err: - self.send_error( - 431, - "Too many headers", - str(err) - ) - return False + try: + self.headers = http_client.parse_headers( + self.rfile, + _class=self.MessageClass) + except http_client.LineTooLong as err: + self.send_error( + 431, + "Line too long", + str(err)) + return False + except http_client.HTTPException as err: + self.send_error( + 431, + "Too many headers", + str(err) + ) + return False conntype = self.headers.get('Connection', "") if conntype.lower() == 'close': @@ -183,52 +166,51 @@ def parse_request(self): return False return True - if not six.PY2: - def get_environ(self, *args, **kwargs): - environ = wsgi.HttpProtocol.get_environ(self, *args, **kwargs) - header_payload = self.headers.get_payload() - if isinstance(header_payload, list) and len(header_payload) == 1: - header_payload = header_payload[0].get_payload() - if header_payload: - # This shouldn't be here. We must've bumped up against - # https://bugs.python.org/issue37093 - headers_raw = list(environ['headers_raw']) - for line in header_payload.rstrip('\r\n').split('\n'): - if ':' not in line or line[:1] in ' \t': - # Well, we're no more broken than we were before... - # Should we support line folding? - # Should we 400 a bad header line? - break - header, value = line.split(':', 1) - value = value.strip(' \t\n\r') - # NB: Eventlet looks at the headers obj to figure out - # whether the client said the connection should close; - # see https://github.com/eventlet/eventlet/blob/v0.25.0/ - # eventlet/wsgi.py#L504 - self.headers.add_header(header, value) - headers_raw.append((header, value)) - wsgi_key = 'HTTP_' + header.replace('-', '_').encode( - 'latin1').upper().decode('latin1') - if wsgi_key in ('HTTP_CONTENT_LENGTH', - 'HTTP_CONTENT_TYPE'): - wsgi_key = wsgi_key[5:] - environ[wsgi_key] = value - environ['headers_raw'] = tuple(headers_raw) - # Since we parsed some more headers, check to see if they - # change how our wsgi.input should behave - te = environ.get('HTTP_TRANSFER_ENCODING', '').lower() - if te.rsplit(',', 1)[-1].strip() == 'chunked': - environ['wsgi.input'].chunked_input = True - else: - length = environ.get('CONTENT_LENGTH') - if length: - length = int(length) - environ['wsgi.input'].content_length = length - if environ.get('HTTP_EXPECT', '').lower() == '100-continue': - environ['wsgi.input'].wfile = self.wfile - environ['wsgi.input'].wfile_line = \ - b'HTTP/1.1 100 Continue\r\n' - return environ + def get_environ(self, *args, **kwargs): + environ = wsgi.HttpProtocol.get_environ(self, *args, **kwargs) + header_payload = self.headers.get_payload() + if isinstance(header_payload, list) and len(header_payload) == 1: + header_payload = header_payload[0].get_payload() + if header_payload: + # This shouldn't be here. We must've bumped up against + # https://bugs.python.org/issue37093 + headers_raw = list(environ['headers_raw']) + for line in header_payload.rstrip('\r\n').split('\n'): + if ':' not in line or line[:1] in ' \t': + # Well, we're no more broken than we were before... + # Should we support line folding? + # Should we 400 a bad header line? + break + header, value = line.split(':', 1) + value = value.strip(' \t\n\r') + # NB: Eventlet looks at the headers obj to figure out + # whether the client said the connection should close; + # see https://github.com/eventlet/eventlet/blob/v0.25.0/ + # eventlet/wsgi.py#L504 + self.headers.add_header(header, value) + headers_raw.append((header, value)) + wsgi_key = 'HTTP_' + header.replace('-', '_').encode( + 'latin1').upper().decode('latin1') + if wsgi_key in ('HTTP_CONTENT_LENGTH', + 'HTTP_CONTENT_TYPE'): + wsgi_key = wsgi_key[5:] + environ[wsgi_key] = value + environ['headers_raw'] = tuple(headers_raw) + # Since we parsed some more headers, check to see if they + # change how our wsgi.input should behave + te = environ.get('HTTP_TRANSFER_ENCODING', '').lower() + if te.rsplit(',', 1)[-1].strip() == 'chunked': + environ['wsgi.input'].chunked_input = True + else: + length = environ.get('CONTENT_LENGTH') + if length: + length = int(length) + environ['wsgi.input'].content_length = length + if environ.get('HTTP_EXPECT', '').lower() == '100-continue': + environ['wsgi.input'].wfile = self.wfile + environ['wsgi.input'].wfile_line = \ + b'HTTP/1.1 100 Continue\r\n' + return environ def _read_request_line(self): # Note this is not a new-style class, so super() won't work @@ -332,8 +314,7 @@ def __init__(self, *a, **kw): SwiftHttpProtocol.__init__(self, *a, **kw) def handle_error(self, connection_line): - if not six.PY2: - connection_line = connection_line.decode('latin-1') + connection_line = connection_line.decode('latin-1') # No further processing will proceed on this connection under any # circumstances. We always send the request into the superclass to @@ -373,16 +354,12 @@ def handle(self): # line. pass elif proxy_parts[1] in (b'TCP4', b'TCP6') and len(proxy_parts) == 6: - if six.PY2: - self.client_address = (proxy_parts[2], proxy_parts[4]) - self.proxy_address = (proxy_parts[3], proxy_parts[5]) - else: - self.client_address = ( - proxy_parts[2].decode('latin-1'), - proxy_parts[4].decode('latin-1')) - self.proxy_address = ( - proxy_parts[3].decode('latin-1'), - proxy_parts[5].decode('latin-1')) + self.client_address = ( + proxy_parts[2].decode('latin-1'), + proxy_parts[4].decode('latin-1')) + self.proxy_address = ( + proxy_parts[3].decode('latin-1'), + proxy_parts[5].decode('latin-1')) else: self.handle_error(connection_line) diff --git a/swift/common/internal_client.py b/swift/common/internal_client.py index fc5242ae8a..883cd4e16e 100644 --- a/swift/common/internal_client.py +++ b/swift/common/internal_client.py @@ -14,13 +14,13 @@ # limitations under the License. from eventlet import sleep, Timeout, spawn -from eventlet.green import httplib, socket +from eventlet.green import socket +from eventlet.green.http import client as http_client +from eventlet.green.urllib import request as urllib_request import json -import six -from six.moves import range -from six.moves import urllib +import urllib import struct -from sys import exc_info, exit +from sys import exit import zlib from time import gmtime, strftime, time from zlib import compressobj @@ -34,11 +34,6 @@ from swift.common.utils import quote, close_if_possible, drain_and_close from swift.common.wsgi import loadapp -if six.PY3: - from eventlet.green.urllib import request as urllib2 -else: - from eventlet.green import urllib2 - class UnexpectedResponse(Exception): """ @@ -127,8 +122,6 @@ def __next__(self): return chunk raise StopIteration - next = __next__ - def seek(self, offset, whence=0): if not (offset == 0 and whence == 0): raise NotImplementedError('Seek implemented on offset 0 only') @@ -217,7 +210,7 @@ def make_request( headers.setdefault(USE_REPLICATION_NETWORK_HEADER, 'true') for attempt in range(self.request_tries): - resp = exc_type = exc_value = exc_traceback = None + resp = err = None req = Request.blank( path, environ={'REQUEST_METHOD': method}, headers=headers) if body_file is not None: @@ -229,8 +222,8 @@ def make_request( try: # execute in a separate greenthread to not polute corolocals resp = spawn(req.get_response, self.app).wait() - except (Exception, Timeout): - exc_type, exc_value, exc_traceback = exc_info() + except (Exception, Timeout) as e: + err = e else: if resp.status_int in acceptable_statuses or \ resp.status_int // 100 in acceptable_statuses: @@ -256,9 +249,8 @@ def make_request( # non 2XX responses msg += ' (%s)' % resp.body raise UnexpectedResponse(msg, resp) - if exc_type: - # To make pep8 tool happy, in place of raise t, v, tb: - six.reraise(exc_type, exc_value, exc_traceback) + if err: + raise err def handle_request(self, *args, **kwargs): resp = self.make_request(*args, **kwargs) @@ -848,10 +840,10 @@ def upload_object( def get_auth(url, user, key, auth_version='1.0', **kwargs): if auth_version != '1.0': exit('ERROR: swiftclient missing, only auth v1.0 supported') - req = urllib2.Request(url) + req = urllib_request.Request(url) req.add_header('X-Auth-User', user) req.add_header('X-Auth-Key', key) - conn = urllib2.urlopen(req) + conn = urllib_request.urlopen(req) headers = conn.info() return ( headers.getheader('X-Storage-Url'), @@ -914,12 +906,12 @@ def base_request(self, method, container=None, name=None, prefix=None, url += '?' + '&'.join(params) - req = urllib2.Request(url, headers=headers, data=contents) + req = urllib_request.Request(url, headers=headers, data=contents) if proxy: proxy = urllib.parse.urlparse(proxy) req.set_proxy(proxy.netloc, proxy.scheme) req.get_method = lambda: method - conn = urllib2.urlopen(req, timeout=timeout) + conn = urllib_request.urlopen(req, timeout=timeout) body = conn.read() info = conn.info() try: @@ -961,14 +953,15 @@ def retry_request(self, method, **kwargs): self.attempts += 1 try: return self.base_request(method, **kwargs) - except urllib2.HTTPError as err: + except urllib_request.HTTPError as err: if is_client_error(err.getcode() or 500): raise ClientException('Client error', http_status=err.getcode()) elif self.attempts > retries: raise ClientException('Raise too many retries', http_status=err.getcode()) - except (socket.error, httplib.HTTPException, urllib2.URLError): + except (socket.error, http_client.HTTPException, + urllib_request.URLError): if self.attempts > retries: raise sleep(backoff) diff --git a/swift/common/linkat.py b/swift/common/linkat.py index 3de45e2a3d..a85463a325 100644 --- a/swift/common/linkat.py +++ b/swift/common/linkat.py @@ -17,8 +17,6 @@ import ctypes from ctypes.util import find_library -import six - __all__ = ['linkat'] @@ -72,9 +70,9 @@ def __call__(self, olddirfd, oldpath, newdirfd, newpath, flags): if not isinstance(olddirfd, int) or not isinstance(newdirfd, int): raise TypeError("fd must be an integer.") - if isinstance(oldpath, six.text_type): + if isinstance(oldpath, str): oldpath = oldpath.encode('utf8') - if isinstance(newpath, six.text_type): + if isinstance(newpath, str): newpath = newpath.encode('utf8') return self._c_linkat(olddirfd, oldpath, newdirfd, newpath, flags) diff --git a/swift/common/manager.py b/swift/common/manager.py index a0e0ef56ec..80beecf46b 100644 --- a/swift/common/manager.py +++ b/swift/common/manager.py @@ -24,14 +24,9 @@ import time import subprocess import re -import six import sys import tempfile -try: - from shutil import which -except ImportError: - # py2 - from distutils.spawn import find_executable as which +from shutil import which from swift.common.utils import search_tree, remove_file, write_file, readconf from swift.common.exceptions import InvalidPidFileException @@ -845,10 +840,8 @@ def wait(self, **kwargs): if proc.stdout.closed: output = '' else: - output = proc.stdout.read() + output = proc.stdout.read().decode('utf8', 'backslashreplace') proc.stdout.close() - if not six.PY2: - output = output.decode('utf8', 'backslashreplace') if kwargs.get('once', False): # if you don't want once to wait you can send it to the diff --git a/swift/common/memcached.py b/swift/common/memcached.py index 68f3424c76..9ffd861f34 100644 --- a/swift/common/memcached.py +++ b/swift/common/memcached.py @@ -45,7 +45,6 @@ """ import os -import six import json import logging # the name of 'time' module is changed to 'tm', to avoid changing the @@ -56,8 +55,7 @@ from eventlet.green import socket, ssl from eventlet.pools import Pool from eventlet import Timeout -from six.moves import range -from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError +from configparser import ConfigParser, NoSectionError, NoOptionError from swift.common import utils from swift.common.exceptions import MemcacheConnectionError, \ MemcacheIncrNotFoundError, MemcachePoolTimeout @@ -91,10 +89,7 @@ def md5hash(key): if not isinstance(key, bytes): - if six.PY2: - key = key.encode('utf-8') - else: - key = key.encode('utf-8', errors='surrogateescape') + key = key.encode('utf-8', errors='surrogateescape') return md5(key, usedforsecurity=False).hexdigest().encode('ascii') @@ -421,8 +416,7 @@ def set(self, key, value, serialize=True, time=0, # Wait for the set to complete msg = fp.readline().strip() if msg != b'STORED': - if not six.PY2: - msg = msg.decode('ascii') + msg = msg.decode('ascii') raise MemcacheConnectionError('failed set: %s' % msg) self._return_conn(server, fp, sock) return diff --git a/swift/common/middleware/acl.py b/swift/common/middleware/acl.py index b0a01166c4..a8c0e04bce 100644 --- a/swift/common/middleware/acl.py +++ b/swift/common/middleware/acl.py @@ -14,8 +14,7 @@ # limitations under the License. import json -import six -from six.moves.urllib.parse import unquote, urlparse +from urllib.parse import unquote, urlparse def clean_acl(name, value): @@ -294,12 +293,8 @@ def acls_from_account_info(info): if not any((admin_members, readwrite_members, readonly_members)): return None - acls = { + return { 'admin': admin_members, 'read-write': readwrite_members, 'read-only': readonly_members, } - if six.PY2: - for k in ('admin', 'read-write', 'read-only'): - acls[k] = [v.encode('utf8') for v in acls[k]] - return acls diff --git a/swift/common/middleware/bulk.py b/swift/common/middleware/bulk.py index 6484508057..eb6465f16e 100644 --- a/swift/common/middleware/bulk.py +++ b/swift/common/middleware/bulk.py @@ -195,7 +195,6 @@ """ import json -import six import tarfile from xml.sax.saxutils import escape # nosec B406 from time import time @@ -257,8 +256,6 @@ def get_response_body(data_format, data_dict, error_list, root_tag): escape(status), '\n', ]) output.extend(['\n\n']) - if six.PY2: - return ''.join(output) return ''.join(output).encode('utf-8') output = [] @@ -268,8 +265,6 @@ def get_response_body(data_format, data_dict, error_list, root_tag): output.extend( '%s, %s\n' % (name, status) for name, status in error_list) - if six.PY2: - return ''.join(output) return ''.join(output).encode('utf-8') @@ -279,13 +274,9 @@ def pax_key_to_swift_header(pax_key): return "Content-Type" elif pax_key.startswith(u"SCHILY.xattr.user.meta."): useful_part = pax_key[len(u"SCHILY.xattr.user.meta."):] - if six.PY2: - return "X-Object-Meta-" + useful_part.encode("utf-8") return str_to_wsgi("X-Object-Meta-" + useful_part) elif pax_key.startswith(u"LIBARCHIVE.xattr.user.meta."): useful_part = pax_key[len(u"LIBARCHIVE.xattr.user.meta."):] - if six.PY2: - return "X-Object-Meta-" + useful_part.encode("utf-8") return str_to_wsgi("X-Object-Meta-" + useful_part) else: # You can get things like atime/mtime/ctime or filesystem ACLs in @@ -357,15 +348,12 @@ def get_objs_to_delete(self, req): while data_remaining: if b'\n' in line: obj_to_delete, line = line.split(b'\n', 1) - if six.PY2: - obj_to_delete = wsgi_unquote(obj_to_delete.strip()) - else: - # yeah, all this chaining is pretty terrible... - # but it gets even worse trying to use UTF-8 and - # errors='surrogateescape' when dealing with terrible - # input like b'\xe2%98\x83' - obj_to_delete = wsgi_to_str(wsgi_unquote( - bytes_to_wsgi(obj_to_delete.strip()))) + # yeah, all this chaining is pretty terrible... + # but it gets even worse trying to use UTF-8 and + # errors='surrogateescape' when dealing with terrible + # input like b'\xe2%98\x83' + obj_to_delete = wsgi_to_str(wsgi_unquote( + bytes_to_wsgi(obj_to_delete.strip()))) objs_to_delete.append({'name': obj_to_delete}) else: data = req.body_file.read(self.max_path_length) @@ -373,11 +361,8 @@ def get_objs_to_delete(self, req): line += data else: data_remaining = False - if six.PY2: - obj_to_delete = wsgi_unquote(line.strip()) - else: - obj_to_delete = wsgi_to_str(wsgi_unquote( - bytes_to_wsgi(line.strip()))) + obj_to_delete = wsgi_to_str(wsgi_unquote( + bytes_to_wsgi(line.strip()))) if obj_to_delete: objs_to_delete.append({'name': obj_to_delete}) if len(objs_to_delete) > self.max_deletes_per_request: @@ -577,9 +562,7 @@ def handle_extract_iter(self, req, compress_type, len(failed_files) >= self.max_failed_extractions: break if tar_info.isfile(): - obj_path = tar_info.name - if not six.PY2: - obj_path = obj_path.encode('utf-8', 'surrogateescape') + obj_path = tar_info.name.encode('utf-8', 'surrogateescape') obj_path = bytes_to_wsgi(obj_path) if obj_path.startswith('./'): obj_path = obj_path[2:] diff --git a/swift/common/middleware/cname_lookup.py b/swift/common/middleware/cname_lookup.py index 8cf5123e14..b9ef4f616f 100644 --- a/swift/common/middleware/cname_lookup.py +++ b/swift/common/middleware/cname_lookup.py @@ -27,8 +27,6 @@ rewritten and the request is passed further down the WSGI chain. """ -import six - try: import dns.resolver import dns.exception @@ -149,8 +147,6 @@ def __call__(self, env, start_response): if self.memcache: memcache_key = ''.join(['cname-', a_domain]) found_domain = self.memcache.get(memcache_key) - if six.PY2 and found_domain: - found_domain = found_domain.encode('utf-8') if found_domain is None: ttl, found_domain = lookup_cname(a_domain, self.resolver) if self.memcache and ttl > 0: diff --git a/swift/common/middleware/crypto/crypto_utils.py b/swift/common/middleware/crypto/crypto_utils.py index 16beceddd2..5cd2740bf9 100644 --- a/swift/common/middleware/crypto/crypto_utils.py +++ b/swift/common/middleware/crypto/crypto_utils.py @@ -19,8 +19,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -import six -from six.moves.urllib import parse as urlparse +import urllib.parse from swift.common.exceptions import EncryptionException, UnknownSecretIdError from swift.common.swob import HTTPInternalServerError @@ -225,7 +224,7 @@ def b64_encode_meta(crypto_meta): for name, value in crypto_meta.items()} # use sort_keys=True to make serialized form predictable for testing - return urlparse.quote_plus( + return urllib.parse.quote_plus( json.dumps(b64_encode_meta(crypto_meta), sort_keys=True)) @@ -251,13 +250,13 @@ def b64_decode_meta(crypto_meta): str(name): ( base64.b64decode(val) if name in ('iv', 'key') and b64decode else b64_decode_meta(val) if isinstance(val, dict) - else val.encode('utf8') if six.PY2 else val) + else val) for name, val in crypto_meta.items()} try: - if not isinstance(value, six.string_types): + if not isinstance(value, str): raise ValueError('crypto meta not a string') - val = json.loads(urlparse.unquote_plus(value)) + val = json.loads(urllib.parse.unquote_plus(value)) if not isinstance(val, dict): raise ValueError('crypto meta not a Mapping') return b64_decode_meta(val) diff --git a/swift/common/middleware/crypto/keymaster.py b/swift/common/middleware/crypto/keymaster.py index 42f723d3de..f8d0e046ba 100644 --- a/swift/common/middleware/crypto/keymaster.py +++ b/swift/common/middleware/crypto/keymaster.py @@ -14,7 +14,6 @@ # limitations under the License. import hashlib import hmac -import six from swift.common.exceptions import UnknownSecretIdError from swift.common.middleware.crypto.crypto_utils import CRYPTO_KEY_CALLBACK @@ -101,14 +100,9 @@ def fetch_crypto_keys(self, key_id=None, *args, **kwargs): # Older py3 proxies may have written down crypto meta as WSGI # strings; we still need to be able to read that try: - if six.PY2: - alt_path = tuple( - part.decode('utf-8').encode('latin1') - for part in (key_acct, key_cont, key_obj)) - else: - alt_path = tuple( - part.encode('latin1').decode('utf-8') - for part in (key_acct, key_cont, key_obj)) + alt_path = tuple( + part.encode('latin1').decode('utf-8') + for part in (key_acct, key_cont, key_obj)) except UnicodeError: # Well, it was worth a shot pass @@ -336,8 +330,7 @@ def create_key(self, path, secret_id=None): self.logger.warning('Unrecognised secret id: %s' % secret_id) raise UnknownSecretIdError(secret_id) else: - if not six.PY2: - path = path.encode('utf-8') + path = path.encode('utf-8') return hmac.new(key, path, digestmod=hashlib.sha256).digest() diff --git a/swift/common/middleware/dlo.py b/swift/common/middleware/dlo.py index 5cb5223099..1b41ac9091 100644 --- a/swift/common/middleware/dlo.py +++ b/swift/common/middleware/dlo.py @@ -120,8 +120,6 @@ import json -import six - from swift.common import constraints from swift.common.exceptions import ListingIterError, SegmentError from swift.common.http import is_success @@ -207,8 +205,6 @@ def _segment_listing_iterator(self, req, version, account, container, break seg_name = segment['name'] - if six.PY2: - seg_name = seg_name.encode("utf-8") # We deliberately omit the etag and size here; # SegmentedIterable will check size and etag if diff --git a/swift/common/middleware/formpost.py b/swift/common/middleware/formpost.py index 45b5800956..00acfb5430 100644 --- a/swift/common/middleware/formpost.py +++ b/swift/common/middleware/formpost.py @@ -123,11 +123,9 @@ __all__ = ['FormPost', 'filter_factory', 'READ_CHUNK_SIZE', 'MAX_VALUE_LENGTH'] import hmac -import hashlib from time import time -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift.common.constraints import valid_api_version from swift.common.exceptions import MimeInvalid @@ -249,9 +247,7 @@ def __call__(self, env, start_response): ('Content-Length', str(len(body))))) return [body] except (FormInvalid, EOFError) as err: - body = 'FormPost: %s' % err - if six.PY3: - body = body.encode('utf-8') + body = ('FormPost: %s' % err).encode('utf-8') start_response( '400 Bad Request', (('Content-Type', 'text/plain'), @@ -273,8 +269,7 @@ def _translate_form(self, env, boundary): :returns: status_line, headers_list, body """ keys = self._get_keys(env) - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = boundary.encode('utf-8') status = message = '' attributes = {} file_attributes = {} @@ -320,8 +315,7 @@ def _translate_form(self, env, boundary): data += chunk while fp.read(READ_CHUNK_SIZE): pass - if six.PY3: - data = data.decode('utf-8') + data = data.decode('utf-8') if 'name' in attrs: attributes[attrs['name'].lower()] = data.rstrip('\r\n--') if not status: @@ -337,8 +331,7 @@ def _translate_form(self, env, boundary): body = status if message: body = status + '\r\nFormPost: ' + message.title() - if six.PY3: - body = body.encode('utf-8') + body = body.encode('utf-8') if not is_success(status_code) and resp_body: body = resp_body headers.extend([('Content-Type', 'text/plain'), @@ -352,8 +345,7 @@ def _translate_form(self, env, boundary): quote(message)) body = '

' \ 'Click to continue...

' % redirect - if six.PY3: - body = body.encode('utf-8') + body = body.encode('utf-8') headers.extend( [('Location', redirect), ('Content-Length', str(len(body)))]) return '303 See Other', headers, body @@ -415,8 +407,7 @@ def _perform_subrequest(self, orig_env, attributes, fp, keys): attributes.get('max_file_size') or '0', attributes.get('max_file_count') or '0', attributes.get('expires') or '0') - if six.PY3: - hmac_body = hmac_body.encode('utf-8') + hmac_body = hmac_body.encode('utf-8') has_valid_sig = False signature = attributes.get('signature', '') @@ -426,13 +417,12 @@ def _perform_subrequest(self, orig_env, attributes, fp, keys): raise FormUnauthorized('invalid signature') if hash_name not in self.allowed_digests: raise FormUnauthorized('invalid signature') - hash_algorithm = getattr(hashlib, hash_name) if six.PY2 else hash_name for key in keys: # Encode key like in swift.common.utls.get_hmac. - if not isinstance(key, six.binary_type): + if not isinstance(key, bytes): key = key.encode('utf8') - sig = hmac.new(key, hmac_body, hash_algorithm).hexdigest() + sig = hmac.new(key, hmac_body, hash_name).hexdigest() if streq_const_time(sig, signature): has_valid_sig = True if not has_valid_sig: diff --git a/swift/common/middleware/gatekeeper.py b/swift/common/middleware/gatekeeper.py index 0254fef98b..dfb5ef04b0 100644 --- a/swift/common/middleware/gatekeeper.py +++ b/swift/common/middleware/gatekeeper.py @@ -36,7 +36,7 @@ from swift.common.request_helpers import ( remove_items, get_sys_meta_prefix, OBJECT_TRANSIENT_SYSMETA_PREFIX ) -from six.moves.urllib.parse import urlsplit +from urllib.parse import urlsplit import re #: A list of python regular expressions that will be used to diff --git a/swift/common/middleware/list_endpoints.py b/swift/common/middleware/list_endpoints.py index 424dc7b822..edceec421e 100644 --- a/swift/common/middleware/list_endpoints.py +++ b/swift/common/middleware/list_endpoints.py @@ -80,7 +80,7 @@ import json -from six.moves.urllib.parse import quote, unquote +from urllib.parse import quote, unquote from swift.common.ring import Ring from swift.common.utils import get_logger, split_path diff --git a/swift/common/middleware/listing_formats.py b/swift/common/middleware/listing_formats.py index 643341afb7..6d4ece4719 100644 --- a/swift/common/middleware/listing_formats.py +++ b/swift/common/middleware/listing_formats.py @@ -14,7 +14,6 @@ # limitations under the License. import json -import six from xml.etree.cElementTree import Element, SubElement, tostring from swift.common.constraints import valid_api_version @@ -84,8 +83,7 @@ def account_to_xml(listing, account_name): else: sub = SubElement(doc, 'container') for field in ('name', 'count', 'bytes', 'last_modified'): - SubElement(sub, field).text = six.text_type( - record.pop(field)) + SubElement(sub, field).text = str(record.pop(field)) sub.tail = '\n' return to_xml(doc) @@ -101,8 +99,7 @@ def container_to_xml(listing, base_name): sub = SubElement(doc, 'object') for field in ('name', 'hash', 'bytes', 'content_type', 'last_modified'): - SubElement(sub, field).text = six.text_type( - record.pop(field)) + SubElement(sub, field).text = str(record.pop(field)) return to_xml(doc) @@ -126,8 +123,6 @@ def filter_reserved(self, listing, account, container): for entry in list(listing): for key in ('name', 'subdir'): value = entry.get(key, '') - if six.PY2: - value = value.encode('utf-8') if RESERVED in value: if container: self.logger.warning( diff --git a/swift/common/middleware/s3api/controllers/bucket.py b/swift/common/middleware/s3api/controllers/bucket.py index 35d9fc516f..c4c8530c16 100644 --- a/swift/common/middleware/s3api/controllers/bucket.py +++ b/swift/common/middleware/s3api/controllers/bucket.py @@ -16,8 +16,7 @@ from base64 import standard_b64encode as b64encode from base64 import standard_b64decode as b64decode -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift.common import swob from swift.common.http import HTTP_OK @@ -145,9 +144,8 @@ def _parse_request_options(self, req, max_keys): query['marker'] = swob.wsgi_to_str(req.params['start-after']) # continuation-token overrides start-after if 'continuation-token' in req.params: - decoded = b64decode(req.params['continuation-token']) - if not six.PY2: - decoded = decoded.decode('utf8') + decoded = b64decode( + req.params['continuation-token']).decode('utf8') query['marker'] = decoded if 'fetch-owner' in req.params: fetch_owner = config_true_value(req.params['fetch-owner']) diff --git a/swift/common/middleware/s3api/controllers/multi_upload.py b/swift/common/middleware/s3api/controllers/multi_upload.py index 735d2be7cd..07e71a12af 100644 --- a/swift/common/middleware/s3api/controllers/multi_upload.py +++ b/swift/common/middleware/s3api/controllers/multi_upload.py @@ -65,17 +65,14 @@ import re import time -import six - from swift.common import constraints from swift.common.swob import Range, bytes_to_wsgi, normalize_etag, \ wsgi_to_str from swift.common.utils import json, public, reiterate, md5, Timestamp -from swift.common.db import utf8encode from swift.common.request_helpers import get_container_update_override_key, \ get_param -from six.moves.urllib.parse import quote, urlparse +from urllib.parse import quote, urlparse from swift.common.middleware.s3api.controllers.base import Controller, \ bucket_operation, object_operation, check_container_existence @@ -293,8 +290,6 @@ def separate_uploads(uploads, prefix, delimiter): :return (non_delimited_uploads, common_prefixes) """ - if six.PY2: - (prefix, delimiter) = utf8encode(prefix, delimiter) non_delimited_uploads = [] common_prefixes = set() for upload in uploads: @@ -363,10 +358,7 @@ def object_to_upload(object_info): new_uploads, prefix, delimiter) uploads.extend(new_uploads) prefixes.extend(new_prefixes) - if six.PY2: - query['marker'] = objects[-1]['name'].encode('utf-8') - else: - query['marker'] = objects[-1]['name'] + query['marker'] = objects[-1]['name'] truncated = len(uploads) >= maxuploads if len(uploads) > maxuploads: @@ -542,10 +534,7 @@ def filter_part_num_marker(o): if not new_objects: break objects.extend(new_objects) - if six.PY2: - query['marker'] = new_objects[-1]['name'].encode('utf-8') - else: - query['marker'] = new_objects[-1]['name'] + query['marker'] = new_objects[-1]['name'] last_part = 0 @@ -642,10 +631,7 @@ def DELETE(self, req): container = req.container_name + MULTIUPLOAD_SUFFIX obj = bytes_to_wsgi(o['name'].encode('utf-8')) req.get_response(self.app, container=container, obj=obj) - if six.PY2: - query['marker'] = objects[-1]['name'].encode('utf-8') - else: - query['marker'] = objects[-1]['name'] + query['marker'] = objects[-1]['name'] resp = req.get_response(self.app, 'GET', container, '', query=query) objects = json.loads(resp.body) diff --git a/swift/common/middleware/s3api/controllers/s3_acl.py b/swift/common/middleware/s3api/controllers/s3_acl.py index 7bb3764e08..ddd7fbe3d2 100644 --- a/swift/common/middleware/s3api/controllers/s3_acl.py +++ b/swift/common/middleware/s3api/controllers/s3_acl.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift.common.utils import public from swift.common.middleware.s3api.controllers.base import Controller diff --git a/swift/common/middleware/s3api/etree.py b/swift/common/middleware/s3api/etree.py index 4c24f8427b..e5d4112b8f 100644 --- a/swift/common/middleware/s3api/etree.py +++ b/swift/common/middleware/s3api/etree.py @@ -26,12 +26,11 @@ else: import importlib.resources resource_stream = None -import six from swift.common.utils import get_logger from swift.common.middleware.s3api.exception import S3Exception from swift.common.middleware.s3api.utils import camel_to_snake, \ - utf8encode, utf8decode + utf8decode XMLNS_S3 = 'http://s3.amazonaws.com/doc/2006-03-01/' XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance' @@ -51,7 +50,7 @@ def remove_ns(tag, ns): tag = tag[len('{%s}' % ns):] return tag - if not isinstance(elem.tag, six.string_types): + if not isinstance(elem.tag, str): # elem is a comment element. return @@ -136,8 +135,6 @@ def text(self): """ utf-8 wrapper property of lxml.etree.Element.text """ - if six.PY2: - return utf8encode(lxml.etree.ElementBase.text.__get__(self)) return lxml.etree.ElementBase.text.__get__(self) @text.setter diff --git a/swift/common/middleware/s3api/s3api.py b/swift/common/middleware/s3api/s3api.py index 55c8732f6c..cb498de3c3 100644 --- a/swift/common/middleware/s3api/s3api.py +++ b/swift/common/middleware/s3api/s3api.py @@ -144,7 +144,7 @@ from cgi import parse_header import json from paste.deploy import loadwsgi -from six.moves.urllib.parse import parse_qs +from urllib.parse import parse_qs from swift.common.constraints import valid_api_version from swift.common.middleware.listing_formats import \ diff --git a/swift/common/middleware/s3api/s3request.py b/swift/common/middleware/s3api/s3request.py index 282c82c0a0..c0ec725d14 100644 --- a/swift/common/middleware/s3api/s3request.py +++ b/swift/common/middleware/s3api/s3request.py @@ -20,9 +20,8 @@ from hashlib import sha1, sha256 import hmac import re -import six # pylint: disable-msg=import-error -from six.moves.urllib.parse import quote, unquote, parse_qsl +from urllib.parse import quote, unquote, parse_qsl import string from swift.common.utils import split_path, json, close_if_possible, md5, \ @@ -421,7 +420,7 @@ def _headers_to_sign(self): else: # mostly-functional fallback headers_lower_dict = dict( (k.lower().strip(), ' '.join(_header_strip(v or '').split())) - for (k, v) in six.iteritems(self.headers)) + for (k, v) in self.headers.items()) if 'host' in headers_lower_dict and re.match( 'Boto/2.[0-9].[0-2]', @@ -636,9 +635,8 @@ def check_signature(self, secret): secret = utf8encode(secret) user_signature = self.signature valid_signature = base64.b64encode(hmac.new( - secret, self.string_to_sign, sha1).digest()).strip() - if not six.PY2: - valid_signature = valid_signature.decode('ascii') + secret, self.string_to_sign, sha1 + ).digest()).strip().decode('ascii') return streq_const_time(user_signature, valid_signature) @property @@ -1488,8 +1486,6 @@ def _get_response(self, app, method, container, obj, self.user_id = "%s:%s" % ( sw_resp.environ['HTTP_X_TENANT_NAME'], sw_resp.environ['HTTP_X_USER_NAME']) - if six.PY2 and not isinstance(self.user_id, bytes): - self.user_id = self.user_id.encode('utf8') else: # tempauth self.user_id = self.access_key @@ -1687,8 +1683,6 @@ def authenticate(self, app): # keystone self.user_id = "%s:%s" % (sw_resp.environ['HTTP_X_TENANT_NAME'], sw_resp.environ['HTTP_X_USER_NAME']) - if six.PY2 and not isinstance(self.user_id, bytes): - self.user_id = self.user_id.encode('utf8') else: # tempauth self.user_id = self.access_key diff --git a/swift/common/middleware/s3api/s3response.py b/swift/common/middleware/s3api/s3response.py index 9a06b523f1..299bf30cef 100644 --- a/swift/common/middleware/s3api/s3response.py +++ b/swift/common/middleware/s3api/s3response.py @@ -14,10 +14,7 @@ # limitations under the License. import re -try: - from collections.abc import MutableMapping -except ImportError: - from collections import MutableMapping # py2 +from collections.abc import MutableMapping from functools import partial from swift.common import header_key_dict diff --git a/swift/common/middleware/s3api/s3token.py b/swift/common/middleware/s3api/s3token.py index 23ebcc7086..0c3f15d891 100644 --- a/swift/common/middleware/s3api/s3token.py +++ b/swift/common/middleware/s3api/s3token.py @@ -61,8 +61,7 @@ from keystoneauth1 import session as keystone_session from keystoneauth1 import loading as keystone_loading import requests -import six -from six.moves import urllib +import urllib from swift.common.swob import Request, HTTPBadRequest, HTTPUnauthorized, \ HTTPException, str_to_wsgi @@ -217,9 +216,7 @@ def _deny_request(self, code): error_msg = ('\r\n' '\r\n %s\r\n ' '%s\r\n\r\n' % - (code, message)) - if six.PY3: - error_msg = error_msg.encode() + (code, message)).encode() resp.body = error_msg return resp @@ -266,18 +263,18 @@ def __call__(self, environ, start_response): return self._app(environ, start_response) access = s3_auth_details['access_key'] - if isinstance(access, six.binary_type): + if isinstance(access, bytes): access = access.decode('utf-8') signature = s3_auth_details['signature'] - if isinstance(signature, six.binary_type): + if isinstance(signature, bytes): signature = signature.decode('utf-8') string_to_sign = s3_auth_details['string_to_sign'] - if isinstance(string_to_sign, six.text_type): + if isinstance(string_to_sign, str): string_to_sign = string_to_sign.encode('utf-8') token = base64.urlsafe_b64encode(string_to_sign) - if isinstance(token, six.binary_type): + if isinstance(token, bytes): token = token.decode('ascii') # NOTE(chmou): This is to handle the special case with nova @@ -399,8 +396,6 @@ def __call__(self, environ, start_response): req.headers.update(headers) tenant_to_connect = force_tenant or tenant['id'] - if six.PY2 and isinstance(tenant_to_connect, six.text_type): - tenant_to_connect = tenant_to_connect.encode('utf-8') self._logger.debug('Connecting with tenant: %s', tenant_to_connect) new_tenant_name = '%s%s' % (self._reseller_prefix, tenant_to_connect) environ['PATH_INFO'] = environ['PATH_INFO'].replace( diff --git a/swift/common/middleware/s3api/subresource.py b/swift/common/middleware/s3api/subresource.py index 1aa47b4b2d..42af24bd05 100644 --- a/swift/common/middleware/s3api/subresource.py +++ b/swift/common/middleware/s3api/subresource.py @@ -43,8 +43,6 @@ """ from functools import partial -import six - from swift.common.utils import json from swift.common.middleware.s3api.s3response import InvalidArgument, \ @@ -233,7 +231,7 @@ class Owner(object): """ def __init__(self, id, name): self.id = id - if not (name is None or isinstance(name, six.string_types)): + if not (name is None or isinstance(name, str)): raise TypeError('name must be a string or None') self.name = name @@ -429,8 +427,6 @@ def __bytes__(self): return tostring(self.elem()) def __repr__(self): - if six.PY2: - return self.__bytes__() return self.__bytes__().decode('utf8') @classmethod diff --git a/swift/common/middleware/s3api/utils.py b/swift/common/middleware/s3api/utils.py index 4c6a6b0b81..bd5fe14a25 100644 --- a/swift/common/middleware/s3api/utils.py +++ b/swift/common/middleware/s3api/utils.py @@ -18,7 +18,6 @@ import datetime import email.utils import re -import six import time import uuid @@ -54,8 +53,6 @@ def snake_to_camel(snake): def unique_id(): result = base64.urlsafe_b64encode(str(uuid.uuid4()).encode('ascii')) - if six.PY2: - return result return result.decode('ascii') diff --git a/swift/common/middleware/slo.py b/swift/common/middleware/slo.py index 160a9ca485..8bbb77c5ab 100644 --- a/swift/common/middleware/slo.py +++ b/swift/common/middleware/slo.py @@ -347,8 +347,6 @@ import re import time -import six - from swift.cli.container_deleter import make_delete_jobs from swift.common.header_key_dict import HeaderKeyDict from swift.common.exceptions import ListingIterError, SegmentError @@ -361,7 +359,7 @@ HTTPServiceUnavailable, Response, Range, normalize_etag, \ RESPONSE_REASONS, str_to_wsgi, bytes_to_wsgi, wsgi_to_str, wsgi_quote from swift.common.utils import get_logger, config_true_value, \ - get_valid_utf8_str, override_bytes_from_content_type, split_path, \ + override_bytes_from_content_type, split_path, \ RateLimitedIterator, quote, closing_if_possible, \ LRUCache, StreamingPile, strict_b64decode, Timestamp, friendly_close, \ get_expirer_container, md5 @@ -462,12 +460,12 @@ def parse_and_validate_input(req_body, req_path): continue if segment_type == 'path': - if not isinstance(seg_dict['path'], six.string_types): + if not isinstance(seg_dict['path'], str): errors.append(b"Index %d: \"path\" must be a string" % seg_index) continue if not (seg_dict.get('etag') is None or - isinstance(seg_dict['etag'], six.string_types)): + isinstance(seg_dict['etag'], str)): errors.append(b'Index %d: "etag" must be a string or null ' b'(if provided)' % seg_index) continue @@ -761,9 +759,7 @@ def _fetch_sub_slo_segments(self, req, version, acc, con, obj): if not sub_resp.is_success: # Error message should be short - body = sub_resp.body - if not six.PY2: - body = body.decode('utf-8') + body = sub_resp.body.decode('utf-8') msg = ('while fetching %s, GET of submanifest %s ' 'failed with status %d (%s)') raise ListingIterError(msg % ( @@ -873,10 +869,7 @@ def _byterange_listing_iterator(self, req, version, account, segments, "While processing manifest %r, " "max recursion depth was exceeded" % req.path) - if six.PY2: - sub_path = get_valid_utf8_str(seg_dict['name']) - else: - sub_path = seg_dict['name'] + sub_path = seg_dict['name'] sub_cont, sub_obj = split_path(sub_path, 2, 2, True) if last_sub_path != sub_path: sub_segments = cached_fetch_sub_slo_segments( @@ -895,8 +888,6 @@ def _byterange_listing_iterator(self, req, version, account, segments, recursion_depth=recursion_depth + 1): yield sub_seg_dict else: - if six.PY2 and isinstance(seg_dict['name'], six.text_type): - seg_dict['name'] = seg_dict['name'].encode("utf-8") yield dict(seg_dict, first_byte=max(0, first_byte) + range_start, last_byte=min(range_end, range_start + last_byte)) @@ -1211,9 +1202,7 @@ def convert_segment_listing(self, resp_iter): seg_dict['etag'] = seg_dict.pop('hash', None) json_data = json.dumps(segments, sort_keys=True) # convert to string - if six.PY3: - json_data = json_data.encode('utf-8') - return json_data + return json_data.encode('utf-8') def _get_manifest_read(self, resp_iter): with closing_if_possible(resp_iter): @@ -1402,12 +1391,8 @@ def handle_multipart_put(self, req, start_response): path2indices[seg_dict['path']].append(index) def do_head(obj_name): - if six.PY2: - obj_path = '/'.join(['', vrs, account, - get_valid_utf8_str(obj_name).lstrip('/')]) - else: - obj_path = '/'.join(['', vrs, account, - str_to_wsgi(obj_name.lstrip('/'))]) + obj_path = '/'.join(['', vrs, account, + str_to_wsgi(obj_name.lstrip('/'))]) obj_path = wsgi_quote(obj_path) sub_req = make_subrequest( @@ -1559,7 +1544,7 @@ def resp_iter(total_size=total_size): r = '%s:%s;' % (seg_data['hash'], seg_data['range']) else: r = seg_data['hash'] - slo_etag.update(r.encode('ascii') if six.PY3 else r) + slo_etag.update(r.encode('ascii')) slo_etag = slo_etag.hexdigest() client_etag = normalize_etag(req.headers.get('Etag')) @@ -1569,7 +1554,7 @@ def resp_iter(total_size=total_size): resp_dict = {} resp_dict['Response Status'] = err.status err_body = err.body - if six.PY3 and isinstance(err_body, bytes): + if isinstance(err_body, bytes): err_body = err_body.decode('utf-8', errors='replace') resp_dict['Response Body'] = err_body or '\n'.join( RESPONSE_REASONS.get(err.status_int, [''])) @@ -1581,9 +1566,7 @@ def resp_iter(total_size=total_size): yield chunk return - json_data = json.dumps(data_for_storage) - if six.PY3: - json_data = json_data.encode('utf-8') + json_data = json.dumps(data_for_storage).encode('utf-8') req.body = json_data req.headers.update({ SYSMETA_SLO_ETAG: slo_etag, @@ -1618,7 +1601,7 @@ def resp_iter(total_size=total_size): if heartbeat: resp_body = resp.body - if six.PY3 and isinstance(resp_body, bytes): + if isinstance(resp_body, bytes): resp_body = resp_body.decode('utf-8') resp_dict['Response Body'] = resp_body yield separator + get_response_body( @@ -1644,10 +1627,7 @@ def get_segments_to_delete_iter(self, req): raise HTTPPreconditionFailed( request=req, body='Invalid UTF8 or contains NULL') vrs, account, container, obj = req.split_path(4, 4, True) - if six.PY2: - obj_path = ('/%s/%s' % (container, obj)).decode('utf-8') - else: - obj_path = '/%s/%s' % (wsgi_to_str(container), wsgi_to_str(obj)) + obj_path = '/%s/%s' % (wsgi_to_str(container), wsgi_to_str(obj)) segments = [{ 'sub_slo': True, @@ -1675,7 +1655,7 @@ def get_segments_to_delete_iter(self, req): except HTTPException as err: # allow bulk delete response to report errors err_body = err.body - if six.PY3 and isinstance(err_body, bytes): + if isinstance(err_body, bytes): err_body = err_body.decode('utf-8', errors='replace') seg_data['error'] = {'code': err.status_int, 'message': err_body} @@ -1684,8 +1664,6 @@ def get_segments_to_delete_iter(self, req): seg_data['sub_slo'] = False segments.append(seg_data) else: - if six.PY2: - seg_data['name'] = seg_data['name'].encode('utf-8') yield seg_data def get_slo_segments(self, obj_name, req): @@ -1714,15 +1692,9 @@ def get_slo_segments(self, obj_name, req): new_env['HTTP_USER_AGENT'] = \ '%s MultipartDELETE' % new_env.get('HTTP_USER_AGENT') new_env['swift.source'] = 'SLO' - if six.PY2: - new_env['PATH_INFO'] = ( - '/%s/%s/%s' % (vrs, account, - obj_name.lstrip('/').encode('utf-8')) - ) - else: - new_env['PATH_INFO'] = ( - '/%s/%s/%s' % (vrs, account, str_to_wsgi(obj_name.lstrip('/'))) - ) + new_env['PATH_INFO'] = ( + '/%s/%s/%s' % (vrs, account, str_to_wsgi(obj_name.lstrip('/'))) + ) # Just request the last byte of non-SLO objects so we don't waste # a resources in friendly_close() below manifest_req = Request.blank('', new_env, range='bytes=-1') @@ -1757,10 +1729,7 @@ def handle_async_delete(self, req): raise HTTPPreconditionFailed( request=req, body='Invalid UTF8 or contains NULL') vrs, account, container, obj = req.split_path(4, 4, True) - if six.PY2: - obj_path = ('/%s/%s' % (container, obj)).decode('utf-8') - else: - obj_path = '/%s/%s' % (wsgi_to_str(container), wsgi_to_str(obj)) + obj_path = '/%s/%s' % (wsgi_to_str(container), wsgi_to_str(obj)) segments = [seg for seg in self.get_slo_segments(obj_path, req) if 'data' not in seg] if not segments: diff --git a/swift/common/middleware/staticweb.py b/swift/common/middleware/staticweb.py index 7770af208f..d63032ae69 100644 --- a/swift/common/middleware/staticweb.py +++ b/swift/common/middleware/staticweb.py @@ -135,13 +135,12 @@ """ +import html import json -import six import time -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse -from swift.common.request_helpers import html_escape from swift.common.utils import human_readable, split_path, config_true_value, \ quote, get_logger from swift.common.registry import register_swift_info @@ -256,7 +255,7 @@ def _listing(self, env, start_response, prefix=''): body = '\n' \ '\n' \ '\n' \ - 'Listing of %s\n' % html_escape(label) + 'Listing of %s\n' % html.escape(label) if self._listings_css: body += ' \n' % self._build_css_path(prefix or '') @@ -322,7 +321,7 @@ def _listing(self, env, start_response, prefix=''): '\n' \ ' \n' \ ' Listing of %s\n' % \ - html_escape(label) + html.escape(label) if self._listings_css: body += ' \n' % (self._build_css_path(prefix)) @@ -341,7 +340,7 @@ def _listing(self, env, start_response, prefix=''): ' Name\n' \ ' Size\n' \ ' Date\n' \ - ' \n' % html_escape(label) + ' \n' % html.escape(label) if len(prefix) > len(tempurl_prefix): body += ' \n' \ ' ../\n' \ @@ -350,8 +349,7 @@ def _listing(self, env, start_response, prefix=''): ' \n' % tempurl_qs for item in listing: if 'subdir' in item: - subdir = item['subdir'] if six.PY3 else \ - item['subdir'].encode('utf-8') + subdir = item['subdir'] if prefix: subdir = subdir[len(wsgi_to_str(prefix)):] body += ' \n' \ @@ -359,28 +357,25 @@ def _listing(self, env, start_response, prefix=''): '  \n' \ '  \n' \ ' \n' % \ - (quote(subdir) + tempurl_qs, html_escape(subdir)) + (quote(subdir) + tempurl_qs, html.escape(subdir)) for item in listing: if 'name' in item: - name = item['name'] if six.PY3 else \ - item['name'].encode('utf-8') + name = item['name'] if prefix: name = name[len(wsgi_to_str(prefix)):] - content_type = item['content_type'] if six.PY3 else \ - item['content_type'].encode('utf-8') + content_type = item['content_type'] bytes = human_readable(item['bytes']) last_modified = ( - html_escape(item['last_modified'] if six.PY3 else - item['last_modified'].encode('utf-8')). + html.escape(item['last_modified']). split('.')[0].replace('T', ' ')) body += ' \n' \ ' %s\n' \ ' %s\n' \ ' %s\n' \ ' \n' % \ - (' '.join('type-' + html_escape(t.lower()) + (' '.join('type-' + html.escape(t.lower()) for t in content_type.split('/')), - quote(name) + tempurl_qs, html_escape(name), + quote(name) + tempurl_qs, html.escape(name), bytes, last_modified) body += ' \n' \ ' \n' \ diff --git a/swift/common/middleware/tempauth.py b/swift/common/middleware/tempauth.py index 52d6659a72..e3b81c15c5 100644 --- a/swift/common/middleware/tempauth.py +++ b/swift/common/middleware/tempauth.py @@ -182,7 +182,6 @@ import base64 from eventlet import Timeout -import six from swift.common.memcached import MemcacheConnectionError from swift.common.swob import ( Response, Request, wsgi_to_str, str_to_wsgi, wsgi_unquote, @@ -246,12 +245,9 @@ def __init__(self, app, conf): # Because trailing equal signs would screw up config file # parsing, we auto-pad with '=' chars. account += '=' * (len(account) % 4) - account = base64.b64decode(account) + account = base64.b64decode(account).decode('utf8') username += '=' * (len(username) % 4) - username = base64.b64decode(username) - if not six.PY2: - account = account.decode('utf8') - username = username.decode('utf8') + username = base64.b64decode(username).decode('utf8') values = conf[conf_key].split() if not values: raise ValueError('%s has no key set' % conf_key) @@ -451,8 +447,6 @@ def get_groups(self, env, token): expires, groups = cached_auth_data if expires < time(): groups = None - elif six.PY2: - groups = groups.encode('utf8') s3_auth_details = env.get('s3api.auth_details') or\ env.get('swift3.auth_details') @@ -530,7 +524,7 @@ def extract_acl_and_report_errors(self, req): if not isinstance(result[key], list): return "Value for key %s must be a list" % json.dumps(key) for grantee in result[key]: - if not isinstance(grantee, six.string_types): + if not isinstance(grantee, str): return "Elements of %s list must be strings" % json.dumps( key) @@ -838,8 +832,7 @@ def handle_get_token(self, req): cached_auth_data = memcache_client.get(memcache_token_key) if cached_auth_data: expires, old_groups = cached_auth_data - old_groups = [group.encode('utf8') if six.PY2 else group - for group in old_groups.split(',')] + old_groups = [group for group in old_groups.split(',')] new_groups = self._get_user_groups(account, account_user, account_id) diff --git a/swift/common/middleware/tempurl.py b/swift/common/middleware/tempurl.py index 022f9e8f31..0d1ff269d4 100644 --- a/swift/common/middleware/tempurl.py +++ b/swift/common/middleware/tempurl.py @@ -299,13 +299,11 @@ 'DEFAULT_OUTGOING_ALLOW_HEADERS'] from calendar import timegm -import six from os.path import basename from time import time, strftime, strptime, gmtime from ipaddress import ip_address, ip_network -from six.moves.urllib.parse import parse_qs -from six.moves.urllib.parse import urlencode +from urllib.parse import parse_qs, urlencode from swift.proxy.controllers.base import get_account_info, get_container_info from swift.common.header_key_dict import HeaderKeyDict @@ -314,7 +312,7 @@ extract_digest_and_algorithm, DEFAULT_ALLOWED_DIGESTS, get_hmac from swift.common.swob import header_to_environ_key, HTTPUnauthorized, \ HTTPBadRequest, wsgi_to_str -from swift.common.utils import split_path, get_valid_utf8_str, \ +from swift.common.utils import split_path, \ streq_const_time, quote, get_logger, close_if_possible from swift.common.registry import register_swift_info, register_sensitive_param from swift.common.wsgi import WSGIContext @@ -361,8 +359,7 @@ def get_tempurl_keys_from_metadata(meta): meta = get_account_info(...)['meta'] keys = get_tempurl_keys_from_metadata(meta) """ - return [(get_valid_utf8_str(value) if six.PY2 else value) - for key, value in meta.items() + return [value for key, value in meta.items() if key.lower() in ('temp-url-key', 'temp-url-key-2')] @@ -575,8 +572,8 @@ def __call__(self, env, start_response): if client_address is None: return self._invalid(env, start_response) try: - allowed_ip_ranges = ip_network(six.u(temp_url_ip_range)) - if ip_address(six.u(client_address)) not in allowed_ip_ranges: + allowed_ip_ranges = ip_network(str(temp_url_ip_range)) + if ip_address(str(client_address)) not in allowed_ip_ranges: return self._invalid(env, start_response) except ValueError: return self._invalid(env, start_response) diff --git a/swift/common/middleware/versioned_writes/object_versioning.py b/swift/common/middleware/versioned_writes/object_versioning.py index fea8abaade..a4f84f3813 100644 --- a/swift/common/middleware/versioned_writes/object_versioning.py +++ b/swift/common/middleware/versioned_writes/object_versioning.py @@ -145,11 +145,10 @@ import calendar import itertools import json -import six import time from cgi import parse_header -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.common.constraints import MAX_FILE_SIZE, valid_api_version, \ ACCOUNT_LISTING_LIMIT, CONTAINER_LISTING_LIMIT @@ -1190,7 +1189,6 @@ def _list_versions(self, req, start_response, location, primary_listing): name, ts = self._split_version_from_name(linked_name) if ts is None: continue - name = name.decode('utf8') if six.PY2 else name is_latest = False if name not in is_latest_set: is_latest_set.add(name) @@ -1231,8 +1229,7 @@ def _list_versions(self, req, start_response, location, primary_listing): path = '/v1/%s/%s/%s' % ( wsgi_to_str(account), wsgi_to_str(location), - item['name'].encode('utf8') - if six.PY2 else item['name']) + item['name']) if path in current_versions: item['is_latest'] = True @@ -1260,7 +1257,7 @@ def _list_versions(self, req, start_response, location, primary_listing): if ts is None: continue broken_listing.append({ - 'name': name.decode('utf8') if six.PY2 else name, + 'name': name, 'is_latest': True, 'version_id': ts.internal, 'content_type': item['content_type'], diff --git a/swift/common/middleware/x_profile/html_viewer.py b/swift/common/middleware/x_profile/html_viewer.py index 9e4efda53c..e385663f84 100644 --- a/swift/common/middleware/x_profile/html_viewer.py +++ b/swift/common/middleware/x_profile/html_viewer.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import html import os import random import re @@ -26,7 +27,6 @@ from swift.common.middleware.x_profile.exceptions import DataLoadFailure from swift.common.middleware.x_profile.exceptions import ProfileException from swift.common.middleware.x_profile.profile_model import Stats2 -from swift.common.request_helpers import html_escape PLOTLIB_INSTALLED = True try: @@ -453,7 +453,7 @@ def format_source_code(self, nfl): fmt = '%' + max_width\ + 'd|%s' for line in lines: - el = html_escape(line) + el = html.escape(line) i = i + 1 if i == lineno: fmt2 = '\ diff --git a/swift/common/middleware/xprofile.py b/swift/common/middleware/xprofile.py index 84d812acf6..a7f4f3e16b 100644 --- a/swift/common/middleware/xprofile.py +++ b/swift/common/middleware/xprofile.py @@ -85,8 +85,7 @@ from eventlet import greenthread, GreenPool, patcher import eventlet.green.profile as eprofile -import six -from six.moves import urllib +import urllib from swift.common.utils import get_logger, config_true_value from swift.common.swob import Request @@ -112,10 +111,7 @@ app_iter_ = self.app(environ, start_response) """ -if six.PY3: - thread = patcher.original('_thread') # non-monkeypatched module needed -else: - thread = patcher.original('thread') # non-monkeypatched module needed +thread = patcher.original('_thread') # non-monkeypatched module needed # This monkey patch code fix the problem of eventlet profile tool @@ -217,7 +213,7 @@ def __call__(self, environ, start_response): query_dict, self.renew_profile) start_response('200 OK', headers) - if isinstance(content, six.text_type): + if isinstance(content, str): content = content.encode('utf-8') return [content] except MethodNotAllowed as mx: diff --git a/swift/common/recon.py b/swift/common/recon.py index 44c8fb8ef1..f1928e2f1c 100644 --- a/swift/common/recon.py +++ b/swift/common/recon.py @@ -13,8 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six - RECON_RELINKER_FILE = 'relinker.recon' RECON_OBJECT_FILE = 'object.recon' RECON_CONTAINER_FILE = 'container.recon' @@ -24,7 +22,7 @@ def server_type_to_recon_file(server_type): - if not isinstance(server_type, six.string_types) or \ + if not isinstance(server_type, str) or \ server_type.lower() not in ('account', 'container', 'object'): raise ValueError('Invalid server_type') return "%s.recon" % server_type.lower() diff --git a/swift/common/registry.py b/swift/common/registry.py index 2aa5376ae0..f1b147ce80 100644 --- a/swift/common/registry.py +++ b/swift/common/registry.py @@ -16,7 +16,6 @@ # Used by get_swift_info and register_swift_info to store information about # the swift cluster. from copy import deepcopy -import six _swift_info = {} _swift_admin_info = {} @@ -115,10 +114,7 @@ def register_sensitive_header(header): """ if not isinstance(header, str): raise TypeError - if six.PY2: - header.decode('ascii') - else: - header.encode('ascii') + header.encode('ascii') _sensitive_headers.add(header.lower()) @@ -147,8 +143,5 @@ def register_sensitive_param(query_param): """ if not isinstance(query_param, str): raise TypeError - if six.PY2: - query_param.decode('ascii') - else: - query_param.encode('ascii') + query_param.encode('ascii') _sensitive_params.add(query_param) diff --git a/swift/common/request_helpers.py b/swift/common/request_helpers.py index c014bd8df9..60a862aa6c 100644 --- a/swift/common/request_helpers.py +++ b/swift/common/request_helpers.py @@ -21,10 +21,8 @@ """ import itertools -import sys import time -import six from swift.common.header_key_dict import HeaderKeyDict from swift.common.constraints import AUTO_CREATE_ACCOUNT_PREFIX, \ @@ -51,15 +49,6 @@ MISPLACED_OBJECTS_ACCOUNT = '.misplaced_objects' -if six.PY2: - import cgi - - def html_escape(s, quote=True): - return cgi.escape(s, quote=quote) -else: - from html import escape as html_escape # noqa: F401 - - def get_param(req, name, default=None): """ Get a parameter from an HTTP request ensuring proper handling UTF-8 @@ -68,30 +57,20 @@ def get_param(req, name, default=None): :param req: request object :param name: parameter name :param default: result to return if the parameter is not found - :returns: HTTP request parameter value, as a native string - (in py2, as UTF-8 encoded str, not unicode object) + :returns: HTTP request parameter value, as a native (not WSGI) string :raises HTTPBadRequest: if param not valid UTF-8 byte sequence """ value = req.params.get(name, default) - if six.PY2: - if value and not isinstance(value, six.text_type): - try: - value.decode('utf8') # Ensure UTF8ness - except UnicodeDecodeError: - raise HTTPBadRequest( - request=req, content_type='text/plain', - body='"%s" parameter not valid UTF-8' % name) - else: - if value: - # req.params is a dict of WSGI strings, so encoding will succeed - value = value.encode('latin1') - try: - # Ensure UTF8ness since we're at it - value = value.decode('utf8') - except UnicodeDecodeError: - raise HTTPBadRequest( - request=req, content_type='text/plain', - body='"%s" parameter not valid UTF-8' % name) + if value: + # req.params is a dict of WSGI strings, so encoding will succeed + value = value.encode('latin1') + try: + # Ensure UTF8ness since we're at it + value = value.decode('utf8') + except UnicodeDecodeError: + raise HTTPBadRequest( + request=req, content_type='text/plain', + body='"%s" parameter not valid UTF-8' % name) return value @@ -606,11 +585,10 @@ def _coalesce_requests(self): pending_etag = seg_etag pending_size = seg_size - except ListingIterError: - e_type, e_value, e_traceback = sys.exc_info() + except ListingIterError as e: if pending_req: yield pending_req, pending_etag, pending_size - six.reraise(e_type, e_value, e_traceback) + raise e if pending_req: yield pending_req, pending_etag, pending_size @@ -629,9 +607,7 @@ def _requests_to_bytes_iter(self): seg_resp = seg_req.get_response(self.app) if not is_success(seg_resp.status_int): # Error body should be short - body = seg_resp.body - if not six.PY2: - body = body.decode('utf8') + body = seg_resp.body.decode('utf8') msg = 'While processing manifest %s, got %d (%s) ' \ 'while retrieving %s' % ( self.name, seg_resp.status_int, diff --git a/swift/common/ring/builder.py b/swift/common/ring/builder.py index 91845070ef..77b00bcd97 100644 --- a/swift/common/ring/builder.py +++ b/swift/common/ring/builder.py @@ -22,14 +22,12 @@ import random import uuid -import six.moves.cPickle as pickle +import pickle # nosec: B403 from copy import deepcopy from contextlib import contextmanager from array import array from collections import defaultdict -import six -from six.moves import range from time import time from swift.common import exceptions @@ -646,8 +644,7 @@ def _build_dispersion_graph(self, old_replica2part2dev=None): dispersion_graph = {} # go over all the devices holding each replica part by part - for part_id, dev_ids in enumerate( - six.moves.zip(*self._replica2part2dev)): + for part_id, dev_ids in enumerate(zip(*self._replica2part2dev)): # count the number of replicas of this part for each tier of each # device, some devices may have overlapping tiers! replicas_at_tier = defaultdict(int) @@ -1741,7 +1738,7 @@ def load(cls, builder_file, open=open, **kwargs): else: with fp: try: - builder = pickle.load(fp) + builder = pickle.load(fp) # nosec: B301 except Exception: # raise error during unpickling as UnPicklingError raise exceptions.UnPicklingError( diff --git a/swift/common/ring/ring.py b/swift/common/ring/ring.py index c3f726df61..7ef9d11446 100644 --- a/swift/common/ring/ring.py +++ b/swift/common/ring/ring.py @@ -16,7 +16,7 @@ import array import contextlib -import six.moves.cPickle as pickle +import pickle # nosec: B403 import json from collections import defaultdict from gzip import GzipFile @@ -29,9 +29,6 @@ import sys import zlib -import six -from six.moves import range - from swift.common.exceptions import RingLoadError from swift.common.utils import hash_path, validate_configuration, md5 from swift.common.ring.utils import tiers_for_dev @@ -206,7 +203,7 @@ def load(cls, filename, metadata_only=False): else: # Assume old-style pickled ring gz_file.seek(0) - ring_data = pickle.load(gz_file) + ring_data = pickle.load(gz_file) # nosec: B301 if hasattr(ring_data, 'devs'): # pickled RingData; make sure we've got region/replication info @@ -244,12 +241,7 @@ def serialize_v1(self, file_obj): file_obj.write(struct.pack('!I', json_len)) file_obj.write(json_text) for part2dev_id in ring['replica2part2dev_id']: - if six.PY2: - # Can't just use tofile() because a GzipFile apparently - # doesn't count as an 'open file' - file_obj.write(part2dev_id.tostring()) - else: - part2dev_id.tofile(file_obj) + part2dev_id.tofile(file_obj) def save(self, filename, mtime=1300507380.0): """ diff --git a/swift/common/splice.py b/swift/common/splice.py index a365a93bbd..9c2384e25f 100644 --- a/swift/common/splice.py +++ b/swift/common/splice.py @@ -18,8 +18,6 @@ ''' import os -import operator -import six import ctypes import ctypes.util @@ -82,8 +80,10 @@ def __call__(self, fd_in, fd_out, len_, flags): if not self.available: raise EnvironmentError('tee not available') - if not isinstance(flags, six.integer_types): - c_flags = six.moves.reduce(operator.or_, flags, 0) + if not isinstance(flags, int): + c_flags = 0 + for flag in flags: + c_flags |= flag else: c_flags = flags @@ -174,8 +174,10 @@ def __call__(self, fd_in, off_in, fd_out, off_out, len_, flags): if not self.available: raise EnvironmentError('splice not available') - if not isinstance(flags, six.integer_types): - c_flags = six.moves.reduce(operator.or_, flags, 0) + if not isinstance(flags, int): + c_flags = 0 + for flag in flags: + c_flags |= flag else: c_flags = flags diff --git a/swift/common/statsd_client.py b/swift/common/statsd_client.py index 825bede383..2576ec8700 100644 --- a/swift/common/statsd_client.py +++ b/swift/common/statsd_client.py @@ -21,7 +21,6 @@ from random import random from eventlet.green import socket -import six def get_statsd_client(conf=None, tail_prefix='', logger=None): @@ -164,8 +163,7 @@ def _send(self, m_name, m_value, m_type, sample_rate): parts.append('@%s' % (sample_rate,)) else: return - if six.PY3: - parts = [part.encode('utf-8') for part in parts] + parts = [part.encode('utf-8') for part in parts] # Ideally, we'd cache a sending socket in self, but that # results in a socket getting shared by multiple green threads. with closing(self._open_socket()) as sock: diff --git a/swift/common/storage_policy.py b/swift/common/storage_policy.py index dcad56b9c9..a1bcfc4130 100644 --- a/swift/common/storage_policy.py +++ b/swift/common/storage_policy.py @@ -17,8 +17,7 @@ import string import sys import textwrap -import six -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from swift.common.utils import ( config_true_value, quorum_size, whataremyips, list_from_csv, config_positive_int_value, get_zero_indexed_base_string, load_pkg_resource) @@ -80,8 +79,10 @@ def all_bind_ports_for_node(self): # the first one we notice. # Return the requested set of ports from our (now-freshened) cache - return six.moves.reduce(set.union, - self.portsets_by_ring_path.values(), set()) + res = set() + for ports in self.portsets_by_ring_path.values(): + res.update(ports) + return res class PolicyError(ValueError): @@ -975,12 +976,9 @@ def reload_storage_policies(): Reload POLICIES from ``swift.conf``. """ global _POLICIES - if six.PY2: - policy_conf = ConfigParser() - else: - # Python 3.2 disallows section or option duplicates by default - # strict=False allows us to preserve the older behavior - policy_conf = ConfigParser(strict=False) + # Python disallows section or option duplicates by default + # strict=False allows them, which Swift has always done + policy_conf = ConfigParser(strict=False) policy_conf.read(utils.SWIFT_CONF_FILE) try: _POLICIES = parse_storage_policies(policy_conf) diff --git a/swift/common/swob.py b/swift/common/swob.py index 60ccb332be..43d35959c8 100644 --- a/swift/common/swob.py +++ b/swift/common/swob.py @@ -36,10 +36,7 @@ """ from collections import defaultdict -try: - from collections.abc import MutableMapping -except ImportError: - from collections import MutableMapping # py2 +from collections.abc import MutableMapping import time from functools import partial from datetime import datetime @@ -49,9 +46,8 @@ import functools from io import BytesIO -import six -from six import StringIO -from six.moves import urllib +from io import StringIO +import urllib from swift.common.header_key_dict import HeaderKeyDict from swift.common.utils import UTC, reiterate, split_path, Timestamp, pairs, \ @@ -157,7 +153,7 @@ def getter(self): return None def setter(self, value): - if isinstance(value, (float,) + six.integer_types): + if isinstance(value, (float, int)): self.headers[header] = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(value)) elif isinstance(value, datetime): @@ -251,9 +247,7 @@ def __getitem__(self, key): def __setitem__(self, key, value): if value is None: self.environ.pop(header_to_environ_key(key), None) - elif six.PY2 and isinstance(value, six.text_type): - self.environ[header_to_environ_key(key)] = value.encode('utf-8') - elif not six.PY2 and isinstance(value, six.binary_type): + elif isinstance(value, bytes): self.environ[header_to_environ_key(key)] = value.decode('latin1') else: self.environ[header_to_environ_key(key)] = str(value) @@ -279,70 +273,42 @@ def keys(self): def wsgi_to_bytes(wsgi_str): if wsgi_str is None: return None - if six.PY2: - return wsgi_str return wsgi_str.encode('latin1') def wsgi_to_str(wsgi_str): if wsgi_str is None: return None - if six.PY2: - return wsgi_str return wsgi_to_bytes(wsgi_str).decode('utf8', errors='surrogateescape') def bytes_to_wsgi(byte_str): - if six.PY2: - return byte_str return byte_str.decode('latin1') def str_to_wsgi(native_str): - if six.PY2: - return native_str return bytes_to_wsgi(native_str.encode('utf8', errors='surrogateescape')) def wsgi_quote(wsgi_str, safe='/'): - if six.PY2: - if not isinstance(wsgi_str, bytes): - raise TypeError('Expected a WSGI string; got %r' % wsgi_str) - return urllib.parse.quote(wsgi_str, safe=safe) - if not isinstance(wsgi_str, str) or any(ord(x) > 255 for x in wsgi_str): raise TypeError('Expected a WSGI string; got %r' % wsgi_str) return urllib.parse.quote(wsgi_str, safe=safe, encoding='latin-1') def wsgi_unquote(wsgi_str): - if six.PY2: - if not isinstance(wsgi_str, bytes): - raise TypeError('Expected a WSGI string; got %r' % wsgi_str) - return urllib.parse.unquote(wsgi_str) - if not isinstance(wsgi_str, str) or any(ord(x) > 255 for x in wsgi_str): raise TypeError('Expected a WSGI string; got %r' % wsgi_str) return urllib.parse.unquote(wsgi_str, encoding='latin-1') def wsgi_quote_plus(wsgi_str): - if six.PY2: - if not isinstance(wsgi_str, bytes): - raise TypeError('Expected a WSGI string; got %r' % wsgi_str) - return urllib.parse.quote_plus(wsgi_str) - if not isinstance(wsgi_str, str) or any(ord(x) > 255 for x in wsgi_str): raise TypeError('Expected a WSGI string; got %r' % wsgi_str) return urllib.parse.quote_plus(wsgi_str, encoding='latin-1') def wsgi_unquote_plus(wsgi_str): - if six.PY2: - if not isinstance(wsgi_str, bytes): - raise TypeError('Expected a WSGI string; got %r' % wsgi_str) - return urllib.parse.unquote_plus(wsgi_str) - if not isinstance(wsgi_str, str) or any(ord(x) > 255 for x in wsgi_str): raise TypeError('Expected a WSGI string; got %r' % wsgi_str) return urllib.parse.unquote_plus(wsgi_str, encoding='latin-1') @@ -360,7 +326,7 @@ def getter(self): return '%s %s' % (self.status_int, self.title) def setter(self, value): - if isinstance(value, six.integer_types): + if isinstance(value, int): self.status_int = value self.explanation = self.title = RESPONSE_REASONS[value][0] else: @@ -388,9 +354,9 @@ def getter(self): return self._body def setter(self, value): - if isinstance(value, six.text_type): + if isinstance(value, str): raise TypeError('WSGI responses must be bytes') - if isinstance(value, six.binary_type): + if isinstance(value, bytes): self.content_length = len(value) close_if_possible(self._app_iter) self._app_iter = None @@ -805,19 +771,13 @@ def getter(self): return self.environ.get(environ_field, None) def setter(self, value): - if six.PY2: - if isinstance(value, six.text_type): - self.environ[environ_field] = value.encode('utf-8') - else: - self.environ[environ_field] = value - else: - if is_wsgi_string_field: - # Check that input is valid before setting - if isinstance(value, str): - value.encode('latin1').decode('utf-8') - if isinstance(value, bytes): - value = value.decode('latin1') - self.environ[environ_field] = value + if is_wsgi_string_field: + # Check that input is valid before setting + if isinstance(value, str): + value.encode('latin1').decode('utf-8') + if isinstance(value, bytes): + value = value.decode('latin1') + self.environ[environ_field] = value return property(getter, setter, doc=("Get and set the %s property " "in the WSGI environment") % environ_field) @@ -835,7 +795,7 @@ def getter(self): return body def setter(self, value): - if not isinstance(value, six.binary_type): + if not isinstance(value, bytes): value = value.encode('utf8') self.environ['wsgi.input'] = WsgiBytesIO(value) self.environ['CONTENT_LENGTH'] = str(len(value)) @@ -932,15 +892,11 @@ def blank(cls, path, environ=None, headers=None, body=None, **kwargs): """ headers = headers or {} environ = environ or {} - if six.PY2: - if isinstance(path, six.text_type): - path = path.encode('utf-8') + if isinstance(path, bytes): + path = path.decode('latin1') else: - if isinstance(path, six.binary_type): - path = path.decode('latin1') - else: - # Check that the input is valid - path.encode('latin1') + # Check that the input is valid + path.encode('latin1') parsed_path = urllib.parse.urlparse(path) server_name = 'localhost' @@ -970,7 +926,7 @@ def blank(cls, path, environ=None, headers=None, body=None, **kwargs): } env.update(environ) if body is not None: - if not isinstance(body, six.binary_type): + if not isinstance(body, bytes): body = body.encode('utf8') env['wsgi.input'] = WsgiBytesIO(body) env['CONTENT_LENGTH'] = str(len(body)) @@ -996,13 +952,9 @@ def params(self): "Provides QUERY_STRING parameters as a dictionary" if self._params_cache is None: if 'QUERY_STRING' in self.environ: - if six.PY2: - self._params_cache = dict(urllib.parse.parse_qsl( - self.environ['QUERY_STRING'], True)) - else: - self._params_cache = dict(urllib.parse.parse_qsl( - self.environ['QUERY_STRING'], - keep_blank_values=True, encoding='latin-1')) + self._params_cache = dict(urllib.parse.parse_qsl( + self.environ['QUERY_STRING'], + keep_blank_values=True, encoding='latin-1')) else: self._params_cache = {} return self._params_cache @@ -1011,11 +963,8 @@ def params(self): @params.setter def params(self, param_pairs): self._params_cache = None - if six.PY2: - self.query_string = urllib.parse.urlencode(param_pairs) - else: - self.query_string = urllib.parse.urlencode(param_pairs, - encoding='latin-1') + self.query_string = urllib.parse.urlencode(param_pairs, + encoding='latin-1') def ensure_x_timestamp(self): """ @@ -1265,7 +1214,7 @@ def __init__(self, body=None, status=200, headers=None, app_iter=None, self.request = request self._app_iter = None # Allow error messages to come as natural strings on py3. - if isinstance(body, six.text_type): + if isinstance(body, str): body = body.encode('utf8') self.body = body self.app_iter = app_iter diff --git a/swift/common/utils/__init__.py b/swift/common/utils/__init__.py index c5fdd6fd8b..67cd6dbd7a 100644 --- a/swift/common/utils/__init__.py +++ b/swift/common/utils/__init__.py @@ -64,15 +64,12 @@ from eventlet.green import socket import eventlet.hubs import eventlet.queue -import six -from six.moves import cPickle as pickle -from six.moves.configparser import (ConfigParser, NoSectionError, - NoOptionError) -from six.moves import range -from six.moves.urllib.parse import unquote -from six.moves.urllib.parse import urlparse -from six.moves import UserList +import pickle # nosec: B403 +from configparser import (ConfigParser, NoSectionError, + NoOptionError) +from urllib.parse import unquote, urlparse +from collections import UserList import swift.common.exceptions from swift.common.http import is_server_error @@ -373,26 +370,18 @@ def validate_hash_conf(): if not HASH_PATH_SUFFIX and not HASH_PATH_PREFIX: hash_conf = ConfigParser() - if six.PY3: - # Use Latin1 to accept arbitrary bytes in the hash prefix/suffix - with open(SWIFT_CONF_FILE, encoding='latin1') as swift_conf_file: - hash_conf.read_file(swift_conf_file) - else: - with open(SWIFT_CONF_FILE) as swift_conf_file: - hash_conf.readfp(swift_conf_file) + # Use Latin1 to accept arbitrary bytes in the hash prefix/suffix + with open(SWIFT_CONF_FILE, encoding='latin1') as swift_conf_file: + hash_conf.read_file(swift_conf_file) try: - HASH_PATH_SUFFIX = hash_conf.get('swift-hash', - 'swift_hash_path_suffix') - if six.PY3: - HASH_PATH_SUFFIX = HASH_PATH_SUFFIX.encode('latin1') + HASH_PATH_SUFFIX = hash_conf.get( + 'swift-hash', 'swift_hash_path_suffix').encode('latin1') except (NoSectionError, NoOptionError): pass try: - HASH_PATH_PREFIX = hash_conf.get('swift-hash', - 'swift_hash_path_prefix') - if six.PY3: - HASH_PATH_PREFIX = HASH_PATH_PREFIX.encode('latin1') + HASH_PATH_PREFIX = hash_conf.get( + 'swift-hash', 'swift_hash_path_prefix').encode('latin1') except (NoSectionError, NoOptionError): pass @@ -498,7 +487,7 @@ def __init__(self, iterable): def __iter__(self): return self - def next(self): + def __next__(self): """ next(x) -> the next value, or raise StopIteration """ @@ -510,7 +499,6 @@ def next(self): return rv else: return next(self.iterator) - __next__ = next def read(self, size=-1): """ @@ -949,7 +937,7 @@ def __init__(self, iterable, elements_per_second, limit_after=0, def __iter__(self): return self - def next(self): + def __next__(self): next_value = next(self.iterator) if self.ratelimit_if(next_value): @@ -958,7 +946,6 @@ def next(self): else: self.rate_limiter.wait() return next_value - __next__ = next class GreenthreadSafeIterator(object): @@ -980,10 +967,9 @@ def __init__(self, unsafe_iterable): def __iter__(self): return self - def next(self): + def __next__(self): with self.semaphore: return next(self.unsafe_iter) - __next__ = next def timing_stats(**dec_kwargs): @@ -1238,13 +1224,13 @@ def hash_path(account, container=None, object=None, raw_digest=False): """ if object and not container: raise ValueError('container is required if object is provided') - paths = [account if isinstance(account, six.binary_type) + paths = [account if isinstance(account, bytes) else account.encode('utf8')] if container: - paths.append(container if isinstance(container, six.binary_type) + paths.append(container if isinstance(container, bytes) else container.encode('utf8')) if object: - paths.append(object if isinstance(object, six.binary_type) + paths.append(object if isinstance(object, bytes) else object.encode('utf8')) if raw_digest: return md5(HASH_PATH_PREFIX + b'/' + b'/'.join(paths) @@ -2006,7 +1992,7 @@ def _wait(self, timeout, first_n=None): def __iter__(self): return self - def next(self): + def __next__(self): while True: try: rv = self._responses.get_nowait() @@ -2018,7 +2004,6 @@ def next(self): if rv is DEAD: continue return rv - __next__ = next class StreamingPile(GreenAsyncPile): @@ -2460,8 +2445,6 @@ def __next__(self): self.close() raise - next = __next__ # py2 - def close(self): if not self.closed: for wrapped in self.closeables: @@ -3085,18 +3068,14 @@ def parse_mime_headers(doc_file): while True: line = doc_file.readline() done = line in (b'\r\n', b'\n', b'') - if six.PY3: - try: - line = line.decode('utf-8') - except UnicodeDecodeError: - line = line.decode('latin1') + try: + line = line.decode('utf-8') + except UnicodeDecodeError: + line = line.decode('latin1') headers.append(line) if done: break - if six.PY3: - header_string = ''.join(headers) - else: - header_string = b''.join(headers) + header_string = ''.join(headers) headers = email.parser.Parser().parsestr(header_string) return HeaderKeyDict(headers) @@ -3111,7 +3090,7 @@ def mime_to_document_iters(input_file, boundary, read_chunk_size=4096): (e.g. "divider", not "--divider") :param read_chunk_size: size of strings read via input_file.read() """ - if six.PY3 and isinstance(boundary, str): + if isinstance(boundary, str): # Since the boundary is in client-supplied headers, it can contain # garbage that trips us and we don't like client-induced 500. boundary = boundary.encode('latin-1', errors='replace') @@ -3351,8 +3330,6 @@ def __repr__(self): def __bool__(self): return False - __nonzero__ = __bool__ - @functools.total_ordering class Namespace(object): @@ -3451,9 +3428,7 @@ def __contains__(self, item): @classmethod def _encode(cls, value): - if six.PY2 and isinstance(value, six.text_type): - return value.encode('utf-8') - if six.PY3 and isinstance(value, six.binary_type): + if isinstance(value, bytes): # This should never fail -- the value should always be coming from # valid swift paths, which means UTF-8 return value.decode('utf-8') @@ -3462,8 +3437,8 @@ def _encode(cls, value): def _encode_bound(self, bound): if isinstance(bound, NamespaceOuterBound): return bound - if not (isinstance(bound, six.text_type) or - isinstance(bound, six.binary_type)): + if not (isinstance(bound, str) or + isinstance(bound, bytes)): raise TypeError('must be a string type') return self._encode(bound) @@ -4364,7 +4339,8 @@ class ShardRangeList(UserList): """ def __getitem__(self, index): - # workaround for py3 - not needed for py2.7,py3.8 + # workaround for py36,py37 - not needed for py3.8+ + # see https://github.com/python/cpython/commit/b1c3167c result = self.data[index] return ShardRangeList(result) if type(result) is list else result @@ -4593,7 +4569,7 @@ def strict_b64decode(value, allow_line_breaks=False): value = value.decode('ascii') except UnicodeDecodeError: raise ValueError - if not isinstance(value, six.text_type): + if not isinstance(value, str): raise ValueError # b64decode will silently discard bad characters, but we want to # treat them as an error @@ -4604,10 +4580,7 @@ def strict_b64decode(value, allow_line_breaks=False): strip_chars += '\r\n' if any(c not in valid_chars for c in value.strip(strip_chars)): raise ValueError - try: - return base64.b64decode(value) - except (TypeError, binascii.Error): # (py2 error, py3 error) - raise ValueError + return base64.b64decode(value) def cap_length(value, max_length): diff --git a/swift/common/utils/base.py b/swift/common/utils/base.py index 7e94eab3e7..159dac0c01 100644 --- a/swift/common/utils/base.py +++ b/swift/common/utils/base.py @@ -23,8 +23,7 @@ import codecs import hashlib -import six -from six.moves.urllib.parse import quote as _quote +from urllib.parse import quote as _quote try: @@ -50,10 +49,9 @@ def md5(string=b'', usedforsecurity=True): utf8_decoder = codecs.getdecoder('utf-8') utf8_encoder = codecs.getencoder('utf-8') -if not six.PY2: - # Apparently under py3 we need to go to utf-16 to collapse surrogates? - utf16_decoder = codecs.getdecoder('utf-16') - utf16_encoder = codecs.getencoder('utf-16') +# Apparently under py3 we need to go to utf-16 to collapse surrogates? +utf16_decoder = codecs.getdecoder('utf-16') +utf16_encoder = codecs.getencoder('utf-16') def get_valid_utf8_str(str_or_unicode): @@ -62,20 +60,15 @@ def get_valid_utf8_str(str_or_unicode): :param str_or_unicode: a string or an unicode which can be invalid utf-8 """ - if six.PY2: - if isinstance(str_or_unicode, six.text_type): - (str_or_unicode, _len) = utf8_encoder(str_or_unicode, 'replace') - (valid_unicode_str, _len) = utf8_decoder(str_or_unicode, 'replace') - else: - if isinstance(str_or_unicode, six.binary_type): - try: - (str_or_unicode, _len) = utf8_decoder(str_or_unicode, - 'surrogatepass') - except UnicodeDecodeError: - (str_or_unicode, _len) = utf8_decoder(str_or_unicode, - 'replace') - (str_or_unicode, _len) = utf16_encoder(str_or_unicode, 'surrogatepass') - (valid_unicode_str, _len) = utf16_decoder(str_or_unicode, 'replace') + if isinstance(str_or_unicode, bytes): + try: + (str_or_unicode, _len) = utf8_decoder(str_or_unicode, + 'surrogatepass') + except UnicodeDecodeError: + (str_or_unicode, _len) = utf8_decoder(str_or_unicode, + 'replace') + (str_or_unicode, _len) = utf16_encoder(str_or_unicode, 'surrogatepass') + (valid_unicode_str, _len) = utf16_decoder(str_or_unicode, 'replace') return valid_unicode_str.encode('utf-8') @@ -84,7 +77,7 @@ def quote(value, safe='/'): Patched version of urllib.quote that encodes utf-8 strings before quoting """ quoted = _quote(get_valid_utf8_str(value), safe) - if isinstance(value, six.binary_type): + if isinstance(value, bytes): quoted = quoted.encode('utf-8') return quoted diff --git a/swift/common/utils/config.py b/swift/common/utils/config.py index 5f4fe8a817..f56d89f0fd 100644 --- a/swift/common/utils/config.py +++ b/swift/common/utils/config.py @@ -13,12 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six import os import operator import re -from six.moves import configparser -from six.moves.configparser import (ConfigParser, RawConfigParser) +import configparser +from configparser import ConfigParser, RawConfigParser # Used when reading config values TRUE_VALUES = {'true', '1', 'yes', 'on', 't', 'y'} @@ -30,7 +29,7 @@ def config_true_value(value): Returns False otherwise. """ return value is True or \ - (isinstance(value, six.string_types) and value.lower() in TRUE_VALUES) + (isinstance(value, str) and value.lower() in TRUE_VALUES) def _non_negative_number(value, expected_type_f=float, @@ -105,7 +104,7 @@ def config_auto_int_value(value, default): Returns value as an int or raises ValueError otherwise. """ if value is None or \ - (isinstance(value, six.string_types) and value.lower() == 'auto'): + (isinstance(value, str) and value.lower() == 'auto'): return default try: value = int(value) @@ -338,15 +337,12 @@ def read_conf_dir(parser, conf_dir): return parser.read(sorted(conf_files)) -if six.PY2: - NicerInterpolation = None # just don't cause ImportErrors over in wsgi.py -else: - class NicerInterpolation(configparser.BasicInterpolation): - def before_get(self, parser, section, option, value, defaults): - if '%(' not in value: - return value - return super(NicerInterpolation, self).before_get( - parser, section, option, value, defaults) +class NicerInterpolation(configparser.BasicInterpolation): + def before_get(self, parser, section, option, value, defaults): + if '%(' not in value: + return value + return super(NicerInterpolation, self).before_get( + parser, section, option, value, defaults) def readconf(conf_path, section_name=None, log_name=None, defaults=None, @@ -370,27 +366,21 @@ def readconf(conf_path, section_name=None, log_name=None, defaults=None, if raw: c = RawConfigParser(defaults) else: - if six.PY2: - c = ConfigParser(defaults) - else: - # In general, we haven't really thought much about interpolation - # in configs. Python's default ConfigParser has always supported - # it, though, so *we* got it "for free". Unfortunatley, since we - # "supported" interpolation, we have to assume there are - # deployments in the wild that use it, and try not to break them. - # So, do what we can to mimic the py2 behavior of passing through - # values like "1%" (which we want to support for - # fallocate_reserve). - c = ConfigParser(defaults, interpolation=NicerInterpolation()) + # In general, we haven't really thought much about interpolation + # in configs. Python's default ConfigParser has always supported + # it, though, so *we* got it "for free". Unfortunatley, since we + # "supported" interpolation, we have to assume there are + # deployments in the wild that use it, and try not to break them. + # So, do what we can to mimic the py2 behavior of passing through + # values like "1%" (which we want to support for + # fallocate_reserve). + c = ConfigParser(defaults, interpolation=NicerInterpolation()) c.optionxform = str # Don't lower-case keys if hasattr(conf_path, 'readline'): if hasattr(conf_path, 'seek'): conf_path.seek(0) - if six.PY2: - c.readfp(conf_path) - else: - c.read_file(conf_path) + c.read_file(conf_path) else: if os.path.isdir(conf_path): # read all configs in directory diff --git a/swift/common/utils/logs.py b/swift/common/utils/logs.py index e35dbce7aa..b9833635f9 100644 --- a/swift/common/utils/logs.py +++ b/swift/common/utils/logs.py @@ -27,7 +27,6 @@ import time import fcntl import eventlet -import six import datetime from swift.common.utils.base import md5, quote, split_path @@ -41,11 +40,8 @@ # we do the same here import swift.common.exceptions -if six.PY2: - from eventlet.green import httplib as green_http_client -else: - from eventlet.green.http import client as green_http_client -from six.moves import http_client +from eventlet.green.http import client as green_http_client +import http.client from eventlet.green import threading @@ -350,7 +346,7 @@ def exception(self, msg, *args, **kwargs): _junk, exc, _junk = sys.exc_info() call = self.error emsg = '' - if isinstance(exc, (http_client.BadStatusLine, + if isinstance(exc, (http.client.BadStatusLine, green_http_client.BadStatusLine)): # Use error(); not really exceptional emsg = repr(exc) @@ -503,9 +499,8 @@ def flush(self): def __iter__(self): return self - def next(self): + def __next__(self): raise IOError(errno.EBADF, 'Bad file descriptor') - __next__ = next def read(self, size=-1): raise IOError(errno.EBADF, 'Bad file descriptor') @@ -744,8 +739,7 @@ class StrAnonymizer(str): def __new__(cls, data, method, salt): method = method.lower() - if method not in (hashlib.algorithms if six.PY2 else - hashlib.algorithms_guaranteed): + if method not in hashlib.algorithms_guaranteed: raise ValueError('Unsupported hashing method: %r' % method) s = str.__new__(cls, data or '') s.method = method @@ -762,8 +756,8 @@ def anonymized(self): else: h = getattr(hashlib, self.method)() if self.salt: - h.update(six.b(self.salt)) - h.update(six.b(self)) + h.update(self.salt.encode('latin1')) + h.update(self.encode('latin1')) return '{%s%s}%s' % ('S' if self.salt else '', self.method.upper(), h.hexdigest()) @@ -880,7 +874,7 @@ def get_policy_index(req_headers, res_headers): """ header = 'X-Backend-Storage-Policy-Index' policy_index = res_headers.get(header, req_headers.get(header)) - if isinstance(policy_index, six.binary_type) and not six.PY2: + if isinstance(policy_index, bytes): policy_index = policy_index.decode('ascii') return str(policy_index) if policy_index is not None else None diff --git a/swift/common/utils/timestamp.py b/swift/common/utils/timestamp.py index 374763ce93..660ae26f19 100644 --- a/swift/common/utils/timestamp.py +++ b/swift/common/utils/timestamp.py @@ -21,8 +21,6 @@ import sys import time -import six - NORMAL_FORMAT = "%016.05f" INTERNAL_FORMAT = NORMAL_FORMAT + '_%016x' @@ -90,7 +88,7 @@ def __init__(self, timestamp, offset=0, delta=0, check_bounds=True): """ if isinstance(timestamp, bytes): timestamp = timestamp.decode('ascii') - if isinstance(timestamp, six.string_types): + if isinstance(timestamp, str): base, base_offset = timestamp.partition('_')[::2] self.timestamp = float(base) if '_' in base_offset: @@ -140,11 +138,8 @@ def __float__(self): def __int__(self): return int(self.timestamp) - def __nonzero__(self): - return bool(self.timestamp or self.offset) - def __bool__(self): - return self.__nonzero__() + return bool(self.timestamp or self.offset) @property def normal(self): @@ -176,24 +171,21 @@ def isoformat(self): :return: an isoformat string """ t = float(self.normal) - if six.PY3: - # On Python 3, round manually using ROUND_HALF_EVEN rounding - # method, to use the same rounding method than Python 2. Python 3 - # used a different rounding method, but Python 3.4.4 and 3.5.1 use - # again ROUND_HALF_EVEN as Python 2. - # See https://bugs.python.org/issue23517 - frac, t = math.modf(t) - us = round(frac * 1e6) - if us >= 1000000: - t += 1 - us -= 1000000 - elif us < 0: - t -= 1 - us += 1000000 - dt = datetime.datetime.fromtimestamp(t, UTC) - dt = dt.replace(microsecond=us) - else: - dt = datetime.datetime.fromtimestamp(t, UTC) + # On Python 3, round manually using ROUND_HALF_EVEN rounding + # method, to use the same rounding method than Python 2. Python 3 + # used a different rounding method, but Python 3.4.4 and 3.5.1 use + # again ROUND_HALF_EVEN as Python 2. + # See https://bugs.python.org/issue23517 + frac, t = math.modf(t) + us = round(frac * 1e6) + if us >= 1000000: + t += 1 + us -= 1000000 + elif us < 0: + t -= 1 + us += 1000000 + dt = datetime.datetime.fromtimestamp(t, UTC) + dt = dt.replace(microsecond=us) isoformat = dt.isoformat() # need to drop tzinfo @@ -316,7 +308,7 @@ def decode_timestamps(encoded, explicit=False): # TODO: some tests, e.g. in test_replicator, put float timestamps values # into container db's, hence this defensive check, but in real world # this may never happen. - if not isinstance(encoded, six.string_types): + if not isinstance(encoded, str): ts = Timestamp(encoded) return ts, ts, ts diff --git a/swift/common/wsgi.py b/swift/common/wsgi.py index fa5367c291..34abf26178 100644 --- a/swift/common/wsgi.py +++ b/swift/common/wsgi.py @@ -18,7 +18,6 @@ from __future__ import print_function import errno -import fcntl import os import signal import sys @@ -31,10 +30,7 @@ from eventlet import greenio, GreenPool, sleep, wsgi, listen, Timeout from paste.deploy import loadwsgi from eventlet.green import socket, ssl, os as green_os -from io import BytesIO - -import six -from six import StringIO +from io import BytesIO, StringIO from swift.common import utils, constraints from swift.common.http_protocol import SwiftHttpProtocol, \ @@ -67,8 +63,7 @@ class NamedConfigLoader(loadwsgi.ConfigLoader): """ def get_context(self, object_type, name=None, global_conf=None): - if not six.PY2: - self.parser._interpolation = NicerInterpolation() + self.parser._interpolation = NicerInterpolation() context = super(NamedConfigLoader, self).get_context( object_type, name=name, global_conf=global_conf) context.name = name @@ -128,10 +123,7 @@ def __init__(self, config_string): self.parser.optionxform = str # Don't lower-case keys # Defaults don't need interpolation (crazy PasteDeploy...) self.parser.defaults = lambda: dict(self.parser._defaults, **defaults) - if six.PY2: - self.parser.readfp(self.contents) - else: - self.parser.read_file(self.contents) + self.parser.read_file(self.contents) def readline(self, *args, **kwargs): return self.contents.readline(*args, **kwargs) @@ -198,10 +190,7 @@ def get_socket(conf): sock = listen(bind_addr, backlog=int(conf.get('backlog', 4096)), family=address_family) if 'cert_file' in conf: - if six.PY2: - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - else: - context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.verify_mode = ssl.CERT_NONE context.load_cert_chain(conf['cert_file'], conf['key_file']) warn_ssl = True @@ -513,13 +502,10 @@ def set_close_on_exec_on_listen_sockets(self): """ for sock in self.iter_sockets(): - if six.PY2: - fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) - else: - # Python 3.4 and later default to sockets having close-on-exec - # set (what PEP 0446 calls "non-inheritable"). This new method - # on socket objects is provided to toggle it. - sock.set_inheritable(False) + # Python 3.4 and later default to sockets having close-on-exec + # set (what PEP 0446 calls "non-inheritable"). This new method + # on socket objects is provided to toggle it. + sock.set_inheritable(False) def signal_ready(self): """ diff --git a/swift/container/backend.py b/swift/container/backend.py index 8b3533c2df..da0632fb24 100644 --- a/swift/container/backend.py +++ b/swift/container/backend.py @@ -20,9 +20,7 @@ import os from uuid import uuid4 -import six -from six.moves import range -from six.moves.urllib.parse import unquote +from urllib.parse import unquote import sqlite3 from eventlet import tpool @@ -33,7 +31,7 @@ ShardRange, renamer, MD5_OF_EMPTY_STRING, mkdirs, get_db_files, \ parse_db_filename, make_db_file_path, split_path, RESERVED_BYTE, \ ShardRangeList, Namespace -from swift.common.db import DatabaseBroker, utf8encode, BROKER_TIMEOUT, \ +from swift.common.db import DatabaseBroker, BROKER_TIMEOUT, \ zero_like, DatabaseAlreadyExists, SQLITE_ARG_LIMIT DATADIR = 'containers' @@ -1138,9 +1136,6 @@ def list_objects_iter(self, limit, marker, end_marker, prefix, delimiter, if transform_func is None: transform_func = self._transform_record delim_force_gte = False - if six.PY2: - (marker, end_marker, prefix, delimiter, path) = utf8encode( - marker, end_marker, prefix, delimiter, path) self._commit_puts_stale_ok() if reverse: # Reverse the markers if we are reversing the listing. @@ -1335,9 +1330,7 @@ def merge_items(self, item_list, source=None): :param source: if defined, update incoming_sync with the source """ for item in item_list: - if six.PY2 and isinstance(item['name'], six.text_type): - item['name'] = item['name'].encode('utf-8') - elif not six.PY2 and isinstance(item['name'], six.binary_type): + if isinstance(item['name'], bytes): item['name'] = item['name'].decode('utf-8') def _really_really_merge_items(conn): @@ -1433,9 +1426,7 @@ def merge_shard_ranges(self, shard_ranges): if isinstance(item, ShardRange): item = dict(item) for col in ('name', 'lower', 'upper'): - if six.PY2 and isinstance(item[col], six.text_type): - item[col] = item[col].encode('utf-8') - elif not six.PY2 and isinstance(item[col], six.binary_type): + if isinstance(item[col], bytes): item[col] = item[col].decode('utf-8') item_list.append(item) diff --git a/swift/container/reconciler.py b/swift/container/reconciler.py index ee030ee409..75a25d9e74 100644 --- a/swift/container/reconciler.py +++ b/swift/container/reconciler.py @@ -19,7 +19,6 @@ import logging from eventlet import GreenPile, GreenPool, Timeout -import six from swift.common import constraints from swift.common.daemon import Daemon, run_daemon @@ -272,11 +271,7 @@ def parse_raw_obj(obj_info): :returns: a queue entry dict with the keys: q_policy_index, account, container, obj, q_op, q_ts, q_record, and path """ - if six.PY2: - raw_obj_name = obj_info['name'].encode('utf-8') - else: - raw_obj_name = obj_info['name'] - + raw_obj_name = obj_info['name'] policy_index, obj_name = raw_obj_name.split(':', 1) q_policy_index = int(policy_index) account, container, obj = split_path(obj_name, 3, 3, rest_with_last=True) @@ -758,9 +753,6 @@ def _iter_containers(self): # reversed order since we expect older containers to be empty for c in reversed(one_page): container = c['name'] - if six.PY2: - # encoding here is defensive - container = container.encode('utf8') if container == current_container: continue # we've already hit this one this pass yield container diff --git a/swift/container/server.py b/swift/container/server.py index e8005e1fd1..2c1ed749c2 100644 --- a/swift/container/server.py +++ b/swift/container/server.py @@ -21,8 +21,7 @@ from eventlet import Timeout -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote import swift.common.db from swift.container.sync_store import ContainerSyncStore @@ -237,10 +236,7 @@ def account_update(self, req, account, container, broker): return HTTPBadRequest(req=req) if account_partition: - # zip is lazy on py3, but we need a list, so force evaluation. - # On py2 it's an extra list copy, but the list is so small - # (one element per replica in account ring, usually 3) that it - # doesn't matter. + # zip is lazy, but we need a list, so force evaluation. updates = list(zip(account_hosts, account_devices)) else: updates = [] @@ -644,11 +640,10 @@ def update_object_record(self, record): """ # record is object info (name, created, size, content_type, etag) = record[:5] - name_ = name.decode('utf8') if six.PY2 else name if content_type is None: - return {'subdir': name_} + return {'subdir': name} response = { - 'bytes': size, 'hash': etag, 'name': name_, + 'bytes': size, 'hash': etag, 'name': name, 'content_type': content_type} override_bytes_from_content_type(response, logger=self.logger) response['last_modified'] = Timestamp(created).isoformat diff --git a/swift/container/sharder.py b/swift/container/sharder.py index 4ee6b914ea..f08673c3e1 100644 --- a/swift/container/sharder.py +++ b/swift/container/sharder.py @@ -24,8 +24,7 @@ from random import random import os -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote from eventlet import Timeout from contextlib import contextmanager @@ -657,18 +656,13 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join( '%s=%r' % prop for prop in self)) - def _encode(cls, value): - if value is not None and six.PY2 and isinstance(value, six.text_type): - return value.encode('utf-8') - return value - @property def cursor(self): return self._cursor @cursor.setter def cursor(self, value): - self._cursor = self._encode(value) + self._cursor = value @property def marker(self): diff --git a/swift/container/sync.py b/swift/container/sync.py index 124d7ba4e3..28bda61240 100644 --- a/swift/container/sync.py +++ b/swift/container/sync.py @@ -22,7 +22,7 @@ from struct import unpack_from from eventlet import sleep, Timeout -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse import swift.common.db from swift.common.db import DatabaseConnectionError diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index 723212a1d8..b581f43fae 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -30,7 +30,7 @@ are also not considered part of the backend API. """ -import six.moves.cPickle as pickle +import pickle # nosec: B403 import binascii import copy import errno @@ -52,7 +52,6 @@ from eventlet import Timeout, tpool from eventlet.hubs import trampoline -import six from pyeclib.ec_iface import ECDriverError, ECInvalidFragmentMetadata, \ ECBadFragmentChecksum, ECInvalidParameter @@ -154,16 +153,10 @@ def _encode_metadata(metadata): :param metadata: a dict """ - if six.PY2: - def encode_str(item): - if isinstance(item, six.text_type): - return item.encode('utf8') - return item - else: - def encode_str(item): - if isinstance(item, six.text_type): - return item.encode('utf8', 'surrogateescape') - return item + def encode_str(item): + if isinstance(item, str): + return item.encode('utf8', 'surrogateescape') + return item return dict(((encode_str(k), encode_str(v)) for k, v in metadata.items())) @@ -175,27 +168,16 @@ def _decode_metadata(metadata, metadata_written_by_py3): :param metadata: a dict :param metadata_written_by_py3: """ - if six.PY2: - def to_str(item, is_name=False): - # For years, py2 and py3 handled non-ascii metadata differently; - # see https://bugs.launchpad.net/swift/+bug/2012531 - if metadata_written_by_py3 and not is_name: - # do our best to read new-style data replicated from a py3 node - item = item.decode('utf8').encode('latin1') - if isinstance(item, six.text_type): - return item.encode('utf8') - return item - else: - def to_str(item, is_name=False): - # For years, py2 and py3 handled non-ascii metadata differently; - # see https://bugs.launchpad.net/swift/+bug/2012531 - if not metadata_written_by_py3 and isinstance(item, bytes) \ - and not is_name: - # do our best to read old py2 data - item = item.decode('latin1') - if isinstance(item, six.binary_type): - return item.decode('utf8', 'surrogateescape') - return item + def to_str(item, is_name=False): + # For years, py2 and py3 handled non-ascii metadata differently; + # see https://bugs.launchpad.net/swift/+bug/2012531 + if not metadata_written_by_py3 and isinstance(item, bytes) \ + and not is_name: + # do our best to read old py2 data + item = item.decode('latin1') + if isinstance(item, bytes): + return item.decode('utf8', 'surrogateescape') + return item return {to_str(k): to_str(v, k == b'name') for k, v in metadata.items()} @@ -255,10 +237,7 @@ def read_metadata(fd, add_missing_checksum=False): # strings are utf-8 encoded when written, but have not always been # (see https://bugs.launchpad.net/swift/+bug/1678018) so encode them again # when read - if six.PY2: - metadata = pickle.loads(metadata) - else: - metadata = pickle.loads(metadata, encoding='bytes') + metadata = pickle.loads(metadata, encoding='bytes') # nosec: B301 return _decode_metadata(metadata, metadata_written_by_py3) @@ -360,7 +339,7 @@ def quarantine_renamer(device_path, corrupted_file_path): def valid_suffix(value): - if not isinstance(value, six.string_types) or len(value) != 3: + if not isinstance(value, str) or len(value) != 3: return False return all(c in '0123456789abcdef' for c in value) @@ -381,7 +360,7 @@ def read_hashes(partition_dir): pass else: try: - hashes = pickle.loads(pickled_hashes) + hashes = pickle.loads(pickled_hashes) # nosec: B301 except Exception: # pickle.loads() can raise a wide variety of exceptions when # given invalid input depending on the way in which the @@ -626,11 +605,7 @@ def get_auditor_status(datadir_path, logger, auditor_type): datadir_path, "auditor_status_%s.json" % auditor_type) status = {} try: - if six.PY3: - statusfile = open(auditor_status, encoding='utf8') - else: - statusfile = open(auditor_status, 'rb') - with statusfile: + with open(auditor_status, encoding='utf8') as statusfile: status = statusfile.read() except (OSError, IOError) as e: if e.errno != errno.ENOENT and logger: @@ -648,9 +623,7 @@ def get_auditor_status(datadir_path, logger, auditor_type): def update_auditor_status(datadir_path, logger, partitions, auditor_type): - status = json.dumps({'partitions': partitions}) - if six.PY3: - status = status.encode('utf8') + status = json.dumps({'partitions': partitions}).encode('utf8') auditor_status = os.path.join( datadir_path, "auditor_status_%s.json" % auditor_type) try: @@ -1170,22 +1143,19 @@ def _hash_suffix_dir(self, path, policy): :param path: full path to directory :param policy: storage policy used """ - if six.PY2: - hashes = defaultdict(lambda: md5(usedforsecurity=False)) - else: - class shim(object): - def __init__(self): - self.md5 = md5(usedforsecurity=False) + class shim(object): + def __init__(self): + self.md5 = md5(usedforsecurity=False) - def update(self, s): - if isinstance(s, str): - self.md5.update(s.encode('utf-8')) - else: - self.md5.update(s) + def update(self, s): + if isinstance(s, str): + self.md5.update(s.encode('utf-8')) + else: + self.md5.update(s) - def hexdigest(self): - return self.md5.hexdigest() - hashes = defaultdict(shim) + def hexdigest(self): + return self.md5.hexdigest() + hashes = defaultdict(shim) try: path_contents = sorted(os.listdir(path)) except OSError as err: @@ -3206,7 +3176,7 @@ def _init_checks(self): def _check_frag(self, frag): if not frag: return - if not isinstance(frag, six.binary_type): + if not isinstance(frag, bytes): # ECInvalidParameter can be returned if the frag violates the input # format so for safety, check the input chunk if it's binary to # avoid quarantining a valid fragment archive. diff --git a/swift/obj/expirer.py b/swift/obj/expirer.py index 5d903b32a1..b5033ba0c8 100644 --- a/swift/obj/expirer.py +++ b/swift/obj/expirer.py @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six -from six.moves import urllib +import urllib from random import random from time import time @@ -344,7 +343,7 @@ def _iter_task_container(self, task_account, task_container, task_container, acceptable_statuses=[2]): container_empty = False - task_object = o['name'].encode('utf8') if six.PY2 else o['name'] + task_object = o['name'] try: delete_timestamp, target_account, target_container, \ target_object = parse_task_obj(task_object) diff --git a/swift/obj/reconstructor.py b/swift/obj/reconstructor.py index 95406387ad..de0e749eed 100644 --- a/swift/obj/reconstructor.py +++ b/swift/obj/reconstructor.py @@ -21,8 +21,7 @@ import random import time from collections import defaultdict -import six -import six.moves.cPickle as pickle +import pickle # nosec: B403 import shutil from eventlet import (GreenPile, GreenPool, Timeout, sleep, tpool, spawn) @@ -84,7 +83,7 @@ def _full_path(node, part, relative_path, policy): :class:`~swift.common.storage_policy.BaseStoragePolicy` :return: string representation of absolute path on node plus policy index """ - if not isinstance(relative_path, six.text_type): + if not isinstance(relative_path, str): relative_path = relative_path.decode('utf8') return '%(node)s/%(part)s%(path)s policy#%(policy)d' % { 'node': node_to_string(node, replication=True), @@ -935,7 +934,7 @@ def _get_suffixes_to_sync(self, job, node): "Invalid response %(resp)s from %(full_path)s", {'resp': resp.status, 'full_path': full_path}) else: - remote_suffixes = pickle.loads(resp.read()) + remote_suffixes = pickle.loads(resp.read()) # nosec: B301 except (Exception, Timeout): # all exceptions are logged here so that our caller can # safely catch our exception and continue to the next node @@ -1286,11 +1285,11 @@ def get_policy2devices(self): policy2devices = {} for policy in self.policies: self.load_object_ring(policy) - local_devices = list(six.moves.filter( - lambda dev: dev and is_local_device( + local_devices = [ + dev for dev in policy.object_ring.devs + if dev and is_local_device( ips, self.port, - dev['replication_ip'], dev['replication_port']), - policy.object_ring.devs)) + dev['replication_ip'], dev['replication_port'])] policy2devices[policy] = local_devices return policy2devices diff --git a/swift/obj/replicator.py b/swift/obj/replicator.py index 07e2815f66..332eaca8e0 100644 --- a/swift/obj/replicator.py +++ b/swift/obj/replicator.py @@ -22,8 +22,7 @@ import shutil import time import itertools -from six import viewkeys -import six.moves.cPickle as pickle +import pickle # nosec: B403 import eventlet from eventlet import GreenPool, queue, tpool, Timeout, sleep @@ -554,8 +553,8 @@ def tpool_get_suffixes(path): failure_devs_info.add((node['replication_ip'], node['device'])) if success and node['region'] != job['region']: - synced_remote_regions[node['region']] = viewkeys( - candidates) + synced_remote_regions[node['region']] = \ + candidates.keys() responses.append(success) for cand_objs in synced_remote_regions.values(): if delete_objs is None: @@ -710,7 +709,8 @@ def update(self, job): failure_devs_info.add((node['replication_ip'], node['device'])) continue - remote_hash = pickle.loads(resp.read()) + remote_hash = pickle.loads( + resp.read()) # nosec: B301 finally: conn.close() del resp diff --git a/swift/obj/server.py b/swift/obj/server.py index 1870515204..b4bf640f74 100644 --- a/swift/obj/server.py +++ b/swift/obj/server.py @@ -15,9 +15,8 @@ """ Object Server for Swift """ -import six -import six.moves.cPickle as pickle -from six.moves.urllib.parse import unquote +import pickle # nosec: B403 +from urllib.parse import unquote import json import os import multiprocessing @@ -200,8 +199,8 @@ def __init__(self, conf, logger=None): # disk_chunk_size parameter. However, it affects all created sockets # using this class so we have chosen to tie it to the # network_chunk_size parameter value instead. - if six.PY2: - socket._fileobject.default_bufsize = self.network_chunk_size + # if six.PY2: + # socket._fileobject.default_bufsize = self.network_chunk_size # TODO: find a way to enable similar functionality in py3 # Provide further setup specific to an object server implementation. diff --git a/swift/obj/ssync_receiver.py b/swift/obj/ssync_receiver.py index de75eaa9d4..ab821f8680 100644 --- a/swift/obj/ssync_receiver.py +++ b/swift/obj/ssync_receiver.py @@ -17,7 +17,7 @@ import eventlet.greenio import eventlet.wsgi from eventlet import sleep -from six.moves import urllib +import urllib from swift.common import exceptions from swift.common import http diff --git a/swift/obj/ssync_sender.py b/swift/obj/ssync_sender.py index 2ebfbd8512..6b3d8e77a3 100644 --- a/swift/obj/ssync_sender.py +++ b/swift/obj/ssync_sender.py @@ -14,8 +14,7 @@ # limitations under the License. from eventlet import sleep -import six -from six.moves import urllib +import urllib from swift.common import bufferedhttp from swift.common import exceptions @@ -306,7 +305,7 @@ def missing_check(self, connection, response): frag_index=self.job.get('frag_index'), frag_prefs=frag_prefs) if self.remote_check_objs is not None: - hash_gen = six.moves.filter( + hash_gen = filter( lambda objhash_timestamps: objhash_timestamps[0] in self.remote_check_objs, hash_gen) @@ -353,11 +352,10 @@ def missing_check(self, connection, response): if line == b':MISSING_CHECK: START': break elif line: - if not six.PY2: - try: - line = line.decode('ascii') - except UnicodeDecodeError: - pass + try: + line = line.decode('ascii') + except UnicodeDecodeError: + pass raise exceptions.ReplicationException( 'Unexpected response: %r' % utils.cap_length(line, 1024)) while True: @@ -442,11 +440,10 @@ def updates(self, connection, response, send_map): if line == b':UPDATES: START': break elif line: - if not six.PY2: - try: - line = line.decode('ascii') - except UnicodeDecodeError: - pass + try: + line = line.decode('ascii') + except UnicodeDecodeError: + pass raise exceptions.ReplicationException( 'Unexpected response: %r' % utils.cap_length(line, 1024)) while True: @@ -459,11 +456,10 @@ def updates(self, connection, response, send_map): if line == b':UPDATES: END': break elif line: - if not six.PY2: - try: - line = line.decode('ascii') - except UnicodeDecodeError: - pass + try: + line = line.decode('ascii') + except UnicodeDecodeError: + pass raise exceptions.ReplicationException( 'Unexpected response: %r' % utils.cap_length(line, 1024)) diff --git a/swift/obj/updater.py b/swift/obj/updater.py index 2500e73df3..4222feee14 100644 --- a/swift/obj/updater.py +++ b/swift/obj/updater.py @@ -12,9 +12,9 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. -from six.moves import queue +import queue -import six.moves.cPickle as pickle +import pickle # nosec: B403 import errno import os import signal @@ -62,8 +62,6 @@ def __len__(self): def __bool__(self): return bool(self.deque) - __nonzero__ = __bool__ # py2 - def __lt__(self, other): # used to sort RateLimiterBuckets by readiness if isinstance(other, RateLimiterBucket): @@ -145,7 +143,7 @@ def _bucket_key(self, update): def _get_time(self): return time.time() - def next(self): + def __next__(self): # first iterate over the wrapped iterator... for update_ctx in self.iterator: bucket = self.buckets[self._bucket_key(update_ctx['update'])] @@ -213,8 +211,6 @@ def next(self): raise StopIteration() - __next__ = next - class OldestAsyncPendingTracker: """ @@ -648,7 +644,7 @@ def aggregate_and_dump_recon(self, devices, elapsed, now): def _load_update(self, device, update_path): try: - return pickle.load(open(update_path, 'rb')) + return pickle.load(open(update_path, 'rb')) # nosec: B301 except Exception as e: if getattr(e, 'errno', None) == errno.ENOENT: return diff --git a/swift/proxy/controllers/account.py b/swift/proxy/controllers/account.py index d59306c693..340e14384b 100644 --- a/swift/proxy/controllers/account.py +++ b/swift/proxy/controllers/account.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.account.utils import account_listing_response from swift.common.middleware.acl import parse_acl, format_acl diff --git a/swift/proxy/controllers/base.py b/swift/proxy/controllers/base.py index 17f497c8fd..a2cba72816 100644 --- a/swift/proxy/controllers/base.py +++ b/swift/proxy/controllers/base.py @@ -24,7 +24,7 @@ # These shenanigans are to ensure all related objects can be garbage # collected. We've seen objects hang around forever otherwise. -from six.moves.urllib.parse import quote +from urllib.parse import quote import time import json @@ -34,10 +34,8 @@ import operator import random from copy import deepcopy -from sys import exc_info from eventlet.timeout import Timeout -import six from swift.common.memcached import MemcacheConnectionError from swift.common.wsgi import make_pre_authed_env, make_pre_authed_request @@ -626,16 +624,10 @@ def get_cache_key(account, container=None, obj=None, shard=None): with obj) :returns: a (native) string cache_key """ - if six.PY2: - def to_native(s): - if s is None or isinstance(s, str): - return s - return s.encode('utf8') - else: - def to_native(s): - if s is None or isinstance(s, str): - return s - return s.decode('utf8', 'surrogateescape') + def to_native(s): + if s is None or isinstance(s, str): + return s + return s.decode('utf8', 'surrogateescape') account = to_native(account) container = to_native(container) @@ -844,27 +836,6 @@ def _get_info_from_memcache(app, env, account, container=None): else: info = memcache.get(cache_key) cache_state = 'hit' if info else 'miss' - if info and six.PY2: - # Get back to native strings - new_info = {} - for key in info: - new_key = key.encode("utf-8") if isinstance( - key, six.text_type) else key - if isinstance(info[key], six.text_type): - new_info[new_key] = info[key].encode("utf-8") - elif isinstance(info[key], dict): - new_info[new_key] = {} - for subkey, value in info[key].items(): - new_subkey = subkey.encode("utf-8") if isinstance( - subkey, six.text_type) else subkey - if isinstance(value, six.text_type): - new_info[new_key][new_subkey] = \ - value.encode("utf-8") - else: - new_info[new_key][new_subkey] = value - else: - new_info[new_key] = info[key] - info = new_info if info: env.setdefault('swift.infocache', {})[cache_key] = info return info, cache_state @@ -921,12 +892,6 @@ def get_namespaces_from_cache(req, cache_key, skip_chance): cache_state = 'error' if bounds: - if six.PY2: - # json.loads() in memcache.get will convert json 'string' to - # 'unicode' with python2, here we cast 'unicode' back to 'str' - bounds = [ - [lower.encode('utf-8'), name.encode('utf-8')] - for lower, name in bounds] ns_bound_list = NamespaceBoundList(bounds) infocache[cache_key] = ns_bound_list else: @@ -1439,14 +1404,13 @@ def _iter_bytes_from_response_part(self, part_file, nbytes): chunk = part_file.read(self.app.object_chunk_size) if nbytes is not None: nbytes -= len(chunk) - except (ChunkReadTimeout, ShortReadError): - exc_type, exc_value, exc_traceback = exc_info() + except (ChunkReadTimeout, ShortReadError) as e: if self.newest or self.server_type != 'Object': raise try: self.fast_forward(self.bytes_used_from_backend) except (HTTPException, ValueError): - six.reraise(exc_type, exc_value, exc_traceback) + raise e except RangeAlreadyComplete: break if self._replace_source( @@ -1458,10 +1422,10 @@ def _iter_bytes_from_response_part(self, part_file, nbytes): # Tried to find a new node from which to # finish the GET, but failed. There's # nothing more we can do here. - six.reraise(exc_type, exc_value, exc_traceback) + raise e part_file = ByteCountEnforcer(part_file, nbytes) else: - six.reraise(exc_type, exc_value, exc_traceback) + raise e else: if not chunk: break @@ -1880,7 +1844,7 @@ def _annotate_node(self, node): return dict(node, use_replication=is_use_replication_network( self.request.headers)) - def next(self): + def __next__(self): node = None if self._node_provider: # give node provider the opportunity to inject a node @@ -1889,9 +1853,6 @@ def next(self): node = next(self._node_iter) return self._annotate_node(node) - def __next__(self): - return self.next() - class Controller(object): """Base WSGI controller class for the proxy""" diff --git a/swift/proxy/controllers/container.py b/swift/proxy/controllers/container.py index 6226b7a703..dcbbcc7851 100644 --- a/swift/proxy/controllers/container.py +++ b/swift/proxy/controllers/container.py @@ -15,8 +15,7 @@ import json -import six -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.common.utils import public, private, csv_append, Timestamp, \ config_true_value, cache_from_env, filter_namespaces, NamespaceBoundList @@ -508,8 +507,6 @@ def _get_from_shards(self, req, resp, namespaces): else: last_name = objects[-1]['name'] - if six.PY2: - last_name = last_name.encode('utf8') params['marker'] = str_to_wsgi(last_name) elif marker: params['marker'] = str_to_wsgi(marker) @@ -594,8 +591,6 @@ def _get_from_shards(self, req, resp, namespaces): break last_name = objects[-1].get('name', objects[-1].get('subdir', u'')) - if six.PY2: - last_name = last_name.encode('utf8') if end_marker and reverse and end_marker >= last_name: break if end_marker and not reverse and end_marker <= last_name: diff --git a/swift/proxy/controllers/obj.py b/swift/proxy/controllers/obj.py index c26fef6d45..61523fa814 100644 --- a/swift/proxy/controllers/obj.py +++ b/swift/proxy/controllers/obj.py @@ -24,9 +24,7 @@ # These shenanigans are to ensure all related objects can be garbage # collected. We've seen objects hang around forever otherwise. -import six -from six.moves.urllib.parse import quote, unquote -from six.moves import zip +from urllib.parse import quote, unquote import collections import itertools @@ -35,7 +33,6 @@ import time import math import random -import sys from greenlet import GreenletExit from eventlet import GreenPile @@ -1301,8 +1298,6 @@ def __iter__(self): def __next__(self): return next(self.stashed_iter) - next = __next__ # py2 - def _real_iter(self, req, resp_headers): if not self.range_specs: client_asked_for_range = False @@ -2490,13 +2485,12 @@ def _iter_bytes_from_response_part(self, part_file, nbytes): buf += chunk if nbytes is not None: nbytes -= len(chunk) - except (ChunkReadTimeout, ShortReadError): - exc_type, exc_value, exc_traceback = sys.exc_info() + except (ChunkReadTimeout, ShortReadError) as e: try: self.fast_forward(self.bytes_used_from_backend) except (HTTPException, ValueError): self.logger.exception('Unable to fast forward') - six.reraise(exc_type, exc_value, exc_traceback) + raise e except RangeAlreadyComplete: break buf = b'' @@ -2509,10 +2503,10 @@ def _iter_bytes_from_response_part(self, part_file, nbytes): # it's not clear to me how to make # _get_next_response_part raise StopIteration for the # first doc part of a new request - six.reraise(exc_type, exc_value, exc_traceback) + raise e part_file = ByteCountEnforcer(part_file, nbytes) else: - six.reraise(exc_type, exc_value, exc_traceback) + raise e else: if buf and self.skip_bytes: if self.skip_bytes < len(buf): diff --git a/test/__init__.py b/test/__init__.py index 2974b465f9..e31ed458a4 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -18,7 +18,6 @@ from contextlib import contextmanager import os -from six import reraise from unittest.util import safe_repr @@ -105,15 +104,15 @@ def annotate_failure(msg): try: yield except AssertionError as err: - err_typ, err_val, err_tb = sys.exc_info() - if err_val.args: - msg = '%s Failed with %s' % (msg, err_val.args[0]) - err_val.args = (msg, ) + err_val.args[1:] + if err.args: + msg = '%s Failed with %s' % (msg, err.args[0]) + err.args = (msg, ) + err.args[1:] + raise err else: # workaround for some IDE's raising custom AssertionErrors - err_val = '%s Failed with %s' % (msg, err) - err_typ = AssertionError - reraise(err_typ, err_val, err_tb) + raise AssertionError( + '%s Failed with %s' % (msg, err) + ).with_traceback(err.__traceback__) from err.__cause__ class BaseTestCase(unittest.TestCase): diff --git a/test/cors/main.py b/test/cors/main.py index 063f967247..5d483c7835 100755 --- a/test/cors/main.py +++ b/test/cors/main.py @@ -24,9 +24,9 @@ import time import traceback -from six.moves import urllib -from six.moves import socketserver -from six.moves import SimpleHTTPServer +import urllib.parse +import socketserver +import http.server try: import selenium.webdriver @@ -51,12 +51,14 @@ STEPS = 500 -# Hack up stdlib so SimpleHTTPRequestHandler works well on py2, too -this_dir = os.path.realpath(os.path.dirname(__file__)) -os.getcwd = lambda: this_dir +class CORSSiteHandler(http.server.SimpleHTTPRequestHandler): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + directory=os.path.realpath(os.path.dirname(__file__)), + **kwargs, + ) - -class CORSSiteHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def log_message(self, fmt, *args): pass # quiet, you! @@ -67,7 +69,7 @@ class CORSSiteServer(socketserver.TCPServer): class CORSSite(threading.Thread): def __init__(self, bind_port=8000): - super(CORSSite, self).__init__() + super().__init__() self.server = None self.bind_port = bind_port diff --git a/test/functional/__init__.py b/test/functional/__init__.py index ef8ca9dc77..73f3d4cb47 100644 --- a/test/functional/__init__.py +++ b/test/functional/__init__.py @@ -20,8 +20,7 @@ import mock import os -import six -from six.moves.urllib.parse import urlparse, urlsplit, urlunsplit +from urllib.parse import urlparse, urlsplit, urlunsplit import sys import pickle import socket @@ -39,9 +38,9 @@ from tempfile import mkdtemp from unittest import SkipTest -from six.moves.configparser import ConfigParser -from six.moves import http_client -from six.moves.http_client import HTTPException +from configparser import ConfigParser +import http.client +from http.client import HTTPException from swift.common.middleware.memcache import MemcacheMiddleware from swift.common.storage_policy import parse_storage_policies, PolicyError @@ -65,7 +64,7 @@ from swift.obj import server as object_server, mem_server as mem_object_server import swift.proxy.controllers.obj -http_client._MAXHEADERS = constraints.MAX_HEADER_COUNT +http.client._MAXHEADERS = constraints.MAX_HEADER_COUNT DEBUG = True # In order to get the proper blocking behavior of sockets without using @@ -357,9 +356,7 @@ def _load_encryption(proxy_conf_file, swift_conf_file, **kwargs): conf, "proxy-logging proxy-server", "keymaster encryption proxy-logging proxy-server") - root_secret = base64.b64encode(os.urandom(32)) - if not six.PY2: - root_secret = root_secret.decode('ascii') + root_secret = base64.b64encode(os.urandom(32)).decode('ascii') conf.set('filter:keymaster', 'encryption_root_secret', root_secret) conf.set('filter:versioned_writes', 'allow_object_versioning', 'true') conf.set('filter:etag-quoter', 'enable_by_default', 'true') @@ -1129,10 +1126,6 @@ def get_url_token(user_index, os_options): swift_test_user[user_index], swift_test_key[user_index], **authargs) - if six.PY2 and not isinstance(url, bytes): - url = url.encode('utf-8') - if six.PY2 and not isinstance(token, bytes): - token = token.encode('utf-8') return url, token diff --git a/test/functional/s3api/s3_test_client.py b/test/functional/s3api/s3_test_client.py index 9be79304bb..3f437a663c 100644 --- a/test/functional/s3api/s3_test_client.py +++ b/test/functional/s3api/s3_test_client.py @@ -15,7 +15,7 @@ import logging import os -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse import test.functional as tf import boto3 from botocore.exceptions import ClientError @@ -27,7 +27,6 @@ ) except ImportError: S3Connection = OrdinaryCallingFormat = S3ResponseError = None -import six import sys import traceback @@ -96,21 +95,11 @@ def reset(self): break for bucket in buckets: - if six.PY2 and not isinstance(bucket.name, bytes): - bucket.name = bucket.name.encode('utf-8') - try: for upload in bucket.list_multipart_uploads(): upload.cancel_upload() for obj in bucket.list_versions(): - if six.PY2: - if not isinstance(obj.name, bytes): - obj.name = obj.name.encode('utf-8') - if obj.version_id is not None and \ - not isinstance(obj.version_id, bytes): - obj.version_id = \ - obj.version_id.encode('utf-8') bucket.delete_key( obj.name, version_id=obj.version_id) diff --git a/test/functional/s3api/test_multi_delete.py b/test/functional/s3api/test_multi_delete.py index ac15927d66..be32a530ff 100644 --- a/test/functional/s3api/test_multi_delete.py +++ b/test/functional/s3api/test_multi_delete.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six import unittest import os import test.functional as tf @@ -83,8 +82,6 @@ def _test_delete_multi_objects(self, with_non_ascii=False): self.assertEqual(len(resp_objects), len(req_objects)) for o in resp_objects: key = o.find('Key').text - if six.PY2: - key = key.decode('utf-8') self.assertTrue(key in req_objects) # Delete 2 objects via MultiDelete API @@ -101,8 +98,6 @@ def _test_delete_multi_objects(self, with_non_ascii=False): self.assertEqual(len(resp_objects), len(req_objects)) for o in resp_objects: key = o.find('Key').text - if six.PY2: - key = key.decode('utf-8') self.assertTrue(key in req_objects) if with_non_ascii: @@ -124,8 +119,6 @@ def _test_delete_multi_objects(self, with_non_ascii=False): self.assertEqual(len(resp_objects), len(req_objects)) for o in resp_objects: key = o.find('Key').text - if six.PY2: - key = key.decode('utf-8') self.assertTrue(key in req_objects) # Delete 2 objects via MultiDelete API but no objects exist @@ -142,8 +135,6 @@ def _test_delete_multi_objects(self, with_non_ascii=False): self.assertEqual(len(resp_objects), len(req_objects)) for o in resp_objects: key = o.find('Key').text - if six.PY2: - key = key.decode('utf-8') self.assertTrue(key in req_objects) def test_delete_multi_objects(self): diff --git a/test/functional/s3api/test_multi_upload.py b/test/functional/s3api/test_multi_upload.py index 82df2419b3..74cbdff0fb 100644 --- a/test/functional/s3api/test_multi_upload.py +++ b/test/functional/s3api/test_multi_upload.py @@ -17,8 +17,8 @@ import binascii import unittest -import six -from six.moves import urllib, zip, zip_longest +import urllib.parse +from itertools import zip_longest import test.functional as tf from swift.common.middleware.s3api.etree import fromstring, tostring, \ @@ -135,8 +135,6 @@ def test_object_multi_upload(self): elem = fromstring(body, 'InitiateMultipartUploadResult') self.assertEqual(elem.find('Bucket').text, bucket) key = elem.find('Key').text - if six.PY2: - expected_key = expected_key.encode('utf-8') self.assertEqual(expected_key, key) upload_id = elem.find('UploadId').text self.assertIsNotNone(upload_id) @@ -475,10 +473,7 @@ def check_obj(req_headers, exp_status): resp_objects = list(elem.findall('./Contents')) self.assertEqual(len(resp_objects), 1) o = resp_objects[0] - if six.PY2: - expected_key = keys[0].encode('utf-8') - else: - expected_key = keys[0] + expected_key = keys[0] self.assertEqual(o.find('Key').text, expected_key) self.assertIsNotNone(o.find('LastModified').text) self.assertRegex( diff --git a/test/functional/s3api/test_object.py b/test/functional/s3api/test_object.py index d3ceef8344..eefe4888dc 100644 --- a/test/functional/s3api/test_object.py +++ b/test/functional/s3api/test_object.py @@ -20,7 +20,6 @@ import email.parser from email.utils import formatdate, parsedate from time import mktime -import six import test.functional as tf from swift.common import utils @@ -787,10 +786,7 @@ def test_get_object_range(self): # TODO: Using swift.common.utils.multipart_byteranges_to_document_iters # could be easy enough. - if six.PY2: - parser = email.parser.FeedParser() - else: - parser = email.parser.BytesFeedParser() + parser = email.parser.BytesFeedParser() parser.feed( b"Content-Type: multipart/byterange; boundary=%s\r\n\r\n" % boundary_str.encode('ascii')) diff --git a/test/functional/s3api/test_xxe_injection.py b/test/functional/s3api/test_xxe_injection.py index 07f8603797..af0a433a88 100644 --- a/test/functional/s3api/test_xxe_injection.py +++ b/test/functional/s3api/test_xxe_injection.py @@ -15,7 +15,6 @@ # limitations under the License. import requests -import six import botocore @@ -62,11 +61,10 @@ def _presign_url(self, method, key=None, **kwargs): finally: self.conn.meta.events.unregister( 'before-sign.s3.*', self._clear_data) - if not params.get('Key') and '/?' not in url and not six.PY2: + if not params.get('Key') and '/?' not in url: # Some combination of dependencies seems to cause bucket requests # to not get the trailing slash despite signing with it? But only - # new-enough versions sign with the trailing slash; py2 is stuck - # with old. + # new-enough versions sign with the trailing slash url = url.replace('?', '/?') return url diff --git a/test/functional/swift_test_client.py b/test/functional/swift_test_client.py index 5998215a04..5b01b411a0 100644 --- a/test/functional/swift_test_client.py +++ b/test/functional/swift_test_client.py @@ -25,9 +25,8 @@ from unittest import SkipTest from xml.dom import minidom -import six -from six.moves import http_client -from six.moves import urllib +import http.client +import urllib.parse from swiftclient import get_auth from swift.common import constraints @@ -37,7 +36,7 @@ from test import safe_repr -http_client._MAXHEADERS = constraints.MAX_HEADER_COUNT +http.client._MAXHEADERS = constraints.MAX_HEADER_COUNT class AuthenticationFailed(Exception): @@ -138,10 +137,10 @@ def putrequest(self, method, url, skip_host=False, skip_accept_encoding=False): and self._HTTPConnection__response.isclosed(): self._HTTPConnection__response = None - if self._HTTPConnection__state == http_client._CS_IDLE: - self._HTTPConnection__state = http_client._CS_REQ_STARTED + if self._HTTPConnection__state == http.client._CS_IDLE: + self._HTTPConnection__state = http.client._CS_REQ_STARTED else: - raise http_client.CannotSendRequest(self._HTTPConnection__state) + raise http.client.CannotSendRequest(self._HTTPConnection__state) self._method = method if not url: @@ -225,15 +224,12 @@ def storage_url(self): @storage_url.setter def storage_url(self, value): - if six.PY2 and not isinstance(value, bytes): - value = value.encode('utf-8') - url = urllib.parse.urlparse(value) if url.scheme == 'http': - self.conn_class = http_client.HTTPConnection + self.conn_class = http.client.HTTPConnection elif url.scheme == 'https': - self.conn_class = http_client.HTTPSConnection + self.conn_class = http.client.HTTPSConnection else: raise ValueError('unexpected protocol %s' % (url.scheme)) @@ -250,7 +246,7 @@ def storage_url(self, value): def storage_scheme(self): if self.conn_class is None: return None - if issubclass(self.conn_class, http_client.HTTPSConnection): + if issubclass(self.conn_class, http.client.HTTPSConnection): return 'https' return 'http' @@ -411,7 +407,7 @@ def request_with_retry(self, try_request): except socket.timeout as e: fail_messages.append(safe_repr(e)) continue - except http_client.HTTPException as e: + except http.client.HTTPException as e: fail_messages.append(safe_repr(e)) continue @@ -500,7 +496,7 @@ def is_int_header(header): 'x-container-bytes-used', ) - # NB: on py2, headers are always lower; on py3, they match the bytes + # NB: on py2, headers were always lower; on py3, they match the bytes # on the wire headers = dict((wsgi_to_str(h).lower(), wsgi_to_str(v)) for h, v in self.conn.response.getheaders()) @@ -568,9 +564,6 @@ def containers(self, hdrs=None, parms=None, cfg=None): if status == 200: if format_type == 'json': conts = json.loads(self.conn.response.read()) - if six.PY2: - for cont in conts: - cont['name'] = cont['name'].encode('utf-8') return conts elif format_type == 'xml': conts = [] @@ -582,8 +575,6 @@ def containers(self, hdrs=None, parms=None, cfg=None): childNodes[0].nodeValue conts.append(cont) for cont in conts: - if six.PY2: - cont['name'] = cont['name'].encode('utf-8') for key in ('count', 'bytes'): cont[key] = int(cont[key]) return conts @@ -591,8 +582,6 @@ def containers(self, hdrs=None, parms=None, cfg=None): lines = self.conn.response.read().split(b'\n') if lines and not lines[-1]: lines = lines[:-1] - if six.PY2: - return lines return [line.decode('utf-8') for line in lines] elif status == 204: return [] @@ -716,15 +705,7 @@ def files(self, hdrs=None, parms=None, cfg=None, tolerate_missing=False): parms=parms, cfg=cfg) if status == 200: if format_type == 'json' or 'versions' in parms: - files = json.loads(self.conn.response.read()) - - if six.PY2: - for file_item in files: - for key in ('name', 'subdir', 'content_type', - 'version_id'): - if key in file_item: - file_item[key] = file_item[key].encode('utf-8') - return files + return json.loads(self.conn.response.read()) elif format_type == 'xml': files = [] tree = minidom.parseString(self.conn.response.read()) @@ -745,15 +726,7 @@ def files(self, hdrs=None, parms=None, cfg=None, tolerate_missing=False): files.append(file_item) for file_item in files: - if 'subdir' in file_item: - if six.PY2: - file_item['subdir'] = \ - file_item['subdir'].encode('utf-8') - else: - if six.PY2: - file_item.update({ - k: file_item[k].encode('utf-8') - for k in ('name', 'content_type')}) + if 'bytes' in file_item: file_item['bytes'] = int(file_item['bytes']) return files else: @@ -762,8 +735,6 @@ def files(self, hdrs=None, parms=None, cfg=None, tolerate_missing=False): lines = content.split(b'\n') if lines and not lines[-1]: lines = lines[:-1] - if six.PY2: - return lines return [line.decode('utf-8') for line in lines] else: return [] diff --git a/test/functional/test_access_control.py b/test/functional/test_access_control.py index 7bc3e479a2..accf1b1ea0 100644 --- a/test/functional/test_access_control.py +++ b/test/functional/test_access_control.py @@ -15,7 +15,7 @@ # limitations under the License. import unittest -from six.moves.urllib.parse import urlparse, urlunparse +from urllib.parse import urlparse, urlunparse import uuid from random import shuffle diff --git a/test/functional/test_account.py b/test/functional/test_account.py index dab6ad9908..9a40a14a07 100644 --- a/test/functional/test_account.py +++ b/test/functional/test_account.py @@ -17,11 +17,10 @@ import unittest import json +import urllib.parse from uuid import uuid4 from string import ascii_letters -import six -from six.moves import range, urllib from swift.common.middleware.acl import format_acl from swift.common.utils import distribute_evenly @@ -756,40 +755,18 @@ def post(url, token, parsed, conn, name, value): def head(url, token, parsed, conn): conn.request('HEAD', parsed.path, '', {'X-Auth-Token': token}) return check_response(conn) - uni_key = u'X-Account-Meta-uni\u0E12' uni_value = u'uni\u0E12' # Note that py3 has issues with non-ascii header names; see - # https://bugs.python.org/issue37093 - if (tf.web_front_end == 'integral' and six.PY2): - resp = retry(post, uni_key, '1') - resp.read() - self.assertIn(resp.status, (201, 204)) - resp = retry(head) - resp.read() - self.assertIn(resp.status, (200, 204)) - self.assertEqual(resp.getheader(uni_key.encode('utf-8')), '1') + # https://bugs.python.org/issue37093 -- so we won't test with unicode + # header names resp = retry(post, 'X-Account-Meta-uni', uni_value) resp.read() self.assertEqual(resp.status, 204) resp = retry(head) resp.read() self.assertIn(resp.status, (200, 204)) - if six.PY2: - self.assertEqual(resp.getheader('X-Account-Meta-uni'), - uni_value.encode('utf8')) - else: - self.assertEqual(resp.getheader('X-Account-Meta-uni'), - uni_value) - # See above note about py3 and non-ascii header names - if (tf.web_front_end == 'integral' and six.PY2): - resp = retry(post, uni_key, uni_value) - resp.read() - self.assertEqual(resp.status, 204) - resp = retry(head) - resp.read() - self.assertIn(resp.status, (200, 204)) - self.assertEqual(resp.getheader(uni_key.encode('utf-8')), - uni_value.encode('utf-8')) + self.assertEqual(resp.getheader('X-Account-Meta-uni'), + uni_value) def test_multi_metadata(self): if tf.skip: diff --git a/test/functional/test_container.py b/test/functional/test_container.py index 879bd0b06e..658e9a6c85 100644 --- a/test/functional/test_container.py +++ b/test/functional/test_container.py @@ -17,15 +17,13 @@ import json import unittest +import urllib.parse from uuid import uuid4 from test.functional import check_response, cluster_info, retry, \ requires_acls, load_constraint, requires_policies, SkipTest import test.functional as tf -import six -from six.moves import range, urllib - def setUpModule(): tf.setup_package() @@ -72,11 +70,7 @@ def get(url, token, parsed, conn, container): return check_response(conn) def delete(url, token, parsed, conn, container, obj): - if six.PY2: - obj_name = obj['name'].encode('utf8') - else: - obj_name = obj['name'] - path = '/'.join([parsed.path, container, obj_name]) + path = '/'.join([parsed.path, container, obj['name']]) conn.request('DELETE', path, '', {'X-Auth-Token': token}) return check_response(conn) @@ -219,40 +213,18 @@ def head(url, token, parsed, conn): {'X-Auth-Token': token}) return check_response(conn) - uni_key = u'X-Container-Meta-uni\u0E12' uni_value = u'uni\u0E12' # Note that py3 has issues with non-ascii header names; see - # https://bugs.python.org/issue37093 - if (tf.web_front_end == 'integral' and six.PY2): - resp = retry(post, uni_key, '1') - resp.read() - self.assertEqual(resp.status, 204) - resp = retry(head) - resp.read() - self.assertIn(resp.status, (200, 204)) - self.assertEqual(resp.getheader(uni_key.encode('utf-8')), '1') + # https://bugs.python.org/issue37093 -- so we won't test with unicode + # header names resp = retry(post, 'X-Container-Meta-uni', uni_value) resp.read() self.assertEqual(resp.status, 204) resp = retry(head) resp.read() self.assertIn(resp.status, (200, 204)) - if six.PY2: - self.assertEqual(resp.getheader('X-Container-Meta-uni'), - uni_value.encode('utf-8')) - else: - self.assertEqual(resp.getheader('X-Container-Meta-uni'), - uni_value) - # See above note about py3 and non-ascii header names - if (tf.web_front_end == 'integral' and six.PY2): - resp = retry(post, uni_key, uni_value) - resp.read() - self.assertEqual(resp.status, 204) - resp = retry(head) - resp.read() - self.assertIn(resp.status, (200, 204)) - self.assertEqual(resp.getheader(uni_key.encode('utf-8')), - uni_value.encode('utf-8')) + self.assertEqual(resp.getheader('X-Container-Meta-uni'), + uni_value) def test_PUT_metadata(self): if tf.skip: @@ -844,9 +816,7 @@ def put(url, token, parsed, conn, name): # read-only can list containers resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.name, listing) @@ -861,9 +831,7 @@ def put(url, token, parsed, conn, name): resp.read() self.assertEqual(resp.status, 201) resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(new_container_name, listing) @@ -963,9 +931,7 @@ def delete(url, token, parsed, conn, name): # can list containers resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.name, listing) @@ -975,9 +941,7 @@ def delete(url, token, parsed, conn, name): resp.read() self.assertIn(resp.status, (201, 202)) resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(new_container_name, listing) @@ -986,9 +950,7 @@ def delete(url, token, parsed, conn, name): resp.read() self.assertIn(resp.status, (204, 404)) resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertNotIn(new_container_name, listing) @@ -1111,9 +1073,7 @@ def delete(url, token, parsed, conn, name): # can list containers resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.name, listing) @@ -1123,9 +1083,7 @@ def delete(url, token, parsed, conn, name): resp.read() self.assertEqual(resp.status, 201) resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(new_container_name, listing) @@ -1134,9 +1092,7 @@ def delete(url, token, parsed, conn, name): resp.read() self.assertEqual(resp.status, 204) resp = retry(get, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertNotIn(new_container_name, listing) diff --git a/test/functional/test_dlo.py b/test/functional/test_dlo.py index 4de2c17c77..58f2004f99 100644 --- a/test/functional/test_dlo.py +++ b/test/functional/test_dlo.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from six.moves import urllib +import urllib from swift.common.swob import str_to_wsgi import test.functional as tf diff --git a/test/functional/test_domain_remap.py b/test/functional/test_domain_remap.py index 1313efcfa1..178fab459b 100644 --- a/test/functional/test_domain_remap.py +++ b/test/functional/test_domain_remap.py @@ -15,7 +15,6 @@ # limitations under the License. from unittest import SkipTest -import six import test.functional as tf from test.functional import cluster_info @@ -117,9 +116,7 @@ def test_GET_remapped_account(self): hdrs={'Host': domain}, cfg={'absolute_path': True}) self.assert_status(200) - body = self.env.account.conn.response.read() - if not six.PY2: - body = body.decode('utf8') + body = self.env.account.conn.response.read().decode('utf8') self.assertIn(self.env.container.name, body.split('\n')) path = '/'.join(['', self.env.container.name]) @@ -127,9 +124,7 @@ def test_GET_remapped_account(self): hdrs={'Host': domain}, cfg={'absolute_path': True}) self.assert_status(200) - body = self.env.account.conn.response.read() - if not six.PY2: - body = body.decode('utf8') + body = self.env.account.conn.response.read().decode('utf8') self.assertIn(self.env.obj.name, body.split('\n')) self.assertIn(self.env.obj_slash.name, body.split('\n')) @@ -170,9 +165,7 @@ def test_GET_remapped_container(self): hdrs={'Host': domain}, cfg={'absolute_path': True}) self.assert_status(200) - body = self.env.account.conn.response.read() - if not six.PY2: - body = body.decode('utf8') + body = self.env.account.conn.response.read().decode('utf8') self.assertIn(self.env.obj.name, body.split('\n')) self.assertIn(self.env.obj_slash.name, body.split('\n')) diff --git a/test/functional/test_object.py b/test/functional/test_object.py index 24dd8d7291..33d8052214 100644 --- a/test/functional/test_object.py +++ b/test/functional/test_object.py @@ -23,9 +23,6 @@ from unittest import SkipTest from xml.dom import minidom -import six -from six.moves import range - from swift.common.header_key_dict import HeaderKeyDict from test.functional import check_response, retry, requires_acls, \ requires_policies, requires_bulk @@ -109,11 +106,7 @@ def get(url, token, parsed, conn, container): # delete an object def delete(url, token, parsed, conn, container, obj): - if six.PY2: - obj_name = obj['name'].encode('utf8') - else: - obj_name = obj['name'] - path = '/'.join([parsed.path, container, obj_name]) + path = '/'.join([parsed.path, container, obj['name']]) conn.request('DELETE', path, '', {'X-Auth-Token': token}) return check_response(conn) @@ -1261,9 +1254,7 @@ def delete(url, token, parsed, conn, name): # can list objects resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.obj, listing.split('\n')) @@ -1286,9 +1277,7 @@ def delete(url, token, parsed, conn, name): # sanity with account1 resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertNotIn(obj_name, listing.split('\n')) self.assertIn(self.obj, listing.split('\n')) @@ -1346,9 +1335,7 @@ def delete(url, token, parsed, conn, name): # can list objects resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.obj, listing.split('\n')) @@ -1371,9 +1358,7 @@ def delete(url, token, parsed, conn, name): # sanity with account1 resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(obj_name, listing.split('\n')) self.assertNotIn(self.obj, listing.split('\n')) @@ -1431,9 +1416,7 @@ def delete(url, token, parsed, conn, name): # can list objects resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(self.obj, listing.split('\n')) @@ -1456,9 +1439,7 @@ def delete(url, token, parsed, conn, name): # sanity with account1 resp = retry(get_listing, use_account=3) - listing = resp.read() - if not six.PY2: - listing = listing.decode('utf8') + listing = resp.read().decode('utf8') self.assertEqual(resp.status, 200) self.assertIn(obj_name, listing.split('\n')) self.assertNotIn(self.obj, listing) @@ -1961,9 +1942,7 @@ def get_obj(url, token, parsed, conn, container, obj): for c, o, body in validate_requests: resp = retry(get_obj, c, o) self.assertEqual(resp.status, 200) - if not six.PY2: - body = body.encode('utf8') - self.assertEqual(body, resp.read()) + self.assertEqual(body.encode('utf8'), resp.read()) @requires_bulk def test_bulk_delete(self): diff --git a/test/functional/test_object_versioning.py b/test/functional/test_object_versioning.py index 32d0641165..a822a71a72 100644 --- a/test/functional/test_object_versioning.py +++ b/test/functional/test_object_versioning.py @@ -18,10 +18,9 @@ import hmac import json import time -import six from copy import deepcopy -from six.moves.urllib.parse import quote, unquote +from urllib.parse import quote, unquote from unittest import SkipTest import test.functional as tf @@ -64,13 +63,7 @@ def setUp(cls): cls.conn2 = Connection(config2) cls.conn2.authenticate() - if six.PY2: - # avoid getting a prefix that stops halfway through an encoded - # character - prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8") - else: - prefix = Utils.create_name()[:10] - + prefix = Utils.create_name()[:10] cls.container = cls.account.container(prefix + "-objs") container_headers = {cls.versions_header_key: 'True'} if not cls.container.create(hdrs=container_headers): @@ -2344,7 +2337,7 @@ def _assert_is_manifest(self, file_item, seg_name, version_id=None): for k_client, k_slo in key_map.items(): self.assertEqual(self.seg_info[seg_name][k_client], - Utils.encode_if_py2(manifest[0][k_slo])) + manifest[0][k_slo]) def _assert_is_object(self, file_item, seg_data, version_id=None): if version_id: @@ -2591,13 +2584,7 @@ class TestVersionsLocationWithVersioning(TestObjectVersioningBase): def setUp(self): super(TestVersionsLocationWithVersioning, self).setUp() - if six.PY2: - # avoid getting a prefix that stops halfway through an encoded - # character - prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8") - else: - prefix = Utils.create_name()[:10] - + prefix = Utils.create_name()[:10] self.versions_container = self.env.account.container( prefix + "-versions") if not self.versions_container.create(): @@ -2725,10 +2712,9 @@ def setUp(self): def tempurl_parms(self, method, expires, path, key): path = unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') sig = hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), @@ -2838,10 +2824,9 @@ def setUp(self): def tempurl_sig(self, method, expires, path, key): path = unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') return hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), diff --git a/test/functional/test_slo.py b/test/functional/test_slo.py index 4a040dc011..011ae84488 100644 --- a/test/functional/test_slo.py +++ b/test/functional/test_slo.py @@ -22,9 +22,7 @@ from copy import deepcopy from unittest import SkipTest -import six -from six.moves import urllib - +import urllib from swift.common.swob import normalize_etag from swift.common.utils import md5, config_true_value @@ -782,10 +780,7 @@ def test_slo_multi_ranged_get(self): hdrs={"Range": "bytes=1048571-1048580,2097147-2097156"}) # See testMultiRangeGets for explanation - if six.PY2: - parser = email.parser.FeedParser() - else: - parser = email.parser.BytesFeedParser() + parser = email.parser.BytesFeedParser() parser.feed(( "Content-Type: %s\r\n\r\n" % file_item.content_type).encode()) parser.feed(file_contents) @@ -1501,8 +1496,6 @@ def test_slo_get_the_manifest_with_details_from_server(self): value[0]['hash'], md5(b'd' * 1024 * 1024, usedforsecurity=False).hexdigest()) expected_name = '/%s/seg_d' % self.env.container.name - if six.PY2: - expected_name = expected_name.decode("utf-8") self.assertEqual(value[0]['name'], expected_name) self.assertEqual(value[1]['bytes'], 1024 * 1024) @@ -1510,8 +1503,6 @@ def test_slo_get_the_manifest_with_details_from_server(self): value[1]['hash'], md5(b'b' * 1024 * 1024, usedforsecurity=False).hexdigest()) expected_name = '/%s/seg_b' % self.env.container.name - if six.PY2: - expected_name = expected_name.decode("utf-8") self.assertEqual(value[1]['name'], expected_name) def test_slo_get_raw_the_manifest_with_details_from_server(self): @@ -1537,16 +1528,12 @@ def test_slo_get_raw_the_manifest_with_details_from_server(self): value[0]['etag'], md5(b'd' * 1024 * 1024, usedforsecurity=False).hexdigest()) expected_name = '/%s/seg_d' % self.env.container.name - if six.PY2: - expected_name = expected_name.decode("utf-8") self.assertEqual(value[0]['path'], expected_name) self.assertEqual(value[1]['size_bytes'], 1024 * 1024) self.assertEqual( value[1]['etag'], md5(b'b' * 1024 * 1024, usedforsecurity=False).hexdigest()) expected_name = '/%s/seg_b' % self.env.container.name - if six.PY2: - expected_name = expected_name.decode("utf-8") self.assertEqual(value[1]['path'], expected_name) file_item = self.env.container.file("manifest-from-get-raw") diff --git a/test/functional/test_staticweb.py b/test/functional/test_staticweb.py index b26f98f37f..a98f4ba861 100644 --- a/test/functional/test_staticweb.py +++ b/test/functional/test_staticweb.py @@ -16,10 +16,9 @@ import functools import hashlib -import six import time from unittest import SkipTest -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.common.middleware import tempurl from swift.common.utils import quote from swift.common.swob import str_to_wsgi @@ -223,9 +222,7 @@ def _test_get_path(self, host, path, anonymous=False, expected_status=200, hdrs={'X-Web-Mode': str(not anonymous), 'Host': host}, cfg={'no_auth_token': anonymous, 'absolute_path': True}) self.assert_status(expected_status) - body = self.env.account.conn.response.read() - if not six.PY2: - body = body.decode('utf8') + body = self.env.account.conn.response.read().decode('utf8') for string in expected_in: self.assertIn(string, body) for string in expected_not_in: @@ -565,9 +562,7 @@ def test_get_root(self): parms=self.whole_container_parms, cfg={'no_auth_token': True}) self.assertEqual(status, 200) - body = self.env.conn.response.read() - if not six.PY2: - body = body.decode('utf-8') + body = self.env.conn.response.read().decode('utf-8') self.assertIn('Listing of /v1/', body) self.assertNotIn('href="..', body) self.assertIn(self.link('dir/'), body) @@ -579,9 +574,7 @@ def test_get_dir(self): parms=self.whole_container_parms, cfg={'no_auth_token': True}) self.assertEqual(status, 200) - body = self.env.conn.response.read() - if not six.PY2: - body = body.decode('utf-8') + body = self.env.conn.response.read().decode('utf-8') self.assertIn('Listing of /v1/', body) self.assertIn('href="..', body) self.assertIn(self.link('dir/obj'), body) @@ -599,9 +592,7 @@ def test_get_dir_with_iso_expiry(self): parms=iso_parms, cfg={'no_auth_token': True}) self.assertEqual(status, 200) - body = self.env.conn.response.read() - if not six.PY2: - body = body.decode('utf-8') + body = self.env.conn.response.read().decode('utf-8') self.assertIn('Listing of /v1/', body) self.assertIn('href="..', body) self.assertIn(self.link('dir/obj', iso_parms), body) @@ -619,9 +610,7 @@ def test_get_limited_dir(self): self.env.container.path + [self.env.objects['dir/'].name, ''], parms=parms, cfg={'no_auth_token': True}) self.assertEqual(status, 200) - body = self.env.conn.response.read() - if not six.PY2: - body = body.decode('utf-8') + body = self.env.conn.response.read().decode('utf-8') self.assertIn('Listing of /v1/', body) self.assertNotIn('href="..', body) self.assertIn(self.link('dir/obj', parms), body) @@ -632,9 +621,7 @@ def test_get_limited_dir(self): self.env.objects['dir/subdir/'].name, ''], parms=parms, cfg={'no_auth_token': True}) self.assertEqual(status, 200) - body = self.env.conn.response.read() - if not six.PY2: - body = body.decode('utf-8') + body = self.env.conn.response.read().decode('utf-8') self.assertIn('Listing of /v1/', body) self.assertIn('href="..', body) self.assertIn(self.link('dir/subdir/obj', parms), body) diff --git a/test/functional/test_symlink.py b/test/functional/test_symlink.py index eee6465761..c1c86044be 100755 --- a/test/functional/test_symlink.py +++ b/test/functional/test_symlink.py @@ -18,10 +18,9 @@ import unittest import itertools import hashlib -import six import time -from six.moves import urllib +import urllib.parse from uuid import uuid4 from swift.common.http import is_success @@ -2293,10 +2292,9 @@ def setUp(self): def tempurl_parms(self, method, expires, path, key): path = urllib.parse.unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') sig = hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), @@ -2391,10 +2389,9 @@ def setUp(self): def tempurl_sig(self, method, expires, path, key): path = urllib.parse.unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') return hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), diff --git a/test/functional/test_tempurl.py b/test/functional/test_tempurl.py index feb36b23a8..d95f6be199 100644 --- a/test/functional/test_tempurl.py +++ b/test/functional/test_tempurl.py @@ -20,8 +20,7 @@ import hashlib import json from copy import deepcopy -import six -from six.moves import urllib +import urllib.parse from time import time, strftime, gmtime from unittest import SkipTest @@ -36,13 +35,9 @@ def tempurl_parms(method, expires, path, key, digest=None): path = urllib.parse.unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') sig = hmac.new( - key, - b'%s\n%d\n%s' % (method, expires, path), + key.encode('utf8'), + b'%s\n%d\n%s' % (method.encode('utf8'), expires, path.encode('utf8')), digest or hashlib.sha256).hexdigest() return {'temp_url_sig': sig, 'temp_url_expires': str(expires)} @@ -349,10 +344,7 @@ def tempurl_parms(self, method, expires, path, key, if prefix is None: # Choose the first 4 chars of object name as prefix. - if six.PY2: - prefix = path_parts[4].decode('utf8')[:4].encode('utf8') - else: - prefix = path_parts[4][:4] + prefix = path_parts[4][:4] prefix_to_hash = '/'.join(path_parts[0:4]) + '/' + prefix parms = tempurl_parms( method, expires, @@ -490,10 +482,9 @@ def setUp(self): def tempurl_sig(self, method, expires, path, key): path = urllib.parse.unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') return hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), @@ -757,10 +748,9 @@ def setUp(self): def tempurl_sig(self, method, expires, path, key): path = urllib.parse.unquote(path) - if not six.PY2: - method = method.encode('utf8') - path = path.encode('utf8') - key = key.encode('utf8') + method = method.encode('utf8') + path = path.encode('utf8') + key = key.encode('utf8') return hmac.new( key, b'%s\n%d\n%s' % (method, expires, path), @@ -815,11 +805,8 @@ def setUp(self): def get_sig(self, expires, digest, encoding): path = urllib.parse.unquote(self.env.conn.make_path(self.env.obj.path)) - if six.PY2: - key = self.env.tempurl_key - else: - path = path.encode('utf8') - key = self.env.tempurl_key.encode('utf8') + path = path.encode('utf8') + key = self.env.tempurl_key.encode('utf8') sig = hmac.new( key, b'GET\n%d\n%s' % (expires, path), diff --git a/test/functional/test_versioned_writes.py b/test/functional/test_versioned_writes.py index 1f8023729d..dd65a83834 100644 --- a/test/functional/test_versioned_writes.py +++ b/test/functional/test_versioned_writes.py @@ -18,8 +18,7 @@ import json import time import unittest -import six -from six.moves.urllib.parse import quote, unquote +from urllib.parse import quote, unquote from unittest import SkipTest import test.functional as tf @@ -56,13 +55,7 @@ def setUp(cls): cls.conn2 = Connection(config2) cls.conn2.authenticate() - if six.PY2: - # avoid getting a prefix that stops halfway through an encoded - # character - prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8") - else: - prefix = Utils.create_name()[:10] - + prefix = Utils.create_name()[:10] cls.versions_container = cls.account.container(prefix + "-versions") if not cls.versions_container.create(): raise ResponseError(cls.conn.response) @@ -148,13 +141,7 @@ def setUp(cls): cls.conn2 = Connection(config2) cls.conn2.authenticate() - if six.PY2: - # avoid getting a prefix that stops halfway through an encoded - # character - prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8") - else: - prefix = Utils.create_name()[:10] - + prefix = Utils.create_name()[:10] cls.versions_container = cls.account.container(prefix + "-versions") if not cls.versions_container.create( {'X-Storage-Policy': policy['name']}): @@ -432,7 +419,7 @@ def test_overwriting_with_url_encoded_object_name(self): def assert_most_recent_version(self, obj_name, content, should_be_dlo=False): - name_len = len(obj_name if six.PY2 else obj_name.encode('utf8')) + name_len = len(obj_name.encode('utf8')) archive_versions = self.env.versions_container.files(parms={ 'prefix': '%03x%s/' % (name_len, obj_name), 'reverse': 'yes'}) @@ -926,7 +913,7 @@ def test_versioning_dlo(self): expected = [b'old content', b'112233', b'new content', b''] - name_len = len(obj_name if six.PY2 else obj_name.encode('utf8')) + name_len = len(obj_name.encode('utf8')) bodies = [ self.env.versions_container.file(f).read() for f in self.env.versions_container.files(parms={ @@ -1047,12 +1034,8 @@ def _assert_is_manifest(self, file_item, seg_name): for k_client, k_slo in key_map.items(): self.assertEqual(self.seg_info[seg_name][k_client], manifest[0][k_slo]) - if six.PY2: - self.assertEqual(self.seg_info[seg_name]['path'].decode('utf8'), - manifest[0]['name']) - else: - self.assertEqual(self.seg_info[seg_name]['path'], - manifest[0]['name']) + self.assertEqual(self.seg_info[seg_name]['path'], + manifest[0]['name']) def _assert_is_object(self, file_item, seg_data): file_contents = file_item.read() diff --git a/test/functional/tests.py b/test/functional/tests.py index 948647feba..7825a84282 100644 --- a/test/functional/tests.py +++ b/test/functional/tests.py @@ -18,8 +18,7 @@ import io import locale import random -import six -from six.moves import urllib +import urllib.parse import time import unittest import uuid @@ -30,10 +29,7 @@ from swift.common.utils import md5 from email.utils import parsedate -if six.PY2: - from email.parser import FeedParser -else: - from email.parser import BytesFeedParser as FeedParser +from email.parser import BytesFeedParser as FeedParser import mock @@ -53,12 +49,6 @@ def tearDownModule(): class Utils(object): - @classmethod - def encode_if_py2(cls, value): - if six.PY2 and isinstance(value, six.text_type): - return value.encode('utf8') - return value - @classmethod def create_ascii_name(cls, length=None): return uuid.uuid4().hex @@ -75,9 +65,8 @@ def create_utf8_name(cls, length=None): u'\u1802\u0901\uF111\uD20F\uB30D\u940B\u850A\u5607'\ u'\u3705\u1803\u0902\uF112\uD210\uB30E\u940C\u850B'\ u'\u5608\u3706\u1804\u0903\u03A9\u2603' - ustr = u''.join([random.choice(utf8_chars) + return u''.join([random.choice(utf8_chars) for x in range(length)]) - return cls.encode_if_py2(ustr) create_name = create_ascii_name @@ -190,11 +179,8 @@ def testNoAuthToken(self): def testInvalidUTF8Path(self): valid_utf8 = Utils.create_utf8_name() - if six.PY2: - invalid_utf8 = valid_utf8[::-1] - else: - invalid_utf8 = (valid_utf8.encode('utf8')[::-1]).decode( - 'utf-8', 'surrogateescape') + invalid_utf8 = (valid_utf8.encode('utf8')[::-1]).decode( + 'utf-8', 'surrogateescape') container = self.env.account.container(invalid_utf8) self.assertFalse(container.create(cfg={'no_path_quote': True})) self.assert_status(412) @@ -778,11 +764,8 @@ def testContainerFileListOnContainerThatDoesNotExist(self): def testUtf8Container(self): valid_utf8 = Utils.create_utf8_name() - if six.PY2: - invalid_utf8 = valid_utf8[::-1] - else: - invalid_utf8 = (valid_utf8.encode('utf8')[::-1]).decode( - 'utf-8', 'surrogateescape') + invalid_utf8 = (valid_utf8.encode('utf8')[::-1]).decode( + 'utf-8', 'surrogateescape') container = self.env.account.container(valid_utf8) self.assertTrue(container.create(cfg={'no_path_quote': True})) self.assertIn(container.name, self.env.account.containers()) @@ -804,14 +787,9 @@ def testCreateOnExisting(self): self.assert_status(202) def testSlashInName(self): - if six.PY2: - cont_name = list(Utils.create_name().decode('utf-8')) - else: - cont_name = list(Utils.create_name()) + cont_name = list(Utils.create_name()) cont_name[random.randint(2, len(cont_name) - 2)] = '/' cont_name = ''.join(cont_name) - if six.PY2: - cont_name = cont_name.encode('utf-8') cont = self.env.account.container(cont_name) self.assertFalse(cont.create(cfg={'no_path_quote': True}), @@ -2031,11 +2009,8 @@ def testMetadataNumberLimit(self): if len(key) > j: key = key[:j] # NB: we'll likely write object metadata that's *not* UTF-8 - if six.PY2: - val = val[:j] - else: - val = val.encode('utf8')[:j].decode( - 'utf8', 'surrogateescape') + val = val.encode('utf8')[:j].decode( + 'utf8', 'surrogateescape') metadata[key] = val diff --git a/test/probe/brain.py b/test/probe/brain.py index 64cce6df94..cdd29e1840 100644 --- a/test/probe/brain.py +++ b/test/probe/brain.py @@ -20,8 +20,7 @@ from optparse import OptionParser import random -import six -from six.moves.urllib.parse import urlparse, parse_qs, quote +from urllib.parse import urlparse, parse_qs, quote from swift.common.manager import Manager from swift.common import utils, ring @@ -68,8 +67,7 @@ def command(f): return f -@six.add_metaclass(meta_command) -class BaseBrain(object): +class BaseBrain(object, metaclass=meta_command): def _setup(self, account, container_name, object_name, server_type, policy): self.account = account diff --git a/test/probe/common.py b/test/probe/common.py index e980f99f46..a6120c560b 100644 --- a/test/probe/common.py +++ b/test/probe/common.py @@ -29,9 +29,8 @@ import unittest from uuid import uuid4 import shutil -import six -from six.moves.http_client import HTTPConnection -from six.moves.urllib.parse import urlparse +from http.client import HTTPConnection +from urllib.parse import urlparse from swiftclient import get_auth, head_account, client from swift.common import internal_client, direct_client, utils @@ -342,9 +341,6 @@ def __next__(self): self.hasher.update(rv) return rv - # for py2 compat: - next = __next__ - def exclude_nodes(nodes, *excludes): """ @@ -723,16 +719,9 @@ def direct_get(self, node, part, require_durable=True, extra_headers=None): if not require_durable: req_headers.update( {'X-Backend-Fragment-Preferences': json.dumps([])}) - # node dict has unicode values so utf8 decode our path parts too in - # case they have non-ascii characters - if six.PY2: - acc, con, obj = (s.decode('utf8') for s in ( - self.account, self.container_name, self.object_name)) - else: - acc, con, obj = self.account, self.container_name, self.object_name headers, data = direct_client.direct_get_object( - node, part, acc, con, obj, headers=req_headers, - resp_chunk_size=64 * 2 ** 20) + node, part, self.account, self.container_name, self.object_name, + headers=req_headers, resp_chunk_size=64 * 2 ** 20) hasher = md5(usedforsecurity=False) for chunk in data: hasher.update(chunk) diff --git a/test/probe/test_account_get_fake_responses_match.py b/test/probe/test_account_get_fake_responses_match.py index a0d58ffd56..5276049fad 100644 --- a/test/probe/test_account_get_fake_responses_match.py +++ b/test/probe/test_account_get_fake_responses_match.py @@ -17,8 +17,8 @@ import re import unittest -from six.moves import http_client -from six.moves.urllib.parse import urlparse +import http.client +from urllib.parse import urlparse from swiftclient import get_auth from test.probe import PROXY_BASE_URL from test.probe.common import ReplProbeTest @@ -53,9 +53,9 @@ def _account_request(self, account, method, headers=None): port = int(port) if scheme == 'https': - conn = http_client.HTTPSConnection(host, port) + conn = http.client.HTTPSConnection(host, port) else: - conn = http_client.HTTPConnection(host, port) + conn = http.client.HTTPConnection(host, port) conn.request(method, self._account_path(account), headers=headers) resp = conn.getresponse() if resp.status // 100 != 2: diff --git a/test/probe/test_container_sync.py b/test/probe/test_container_sync.py index a6d521b0ec..b5aca19fc8 100644 --- a/test/probe/test_container_sync.py +++ b/test/probe/test_container_sync.py @@ -16,7 +16,7 @@ import random import unittest -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from swiftclient import client, ClientException from swift.common.http import HTTP_NOT_FOUND diff --git a/test/probe/test_dark_data.py b/test/probe/test_dark_data.py index e45474c290..dcd6cff53b 100644 --- a/test/probe/test_dark_data.py +++ b/test/probe/test_dark_data.py @@ -22,7 +22,7 @@ import shutil from datetime import datetime -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from test.probe.brain import BrainSplitter from test.probe.common import ReplProbeTest diff --git a/test/probe/test_object_async_update.py b/test/probe/test_object_async_update.py index 6bd404ec4a..b2d71185aa 100644 --- a/test/probe/test_object_async_update.py +++ b/test/probe/test_object_async_update.py @@ -30,7 +30,7 @@ from swiftclient import client from swiftclient.exceptions import ClientException -from six.moves.configparser import ConfigParser +from configparser import ConfigParser from swift.common import direct_client, manager from swift.common.manager import Manager, Server from swift.common.swob import normalize_etag diff --git a/test/probe/test_reconstructor_rebuild.py b/test/probe/test_reconstructor_rebuild.py index a5e14ea398..d54fe25ae9 100644 --- a/test/probe/test_reconstructor_rebuild.py +++ b/test/probe/test_reconstructor_rebuild.py @@ -19,7 +19,6 @@ import uuid import random import time -import six from swift.common.direct_client import DirectClientException from swift.common.manager import Manager @@ -54,9 +53,6 @@ def __next__(self): self.hasher.update(self.chunk) return self.chunk - # for py2 compat - next = __next__ - class TestReconstructorRebuild(ECProbeTest): @@ -526,15 +522,15 @@ def test_rebuild_quarantines_lonely_frag(self): self.assertEqual([], lines) -if six.PY2: - # The non-ASCII chars in metadata cause test hangs in - # _assert_all_nodes_have_frag because of https://bugs.python.org/issue37093 - - class TestReconstructorRebuildUTF8(TestReconstructorRebuild): +class TestReconstructorRebuildUTF8(TestReconstructorRebuild): - def _make_name(self, prefix): - return b'%s\xc3\xa8-%s' % ( - prefix.encode(), str(uuid.uuid4()).encode()) + def _make_name(self, prefix): + # The non-ASCII chars in metadata cause test hangs in + # _assert_all_nodes_have_frag because of + # https://bugs.python.org/issue37093 + raise unittest.SkipTest('This never got fixed on py3') + return b'%s\xc3\xa8-%s' % ( + prefix.encode(), str(uuid.uuid4()).encode()) if __name__ == "__main__": diff --git a/test/probe/test_sharder.py b/test/probe/test_sharder.py index efef292081..d41baf771a 100644 --- a/test/probe/test_sharder.py +++ b/test/probe/test_sharder.py @@ -21,8 +21,7 @@ import uuid from unittest import SkipTest -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift.common import direct_client, utils from swift.common.header_key_dict import HeaderKeyDict @@ -352,8 +351,7 @@ def assert_container_listing(self, expected_listing, req_hdrs=None): self.assertIn('x-container-object-count', headers) expected_obj_count = len(expected_listing) self.assertEqual(expected_listing, [ - x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in actual_listing]) + x['name'] for x in actual_listing]) self.assertEqual(str(expected_obj_count), headers['x-container-object-count']) return headers, actual_listing @@ -519,8 +517,7 @@ def check_listing(objects, req_hdrs=None, **params): headers, listing = client.get_container( self.url, self.token, self.container_name, query_string=qs, headers=req_hdrs) - listing = [x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing] + listing = [x['name'] for x in listing] if params.get('reverse'): marker = params.get('marker', ShardRange.MAX) end_marker = params.get('end_marker', ShardRange.MIN) @@ -716,9 +713,7 @@ def _make_object_names(self, number, start=0): obj_names = [] for x in range(start, start + number): name = (u'obj-\u00e4\u00ea\u00ec\u00f2\u00fb\u1234-%04d' % x) - name = name.encode('utf8').ljust(name_length, b'o') - if not six.PY2: - name = name.decode('utf8') + name = name.encode('utf8').ljust(name_length, b'o').decode('utf8') obj_names.append(name) return obj_names @@ -728,9 +723,8 @@ def _setup_container_name(self): name_length = self.cluster_info['swift']['max_container_name_length'] cont_name = \ self.container_name + u'-\u00e4\u00ea\u00ec\u00f2\u00fb\u1234' - self.container_name = cont_name.encode('utf8').ljust(name_length, b'x') - if not six.PY2: - self.container_name = self.container_name.decode('utf8') + self.container_name = cont_name.encode('utf8').ljust( + name_length, b'x').decode('utf8') class TestContainerShardingObjectVersioning(BaseAutoContainerSharding): @@ -783,8 +777,7 @@ def check_listing(objects, **params): qs = '&'.join('%s=%s' % param for param in params.items()) headers, listing = client.get_container( self.url, self.token, self.container_name, query_string=qs) - listing = [(x['name'].encode('utf-8') if six.PY2 else x['name'], - x['version_id']) + listing = [(x['name'], x['version_id']) for x in listing] if params.get('reverse'): marker = ( @@ -958,8 +951,7 @@ def _test_sharded_listing(self, run_replicators=False): headers, pre_sharding_listing = client.get_container( self.url, self.token, self.container_name) self.assertEqual(obj_names, [ - x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in pre_sharding_listing]) # sanity + x['name'] for x in pre_sharding_listing]) # sanity # Shard it client.post_container(self.url, self.admin_token, self.container_name, @@ -1595,9 +1587,7 @@ def test_async_pendings(self): shard_listings = self.direct_get_container(sr.account, sr.container) for node, (hdrs, listing) in shard_listings.items(): - shard_listing_names = [ - o['name'].encode('utf-8') if six.PY2 else o['name'] - for o in listing] + shard_listing_names = [o['name'] for o in listing] for obj in obj_names[4::5]: if obj in sr: self.assertIn(obj, shard_listing_names) @@ -1612,29 +1602,25 @@ def test_async_pendings(self): start_listing = [ o for o in obj_names if o <= expected_shard_ranges[1].upper] self.assertEqual( - [x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing[:len(start_listing)]], + [x['name'] for x in listing[:len(start_listing)]], start_listing) # we can't assert much about the remaining listing, other than that # there should be something self.assertTrue( - [x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing[len(start_listing):]]) + [x['name'] for x in listing[len(start_listing):]]) self.assertIn('x-container-object-count', headers) self.assertEqual(str(len(listing)), headers['x-container-object-count']) headers, listing = client.get_container(self.url, self.token, self.container_name, query_string='reverse=on') - self.assertEqual([x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing[-len(start_listing):]], + self.assertEqual([x['name'] for x in listing[-len(start_listing):]], list(reversed(start_listing))) self.assertIn('x-container-object-count', headers) self.assertEqual(str(len(listing)), headers['x-container-object-count']) self.assertTrue( - [x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing[:-len(start_listing)]]) + [x['name'] for x in listing[:-len(start_listing)]]) # Run the sharders again to get everything to settle self.sharders.once() @@ -1644,8 +1630,7 @@ def test_async_pendings(self): # now all shards have been cleaved we should get the complete listing headers, listing = client.get_container(self.url, self.token, self.container_name) - self.assertEqual([x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing], + self.assertEqual([x['name'] for x in listing], obj_names) # Create a few more objects in async pending. Check them, they should @@ -1669,16 +1654,13 @@ def test_async_pendings(self): # they don't exist yet headers, listing = client.get_container(self.url, self.token, self.container_name) - self.assertEqual([x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing], - obj_names) + self.assertEqual([x['name'] for x in listing], obj_names) # Now clear them out and they should now exist where we expect. Manager(['object-updater']).once() headers, listing = client.get_container(self.url, self.token, self.container_name) - self.assertEqual([x['name'].encode('utf-8') if six.PY2 else x['name'] - for x in listing], + self.assertEqual([x['name'] for x in listing], obj_names + more_obj_names) # And they're cleared up @@ -3202,9 +3184,7 @@ def _make_object_names(self, number, start=0): obj_names = [] for x in range(start, start + number): name = (u'obj-\u00e4\u00ea\u00ec\u00f2\u00fb-%04d' % x) - name = name.encode('utf8').ljust(name_length, b'o') - if not six.PY2: - name = name.decode('utf8') + name = name.encode('utf8').ljust(name_length, b'o').decode('utf8') obj_names.append(name) return obj_names @@ -3214,9 +3194,8 @@ def _setup_container_name(self): name_length = self.cluster_info['swift']['max_container_name_length'] cont_name = \ self.container_name + u'-\u00e4\u00ea\u00ec\u00f2\u00fb\u1234' - self.container_name = cont_name.encode('utf8').ljust(name_length, b'x') - if not six.PY2: - self.container_name = self.container_name.decode('utf8') + self.container_name = cont_name.encode('utf8').ljust( + name_length, b'x').decode('utf8') class TestManagedContainerSharding(BaseTestContainerSharding): diff --git a/test/probe/test_signals.py b/test/probe/test_signals.py index 761c53d2e2..1fd3facee6 100644 --- a/test/probe/test_signals.py +++ b/test/probe/test_signals.py @@ -25,8 +25,8 @@ import time from uuid import uuid4 -from six.moves import http_client as httplib -from six.moves.urllib.parse import urlparse +import http.client +from urllib.parse import urlparse from swift.common.ring import Ring from swift.common.manager import Manager @@ -113,8 +113,8 @@ def assert4xx(self, resp): def get_conn(self): scheme, ip, port = self.get_scheme_ip_port() if scheme == 'https': - return httplib.HTTPSConnection('%s:%s' % (ip, port)) - return httplib.HTTPConnection('%s:%s' % (ip, port)) + return http.client.HTTPSConnection('%s:%s' % (ip, port)) + return http.client.HTTPConnection('%s:%s' % (ip, port)) def _check_reload(self): conn = self.get_conn() diff --git a/test/s3api/__init__.py b/test/s3api/__init__.py index 14ce43166f..8eaa65567e 100644 --- a/test/s3api/__init__.py +++ b/test/s3api/__init__.py @@ -21,7 +21,7 @@ import boto3 from botocore.exceptions import ClientError -from six.moves import urllib +import urllib.parse from swift.common.utils import config_true_value, readconf diff --git a/test/s3api/test_input_errors.py b/test/s3api/test_input_errors.py index b260e6d564..45938ec602 100644 --- a/test/s3api/test_input_errors.py +++ b/test/s3api/test_input_errors.py @@ -21,7 +21,7 @@ import os import requests import requests.models -from six.moves.urllib.parse import urlsplit, urlunsplit, quote +from urllib.parse import urlsplit, urlunsplit, quote from swift.common import bufferedhttp from swift.common.utils import UTC diff --git a/test/s3api/test_versioning.py b/test/s3api/test_versioning.py index ec06594fa8..01c242ff45 100644 --- a/test/s3api/test_versioning.py +++ b/test/s3api/test_versioning.py @@ -17,7 +17,7 @@ from collections import defaultdict from botocore.exceptions import ClientError -import six +import io from swift.common.header_key_dict import HeaderKeyDict from swift.common.utils import md5 @@ -125,7 +125,7 @@ def test_upload_fileobj_versioned(self): obj_data = self.create_name('some-data').encode('ascii') obj_etag = md5(obj_data, usedforsecurity=False).hexdigest() obj_name = self.create_name('versioned-obj') - self.client.upload_fileobj(six.BytesIO(obj_data), + self.client.upload_fileobj(io.BytesIO(obj_data), self.bucket_name, obj_name) # object is in the listing @@ -158,7 +158,7 @@ def test_upload_fileobj_versioned(self): # overwrite the object new_obj_data = self.create_name('some-new-data').encode('ascii') new_obj_etag = md5(new_obj_data, usedforsecurity=False).hexdigest() - self.client.upload_fileobj(six.BytesIO(new_obj_data), + self.client.upload_fileobj(io.BytesIO(new_obj_data), self.bucket_name, obj_name) # new object is in the listing @@ -200,7 +200,7 @@ def test_delete_versioned_objects(self): for i in range(3): obj_data = self.create_name('some-data-%s' % i).encode('ascii') etags.insert(0, md5(obj_data, usedforsecurity=False).hexdigest()) - self.client.upload_fileobj(six.BytesIO(obj_data), + self.client.upload_fileobj(io.BytesIO(obj_data), self.bucket_name, obj_name) # only one object appears in the listing @@ -320,7 +320,7 @@ def test_delete_versioned_deletes(self): for i in range(3): obj_data = self.create_name('some-data-%s' % i).encode('ascii') etags.insert(0, md5(obj_data, usedforsecurity=False).hexdigest()) - self.client.upload_fileobj(six.BytesIO(obj_data), + self.client.upload_fileobj(io.BytesIO(obj_data), self.bucket_name, obj_name) # and make a delete marker self.client.delete_object(Bucket=self.bucket_name, Key=obj_name) @@ -492,7 +492,7 @@ def test_get_versioned_object(self): # TODO: pull etag from response instead etags.insert(0, md5(obj_data, usedforsecurity=False).hexdigest()) self.client.upload_fileobj( - six.BytesIO(obj_data), self.bucket_name, obj_name) + io.BytesIO(obj_data), self.bucket_name, obj_name) resp = self.client.list_object_versions(Bucket=self.bucket_name) objs = resp.get('Versions', []) @@ -574,13 +574,13 @@ def test_get_versioned_object_key_marker(self): etags.insert(0, '"%s"' % md5( obj_data, usedforsecurity=False).hexdigest()) self.client.upload_fileobj( - six.BytesIO(obj_data), self.bucket_name, obj01_name) + io.BytesIO(obj_data), self.bucket_name, obj01_name) for i in range(3): obj_data = self.create_name('some-data-%s' % i).encode('ascii') etags.insert(0, '"%s"' % md5( obj_data, usedforsecurity=False).hexdigest()) self.client.upload_fileobj( - six.BytesIO(obj_data), self.bucket_name, obj00_name) + io.BytesIO(obj_data), self.bucket_name, obj00_name) resp = self.client.list_object_versions(Bucket=self.bucket_name) versions = [] objs = [] @@ -658,7 +658,7 @@ def test_list_objects(self): etags[obj_name].insert(0, md5( obj_data, usedforsecurity=False).hexdigest()) self.client.upload_fileobj( - six.BytesIO(obj_data), self.bucket_name, obj_name) + io.BytesIO(obj_data), self.bucket_name, obj_name) # both unversioned list_objects responses are similar expected = [] @@ -714,7 +714,7 @@ def test_copy_object(self): etags.insert(0, md5( obj_data, usedforsecurity=False).hexdigest()) self.client.upload_fileobj( - six.BytesIO(obj_data), self.bucket_name, obj_name) + io.BytesIO(obj_data), self.bucket_name, obj_name) resp = self.client.list_object_versions(Bucket=self.bucket_name) objs = resp.get('Versions', []) diff --git a/test/unit/__init__.py b/test/unit/__init__.py index 484f934eed..a8659b6762 100644 --- a/test/unit/__init__.py +++ b/test/unit/__init__.py @@ -23,10 +23,7 @@ import sys from contextlib import contextmanager, closing from collections import defaultdict -try: - from collections.abc import Iterable -except ImportError: - from collections import Iterable # py2 +from collections.abc import Iterable import itertools from numbers import Number from tempfile import NamedTemporaryFile @@ -43,12 +40,8 @@ import xattr from io import BytesIO from uuid import uuid4 - -import six -import six.moves.cPickle as pickle -from six.moves import range -from six.moves.http_client import HTTPException -from six.moves import configparser +import pickle +from http.client import HTTPException from swift.common import storage_policy, swob, utils, exceptions from swift.common.memcached import MemcacheConnectionError @@ -492,8 +485,6 @@ def __next__(self): self.next_call_count += 1 return next(self.values) - next = __next__ # py2 - def close(self): self.close_call_count += 1 @@ -984,14 +975,9 @@ def connect(*args, **ckwargs): if 'give_connect' in kwargs: give_conn_fn = kwargs['give_connect'] - if six.PY2: - argspec = inspect.getargspec(give_conn_fn) - if argspec.keywords or 'connection_id' in argspec.args: - ckwargs['connection_id'] = i - else: - argspec = inspect.getfullargspec(give_conn_fn) - if argspec.varkw or 'connection_id' in argspec.args: - ckwargs['connection_id'] = i + argspec = inspect.getfullargspec(give_conn_fn) + if argspec.varkw or 'connection_id' in argspec.args: + ckwargs['connection_id'] = i give_conn_fn(*args, **ckwargs) etag = next(etag_iter) headers = next(headers_iter) @@ -1024,8 +1010,6 @@ def mocked_http_conn(*args, **kwargs): responses = [] def capture_requests(ip, port, method, path, headers, qs, ssl): - if six.PY2 and not isinstance(ip, bytes): - ip = ip.encode('ascii') req = { 'ip': ip, 'port': port, @@ -1435,39 +1419,6 @@ def generate_db_path(tempdir, server_type): '%s-%s.db' % (server_type, uuid4())) -class ConfigAssertMixin(object): - """ - Use this with a TestCase to get py2/3 compatible assert for DuplicateOption - """ - def assertDuplicateOption(self, app_config, option_name, option_value): - """ - PY3 added a DuplicateOptionError, PY2 didn't seem to care - """ - if six.PY3: - self.assertDuplicateOptionError(app_config, option_name) - else: - self.assertDuplicateOptionOK(app_config, option_name, option_value) - - def assertDuplicateOptionError(self, app_config, option_name): - with self.assertRaises( - configparser.DuplicateOptionError) as ctx: - app_config() - msg = str(ctx.exception) - self.assertIn(option_name, msg) - self.assertIn('already exists', msg) - - def assertDuplicateOptionOK(self, app_config, option_name, option_value): - app = app_config() - if hasattr(app, 'conf'): - found_value = app.conf[option_name] - else: - if hasattr(app, '_pipeline_final_app'): - # special case for proxy app! - app = app._pipeline_final_app - found_value = getattr(app, option_name) - self.assertEqual(found_value, option_value) - - class FakeSource(object): def __init__(self, chunks, headers=None, body=b''): self.chunks = list(chunks) @@ -1526,12 +1477,10 @@ def _capture_call(self): def __iter__(self): return self - def next(self): + def __next__(self): self._capture_call() return next(self.wrapped_iter) - __next__ = next - def __del__(self): self._capture_call() diff --git a/test/unit/account/test_backend.py b/test/unit/account/test_backend.py index 000a45417f..4cfde189c0 100644 --- a/test/unit/account/test_backend.py +++ b/test/unit/account/test_backend.py @@ -29,8 +29,6 @@ import base64 import shutil -import six - from swift.account.backend import AccountBroker from swift.common.utils import Timestamp from test.unit import patch_policies, with_tempdir, make_timestamp_iter @@ -190,7 +188,7 @@ def test_batched_reclaim(self): now = time() top_of_the_minute = now - (now % 60) c = itertools.cycle([True, False]) - for m, is_deleted in six.moves.zip(range(num_of_containers), c): + for m, is_deleted in zip(range(num_of_containers), c): offset = top_of_the_minute - (m * 60) container_specs.append((Timestamp(offset), is_deleted)) random.seed(now) @@ -847,7 +845,7 @@ def test_chexor(self): text = '%s-%s' % ('b', "%s-%s-%s-%s" % ( Timestamp(2).internal, Timestamp(0).internal, 0, 0)) hashb = md5(text.encode('ascii'), usedforsecurity=False).digest() - hashc = ''.join(('%02x' % (ord(a) ^ ord(b) if six.PY2 else a ^ b) + hashc = ''.join(('%02x' % (a ^ b) for a, b in zip(hasha, hashb))) self.assertEqual(broker.get_info()['hash'], hashc) broker.put_container('b', Timestamp(3).internal, @@ -856,7 +854,7 @@ def test_chexor(self): text = '%s-%s' % ('b', "%s-%s-%s-%s" % ( Timestamp(3).internal, Timestamp(0).internal, 0, 0)) hashb = md5(text.encode('ascii'), usedforsecurity=False).digest() - hashc = ''.join(('%02x' % (ord(a) ^ ord(b) if six.PY2 else a ^ b) + hashc = ''.join(('%02x' % (a ^ b) for a, b in zip(hasha, hashb))) self.assertEqual(broker.get_info()['hash'], hashc) @@ -886,8 +884,6 @@ def test_merge_items(self): def test_merge_items_overwrite_unicode(self): snowman = u'\N{SNOWMAN}' - if six.PY2: - snowman = snowman.encode('utf-8') broker1 = AccountBroker(self.get_db_path(), account='a') broker1.initialize(Timestamp('1').internal, 0) id1 = broker1.get_info()['id'] diff --git a/test/unit/account/test_server.py b/test/unit/account/test_server.py index ddb877c150..63ee07fb69 100644 --- a/test/unit/account/test_server.py +++ b/test/unit/account/test_server.py @@ -22,11 +22,10 @@ from shutil import rmtree import itertools import random -from io import BytesIO +from io import BytesIO, StringIO import json -from six import StringIO -from six.moves.urllib.parse import quote +from urllib.parse import quote import xml.dom.minidom from swift import __version__ as swift_version diff --git a/test/unit/cli/test_container_deleter.py b/test/unit/cli/test_container_deleter.py index b7819c9dd5..38046f09cd 100644 --- a/test/unit/cli/test_container_deleter.py +++ b/test/unit/cli/test_container_deleter.py @@ -14,7 +14,6 @@ import itertools import json import mock -import six import unittest from swift.cli import container_deleter @@ -91,11 +90,6 @@ def test_make_delete_jobs_native_utf8(self): ucont = cont = u'cont-\N{SNOWMAN}' uobj1 = obj1 = u'obj-\N{GREEK CAPITAL LETTER ALPHA}' uobj2 = obj2 = u'/obj-\N{GREEK CAPITAL LETTER OMEGA}' - if six.PY2: - acct = acct.encode('utf8') - cont = cont.encode('utf8') - obj1 = obj1.encode('utf8') - obj2 = obj2.encode('utf8') self.assertEqual( container_deleter.make_delete_jobs( acct, cont, [obj1, obj2], utils.Timestamp(ts)), diff --git a/test/unit/cli/test_form_signature.py b/test/unit/cli/test_form_signature.py index 944589145b..daeb15fa91 100644 --- a/test/unit/cli/test_form_signature.py +++ b/test/unit/cli/test_form_signature.py @@ -14,10 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import hashlib import hmac import mock -import six import unittest from swift.cli import form_signature @@ -26,7 +26,7 @@ class TestFormSignature(unittest.TestCase): def test_prints_signature(self): the_time = 1406143563.020043 - key = 'secret squirrel' + key = b'secret squirrel' expires = 3600 path = '/v1/a/c/o' redirect = 'https://example.com/done.html' @@ -35,17 +35,11 @@ def test_prints_signature(self): data = "\n".join(( path, redirect, max_file_size, max_file_count, - str(int(the_time + expires)))) - - if six.PY3: - data = data if isinstance(data, six.binary_type) else \ - data.encode('utf8') - key = key if isinstance(key, six.binary_type) else \ - key.encode('utf8') + str(int(the_time + expires)))).encode('utf8') expected_signature = hmac.new(key, data, hashlib.sha1).hexdigest() - out = six.StringIO() + out = io.StringIO() with mock.patch('swift.cli.form_signature.time', lambda: the_time): with mock.patch('sys.stdout', out): exitcode = form_signature.main([ @@ -64,7 +58,7 @@ def test_prints_signature(self): self.assertIn(sig_input, out.getvalue()) def test_too_few_args(self): - out = six.StringIO() + out = io.StringIO() with mock.patch('sys.stdout', out): exitcode = form_signature.main([ '/path/to/swift-form-signature', @@ -75,7 +69,7 @@ def test_too_few_args(self): self.assertIn(usage, out.getvalue()) def test_invalid_filesize_arg(self): - out = six.StringIO() + out = io.StringIO() key = 'secret squirrel' with mock.patch('sys.stdout', out): exitcode = form_signature.main([ @@ -84,7 +78,7 @@ def test_invalid_filesize_arg(self): self.assertNotEqual(exitcode, 0) def test_invalid_filecount_arg(self): - out = six.StringIO() + out = io.StringIO() key = 'secret squirrel' with mock.patch('sys.stdout', out): exitcode = form_signature.main([ @@ -93,7 +87,7 @@ def test_invalid_filecount_arg(self): self.assertNotEqual(exitcode, 0) def test_invalid_path_arg(self): - out = six.StringIO() + out = io.StringIO() key = 'secret squirrel' with mock.patch('sys.stdout', out): exitcode = form_signature.main([ @@ -102,7 +96,7 @@ def test_invalid_path_arg(self): self.assertNotEqual(exitcode, 0) def test_invalid_seconds_arg(self): - out = six.StringIO() + out = io.StringIO() key = 'secret squirrel' with mock.patch('sys.stdout', out): exitcode = form_signature.main([ diff --git a/test/unit/cli/test_info.py b/test/unit/cli/test_info.py index a2a17c8647..5899e14bab 100644 --- a/test/unit/cli/test_info.py +++ b/test/unit/cli/test_info.py @@ -19,8 +19,7 @@ from shutil import rmtree from tempfile import mkdtemp -import six -from six.moves import cStringIO as StringIO +from io import StringIO from test.unit import patch_policies, write_fake_ring, skip_if_no_xattrs from swift.common import ring, utils @@ -423,12 +422,8 @@ def test_print_db_info_metadata_with_shard_ranges_bis(self): out = StringIO() with mock.patch('sys.stdout', out): print_db_info_metadata('container', info, {}, verbose=True) - if six.PY2: - s_a = '\\xe3\\x82\\xa2' - s_ya = '\\xe3\\x83\\xa4' - else: - s_a = '\u30a2' - s_ya = '\u30e4' + s_a = '\u30a2' + s_ya = '\u30e4' exp_out = '''Path: /acct/cont Account: acct Container: cont diff --git a/test/unit/cli/test_manage_shard_ranges.py b/test/unit/cli/test_manage_shard_ranges.py index 9efcf2ad2f..05f44e1051 100644 --- a/test/unit/cli/test_manage_shard_ranges.py +++ b/test/unit/cli/test_manage_shard_ranges.py @@ -21,8 +21,7 @@ from shutil import rmtree from tempfile import mkdtemp -import six -from six.moves import cStringIO as StringIO +from io import StringIO from swift.cli.manage_shard_ranges import main from swift.common import utils @@ -660,8 +659,7 @@ def test_info(self): '}', 'Metadata:', ' X-Container-Sysmeta-Sharding = True'] - # The json.dumps() in py2 produces trailing space, not in py3. - result = [x.rstrip() for x in out.getvalue().splitlines()] + result = [x for x in out.getvalue().splitlines()] self.assertEqual(expected, result) self.assertEqual(['Loaded db broker for a/c'], err.getvalue().splitlines()) @@ -2909,17 +2907,10 @@ def test_subcommand_required(self): err = StringIO() with mock.patch('sys.stdout', out), \ mock.patch('sys.stderr', err): - if six.PY2: - with self.assertRaises(SystemExit) as cm: - main(['db file']) - err_lines = err.getvalue().split('\n') - self.assertIn('too few arguments', ' '.join(err_lines)) - self.assertEqual(2, cm.exception.code) - else: - ret = main(['db file']) - self.assertEqual(2, ret) - err_lines = err.getvalue().split('\n') - self.assertIn('A sub-command is required.', err_lines) + ret = main(['db file']) + self.assertEqual(2, ret) + err_lines = err.getvalue().split('\n') + self.assertIn('A sub-command is required.', err_lines) def test_dry_run_and_yes_is_invalid(self): out = StringIO() diff --git a/test/unit/cli/test_recon.py b/test/unit/cli/test_recon.py index 541bdc0047..c29d2b0b8b 100644 --- a/test/unit/cli/test_recon.py +++ b/test/unit/cli/test_recon.py @@ -24,11 +24,10 @@ import shutil import string import sys -import six from eventlet.green import socket -from six import StringIO -from six.moves import urllib +from io import StringIO +import urllib from swift.cli import recon from swift.common import utils @@ -37,12 +36,8 @@ from swift.common.storage_policy import StoragePolicy, POLICIES from test.unit import patch_policies -if six.PY3: - from eventlet.green.urllib import request as urllib2 - GREEN_URLLIB_URLOPEN = 'eventlet.green.urllib.request.urlopen' -else: - from eventlet.green import urllib2 - GREEN_URLLIB_URLOPEN = 'eventlet.green.urllib2.urlopen' +from eventlet.green.urllib import request as urllib_request +GREEN_URLLIB_URLOPEN = 'eventlet.green.urllib.request.urlopen' class TestHelpers(unittest.TestCase): @@ -81,21 +76,21 @@ def test_scout_ok(self, mock_urlopen): @mock.patch(GREEN_URLLIB_URLOPEN) def test_scout_url_error(self, mock_urlopen): - mock_urlopen.side_effect = urllib2.URLError("") + mock_urlopen.side_effect = urllib_request.URLError("") url, content, status, ts_start, ts_end = self.scout_instance.scout( ("127.0.0.1", "8080")) - self.assertIsInstance(content, urllib2.URLError) + self.assertIsInstance(content, urllib_request.URLError) self.assertEqual(url, self.url) self.assertEqual(status, -1) @mock.patch(GREEN_URLLIB_URLOPEN) def test_scout_http_error(self, mock_urlopen): - mock_urlopen.side_effect = urllib2.HTTPError( + mock_urlopen.side_effect = urllib_request.HTTPError( self.url, 404, "Internal error", None, None) url, content, status, ts_start, ts_end = self.scout_instance.scout( ("127.0.0.1", "8080")) self.assertEqual(url, self.url) - self.assertIsInstance(content, urllib2.HTTPError) + self.assertIsInstance(content, urllib_request.HTTPError) self.assertEqual(status, 404) @mock.patch(GREEN_URLLIB_URLOPEN) @@ -121,21 +116,21 @@ def getheader(name): @mock.patch(GREEN_URLLIB_URLOPEN) def test_scout_server_type_url_error(self, mock_urlopen): - mock_urlopen.side_effect = urllib2.URLError("") + mock_urlopen.side_effect = urllib_request.URLError("") url, content, status = self.scout_instance.scout_server_type( ("127.0.0.1", "8080")) - self.assertIsInstance(content, urllib2.URLError) + self.assertIsInstance(content, urllib_request.URLError) self.assertEqual(url, self.server_type_url) self.assertEqual(status, -1) @mock.patch(GREEN_URLLIB_URLOPEN) def test_scout_server_type_http_error(self, mock_urlopen): - mock_urlopen.side_effect = urllib2.HTTPError( + mock_urlopen.side_effect = urllib_request.HTTPError( self.server_type_url, 404, "Internal error", None, None) url, content, status = self.scout_instance.scout_server_type( ("127.0.0.1", "8080")) self.assertEqual(url, self.server_type_url) - self.assertIsInstance(content, urllib2.HTTPError) + self.assertIsInstance(content, urllib_request.HTTPError) self.assertEqual(status, 404) @mock.patch(GREEN_URLLIB_URLOPEN) @@ -711,7 +706,7 @@ def fake_urlopen(url, timeout): resp = mock.MagicMock() resp.read = mock.MagicMock(side_effect=[ - response_body if six.PY2 else response_body.encode('utf8')]) + response_body.encode('utf8')]) return resp return mock.patch(GREEN_URLLIB_URLOPEN, fake_urlopen) @@ -912,18 +907,16 @@ def dummy_request(*args, **kwargs): mock.call(' 90% 1 **********************************'), mock.call('Disk usage: space used: 260 of 300'), mock.call('Disk usage: space free: 40 of 300'), - mock.call('Disk usage: lowest: 85.0%, ' + - 'highest: 90.0%%, avg: %s' % - ('86.6666666667%' if six.PY2 else - '86.66666666666667%')), + mock.call('Disk usage: lowest: 85.0%, ' + 'highest: 90.0%, avg: 86.66666666666667%'), mock.call('=' * 79), ] - with mock.patch('six.moves.builtins.print') as mock_print: + with mock.patch('builtins.print') as mock_print: cli.disk_usage([('127.0.0.1', 6010)]) mock_print.assert_has_calls(default_calls) - with mock.patch('six.moves.builtins.print') as mock_print: + with mock.patch('builtins.print') as mock_print: expected_calls = default_calls + [ mock.call('LOWEST 5'), mock.call('85.00% 127.0.0.1 sdc1'), @@ -933,7 +926,7 @@ def dummy_request(*args, **kwargs): cli.disk_usage([('127.0.0.1', 6010)], 0, 5) mock_print.assert_has_calls(expected_calls) - with mock.patch('six.moves.builtins.print') as mock_print: + with mock.patch('builtins.print') as mock_print: expected_calls = default_calls + [ mock.call('TOP 5'), mock.call('90.00% 127.0.0.1 sdb1'), @@ -943,7 +936,7 @@ def dummy_request(*args, **kwargs): cli.disk_usage([('127.0.0.1', 6010)], 5, 0) mock_print.assert_has_calls(expected_calls) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_replication_check(self, mock_now, mock_print): now = 1430000000.0 @@ -998,7 +991,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_sharding_check(self, mock_now, mock_print): now = 1430000000.0 @@ -1106,7 +1099,7 @@ def dummy_request(*args, **kwargs): cli.sharding_check([('127.0.0.1', 6011), ('127.0.0.1', 6021)]) mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_reconstruction_check(self, mock_now, mock_print): now = 1430000000.0 @@ -1141,7 +1134,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_load_check(self, mock_now, mock_print): now = 1430000000.0 @@ -1175,7 +1168,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_time_check(self, mock_now, mock_print): now = 1430000000.0 @@ -1207,7 +1200,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_time_check_mismatch(self, mock_now, mock_print): now = 1430000000.0 @@ -1243,7 +1236,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_time_check_jitter(self, mock_now, mock_print): now = 1430000000.0 @@ -1275,7 +1268,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') def test_version_check(self, mock_print): version = "2.7.1.dev144" @@ -1306,7 +1299,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('time.time') def test_time_check_jitter_mismatch(self, mock_now, mock_print): now = 1430000000.0 @@ -1344,7 +1337,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') def test_version_check_differs(self, mock_print): def dummy_request(*args, **kwargs): return [ @@ -1373,7 +1366,7 @@ def dummy_request(*args, **kwargs): # that is returned from the recon middleware, thus can't rely on it mock_print.assert_has_calls(default_calls, any_order=True) - @mock.patch('six.moves.builtins.print') + @mock.patch('builtins.print') @mock.patch('swift.cli.recon.SwiftRecon.get_hosts') def test_multiple_server_types(self, mock_get_hosts, mock_print): mock_get_hosts.return_value = set([('127.0.0.1', 10000)]) diff --git a/test/unit/cli/test_relinker.py b/test/unit/cli/test_relinker.py index b6bd7e0e14..9ca18c3316 100644 --- a/test/unit/cli/test_relinker.py +++ b/test/unit/cli/test_relinker.py @@ -27,7 +27,7 @@ import unittest import uuid -from six.moves import cStringIO as StringIO +from io import StringIO from swift.cli import relinker from swift.common import ring, utils diff --git a/test/unit/cli/test_reload.py b/test/unit/cli/test_reload.py index 33fbc15a67..5ccd59391d 100644 --- a/test/unit/cli/test_reload.py +++ b/test/unit/cli/test_reload.py @@ -15,11 +15,10 @@ import mock import signal -import six import subprocess import unittest -from six.moves import StringIO +from io import StringIO from swift.cli import reload @@ -213,8 +212,5 @@ def test_needs_pid(self): self.assertEqual(caught.exception.args, (reload.EXIT_BAD_PID,)) msg = 'usage: \nSafely reload WSGI servers' self.assertEqual(self.mock_stderr.getvalue()[:len(msg)], msg) - if six.PY2: - msg = '\n: error: too few arguments\n' - else: - msg = '\n: error: the following arguments are required: pid\n' + msg = '\n: error: the following arguments are required: pid\n' self.assertEqual(self.mock_stderr.getvalue()[-len(msg):], msg) diff --git a/test/unit/cli/test_ring_builder_analyzer.py b/test/unit/cli/test_ring_builder_analyzer.py index 3b7ca8030d..0d56a8054f 100644 --- a/test/unit/cli/test_ring_builder_analyzer.py +++ b/test/unit/cli/test_ring_builder_analyzer.py @@ -17,7 +17,7 @@ import os import json import mock -from six import StringIO +from io import StringIO import unittest from test.unit import with_tempdir diff --git a/test/unit/cli/test_ringbuilder.py b/test/unit/cli/test_ringbuilder.py index 11a2d40ae8..00b3b344af 100644 --- a/test/unit/cli/test_ringbuilder.py +++ b/test/unit/cli/test_ringbuilder.py @@ -19,7 +19,7 @@ import mock import os import re -import six +import io import tempfile import unittest import uuid @@ -44,11 +44,11 @@ class RunSwiftRingBuilderMixin(object): def run_srb(self, *argv, **kwargs): - if len(argv) == 1 and isinstance(argv[0], six.string_types): + if len(argv) == 1 and isinstance(argv[0], str): # convert a single string to a list argv = shlex.split(argv[0]) - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() if 'exp_results' in kwargs: exp_results = kwargs['exp_results'] @@ -1732,7 +1732,7 @@ def test_validate_composite_builder_file(self): cb_file = os.path.join(self.tmpdir, 'composite.builder') cb.save(cb_file) argv = ["", cb_file, "validate"] - with mock.patch("sys.stdout", six.StringIO()) as mock_stdout: + with mock.patch("sys.stdout", io.StringIO()) as mock_stdout: self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) lines = mock_stdout.getvalue().strip().split('\n') self.assertIn("Ring Builder file is invalid", lines[0]) @@ -1742,7 +1742,7 @@ def test_validate_composite_builder_file(self): def test_validate_empty_file(self): open(self.tmpfile, 'a').close argv = ["", self.tmpfile, "validate"] - with mock.patch("sys.stdout", six.StringIO()) as mock_stdout: + with mock.patch("sys.stdout", io.StringIO()) as mock_stdout: self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) lines = mock_stdout.getvalue().strip().split('\n') self.assertIn("Ring Builder file is invalid", lines[0]) @@ -1761,7 +1761,7 @@ def test_validate_corrupted_file(self): # corrupt the file with open(self.tmpfile, 'wb') as f: f.write(os.urandom(1024)) - with mock.patch("sys.stdout", six.StringIO()) as mock_stdout: + with mock.patch("sys.stdout", io.StringIO()) as mock_stdout: self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) lines = mock_stdout.getvalue().strip().split('\n') self.assertIn("Ring Builder file is invalid", lines[0]) @@ -1772,7 +1772,7 @@ def test_validate_corrupted_file(self): def test_validate_non_existent_file(self): rand_file = '%s/%s' % (tempfile.gettempdir(), str(uuid.uuid4())) argv = ["", rand_file, "validate"] - with mock.patch("sys.stdout", six.StringIO()) as mock_stdout: + with mock.patch("sys.stdout", io.StringIO()) as mock_stdout: self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) lines = mock_stdout.getvalue().strip().split('\n') self.assertIn("Ring Builder file does not exist", lines[0]) @@ -1785,7 +1785,7 @@ def test_validate_non_accessible_file(self): RingBuilder, 'load', mock.Mock(side_effect=exceptions.PermissionError("boom"))): argv = ["", self.tmpfile, "validate"] - with mock.patch("sys.stdout", six.StringIO()) as mock_stdout: + with mock.patch("sys.stdout", io.StringIO()) as mock_stdout: self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) lines = mock_stdout.getvalue().strip().split('\n') self.assertIn("boom", lines[0]) @@ -2100,8 +2100,8 @@ def test_ipv6_output(self): self.assertOutputStub(out, builder_id=ring.id) def test_default_show_removed(self): - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() ring = self.create_sample_ring() @@ -2146,8 +2146,8 @@ def test_default_show_removed(self): self.assertEqual(expected, mock_stdout.getvalue()) def test_default_sorted_output(self): - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() # Create a sample ring and remove/add some devices. now = time.time() @@ -2186,8 +2186,8 @@ def test_default_ringfile_check(self): self.create_sample_ring() # ring file not created - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() argv = ["", self.tmpfile] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2199,7 +2199,7 @@ def test_default_ringfile_check(self): argv = ["", self.tmpfile, "rebalance"] self.assertSystemExit(EXIT_SUCCESS, ringbuilder.main, argv) # ring file is up-to-date - mock_stdout = six.StringIO() + mock_stdout = io.StringIO() argv = ["", self.tmpfile] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2213,7 +2213,7 @@ def test_default_ringfile_check(self): argv = ["", self.tmpfile, "set_weight", "0", "--id", "3"] self.assertSystemExit(EXIT_SUCCESS, ringbuilder.main, argv) # ring file is obsolete after set_weight - mock_stdout = six.StringIO() + mock_stdout = io.StringIO() argv = ["", self.tmpfile] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2225,7 +2225,7 @@ def test_default_ringfile_check(self): argv = ["", self.tmpfile, "write_ring"] self.assertSystemExit(EXIT_SUCCESS, ringbuilder.main, argv) # ring file up-to-date again - mock_stdout = six.StringIO() + mock_stdout = io.StringIO() argv = ["", self.tmpfile] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2235,7 +2235,7 @@ def test_default_ringfile_check(self): # Break ring file e.g. just make it empty open('%s.ring.gz' % self.tmpfile, 'w').close() # ring file is invalid - mock_stdout = six.StringIO() + mock_stdout = io.StringIO() argv = ["", self.tmpfile] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2247,16 +2247,16 @@ def test_default_no_device_ring_without_exception(self): self.create_sample_ring() # remove devices from ring file - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() for device in ["d0", "d1", "d2", "d3"]: argv = ["", self.tmpfile, "remove", device] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): self.assertSystemExit(EXIT_SUCCESS, ringbuilder.main, argv) # default ring file without exception - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() argv = ["", self.tmpfile, "default"] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2281,8 +2281,8 @@ def test_empty_ring(self): self.create_sample_ring(empty=True) # default ring file without exception - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() argv = ["", self.tmpfile, "default"] with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): @@ -2515,7 +2515,7 @@ def test_rebalance_min_part_hours_not_passed(self): ring = RingBuilder.load(self.tmpfile) last_replica2part2dev = ring._replica2part2dev - mock_stdout = six.StringIO() + mock_stdout = io.StringIO() argv = ["", self.tmpfile, "rebalance", "3"] with mock.patch("sys.stdout", mock_stdout): self.assertSystemExit(EXIT_WARNING, ringbuilder.main, argv) @@ -2736,8 +2736,8 @@ def test_dispersion_command_recalculate(self): self.assertEqual(rb.version, old_version + 1) def test_use_ringfile_as_builderfile(self): - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() argv = ["", self.tmpfile, "rebalance", "3"], self.assertSystemExit(EXIT_SUCCESS, ringbuilder.main, argv) @@ -2810,8 +2810,8 @@ def tearDown(self): pass def run_srb(self, *argv): - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() srb_args = ["", self.tempfile] + [str(s) for s in argv] diff --git a/test/unit/cli/test_ringcomposer.py b/test/unit/cli/test_ringcomposer.py index 8183f7f89f..5ff7b4d062 100644 --- a/test/unit/cli/test_ringcomposer.py +++ b/test/unit/cli/test_ringcomposer.py @@ -10,6 +10,7 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. +import io import json import os @@ -17,7 +18,6 @@ import tempfile import unittest -import six from mock import mock from swift.cli import ringcomposer @@ -37,8 +37,8 @@ def tearDown(self): shutil.rmtree(self.tmpdir) def _run_composer(self, args): - mock_stdout = six.StringIO() - mock_stderr = six.StringIO() + mock_stdout = io.StringIO() + mock_stderr = io.StringIO() with mock.patch("sys.stdout", mock_stdout): with mock.patch("sys.stderr", mock_stderr): with self.assertRaises(SystemExit) as cm: diff --git a/test/unit/common/middleware/crypto/test_encrypter.py b/test/unit/common/middleware/crypto/test_encrypter.py index 5d77cdde89..0b95fd4552 100644 --- a/test/unit/common/middleware/crypto/test_encrypter.py +++ b/test/unit/common/middleware/crypto/test_encrypter.py @@ -21,7 +21,7 @@ import mock -from six.moves.urllib import parse as urlparse +import urllib.parse from swift.common.middleware.crypto import encrypter from swift.common.middleware.crypto.crypto_utils import ( CRYPTO_KEY_CALLBACK, Crypto) @@ -53,7 +53,7 @@ def _verify_user_metadata(self, req_hdrs, name, value, key): param = param.strip() self.assertTrue(param.startswith('swift_meta=')) actual_meta = json.loads( - urlparse.unquote_plus(param[len('swift_meta='):])) + urllib.parse.unquote_plus(param[len('swift_meta='):])) self.assertEqual(Crypto.cipher, actual_meta['cipher']) meta_iv = base64.b64decode(actual_meta['iv']) self.assertEqual(FAKE_IV, meta_iv) @@ -62,7 +62,7 @@ def _verify_user_metadata(self, req_hdrs, name, value, key): wsgi_to_bytes(enc_val)) # if there is any encrypted user metadata then this header should exist self.assertIn('X-Object-Transient-Sysmeta-Crypto-Meta', req_hdrs) - common_meta = json.loads(urlparse.unquote_plus( + common_meta = json.loads(urllib.parse.unquote_plus( req_hdrs['X-Object-Transient-Sysmeta-Crypto-Meta'])) self.assertDictEqual({'cipher': Crypto.cipher, 'key_id': {'v': 'fake', 'path': '/a/c/fake'}}, @@ -102,7 +102,7 @@ def test_PUT_req(self): # verify body crypto meta actual = req_hdrs['X-Object-Sysmeta-Crypto-Body-Meta'] - actual = json.loads(urlparse.unquote_plus(actual)) + actual = json.loads(urllib.parse.unquote_plus(actual)) self.assertEqual(Crypto().cipher, actual['cipher']) self.assertEqual(FAKE_IV, base64.b64decode(actual['iv'])) @@ -121,7 +121,7 @@ def test_PUT_req(self): req_hdrs['X-Object-Sysmeta-Crypto-Etag'].partition('; swift_meta=') # verify crypto_meta was appended to this etag self.assertTrue(etag_meta) - actual_meta = json.loads(urlparse.unquote_plus(etag_meta)) + actual_meta = json.loads(urllib.parse.unquote_plus(etag_meta)) self.assertEqual(Crypto().cipher, actual_meta['cipher']) # verify encrypted version of plaintext etag @@ -151,7 +151,7 @@ def test_PUT_req(self): crypto_meta_tag = 'swift_meta=' self.assertTrue(param.startswith(crypto_meta_tag), param) actual_meta = json.loads( - urlparse.unquote_plus(param[len(crypto_meta_tag):])) + urllib.parse.unquote_plus(param[len(crypto_meta_tag):])) self.assertEqual(Crypto().cipher, actual_meta['cipher']) self.assertEqual(fetch_crypto_keys()['id'], actual_meta['key_id']) @@ -282,7 +282,7 @@ def _test_PUT_with_other_footers(self, override_etag): encrypted_etag, _junk, etag_meta = \ req_hdrs['X-Object-Sysmeta-Crypto-Etag'].partition('; swift_meta=') self.assertTrue(etag_meta) - actual_meta = json.loads(urlparse.unquote_plus(etag_meta)) + actual_meta = json.loads(urllib.parse.unquote_plus(etag_meta)) self.assertEqual(Crypto().cipher, actual_meta['cipher']) self.assertEqual(ciphertext_etag, req_hdrs['Etag']) @@ -303,7 +303,7 @@ def _test_PUT_with_other_footers(self, override_etag): crypto_meta_tag = 'swift_meta=' self.assertTrue(param.startswith(crypto_meta_tag), param) actual_meta = json.loads( - urlparse.unquote_plus(param[len(crypto_meta_tag):])) + urllib.parse.unquote_plus(param[len(crypto_meta_tag):])) self.assertEqual(Crypto().cipher, actual_meta['cipher']) cont_key = fetch_crypto_keys()['container'] @@ -315,7 +315,7 @@ def _test_PUT_with_other_footers(self, override_etag): # verify body crypto meta actual = req_hdrs['X-Object-Sysmeta-Crypto-Body-Meta'] - actual = json.loads(urlparse.unquote_plus(actual)) + actual = json.loads(urllib.parse.unquote_plus(actual)) self.assertEqual(Crypto().cipher, actual['cipher']) self.assertEqual(FAKE_IV, base64.b64decode(actual['iv'])) @@ -374,7 +374,7 @@ def _test_PUT_with_etag_override_in_headers(self, override_etag): crypto_meta_tag = 'swift_meta=' self.assertTrue(param.startswith(crypto_meta_tag), param) actual_meta = json.loads( - urlparse.unquote_plus(param[len(crypto_meta_tag):])) + urllib.parse.unquote_plus(param[len(crypto_meta_tag):])) self.assertEqual(Crypto().cipher, actual_meta['cipher']) self.assertEqual(fetch_crypto_keys()['id'], actual_meta['key_id']) @@ -569,7 +569,7 @@ def __call__(self, env, start_response): crypto_meta_tag = 'swift_meta=' self.assertTrue(param.startswith(crypto_meta_tag), param) actual_meta = json.loads( - urlparse.unquote_plus(param[len(crypto_meta_tag):])) + urllib.parse.unquote_plus(param[len(crypto_meta_tag):])) self.assertEqual(Crypto().cipher, actual_meta['cipher']) self.assertEqual(fetch_crypto_keys()['id'], actual_meta['key_id']) diff --git a/test/unit/common/middleware/crypto/test_keymaster.py b/test/unit/common/middleware/crypto/test_keymaster.py index 882f88b550..54db3db266 100644 --- a/test/unit/common/middleware/crypto/test_keymaster.py +++ b/test/unit/common/middleware/crypto/test_keymaster.py @@ -20,7 +20,6 @@ import os import mock -import six import unittest from getpass import getuser @@ -147,10 +146,7 @@ def verify_keys_for_path(self, wsgi_path, expected_keys, key_id=None): self.assertIn('id', keys) id = keys.pop('id') path = swob.wsgi_to_str(wsgi_path) - if six.PY2: - self.assertEqual(path, id['path']) - else: - self.assertEqual(swob.str_to_wsgi(path), id['path']) + self.assertEqual(swob.str_to_wsgi(path), id['path']) self.assertEqual('2', id['v']) keys.pop('all_ids') self.assertListEqual(sorted(expected_keys), sorted(keys.keys()), @@ -189,10 +185,7 @@ def verify_v1_keys_for_path(self, wsgi_path, expected_keys, key_id=None): path = swob.wsgi_to_str(wsgi_path) if '//' in path: path = path[path.index('//') + 1:] - if six.PY2: - self.assertEqual(path, id['path']) - else: - self.assertEqual(swob.str_to_wsgi(path), id['path']) + self.assertEqual(swob.str_to_wsgi(path), id['path']) self.assertEqual('1', id['v']) keys.pop('all_ids') self.assertListEqual(sorted(expected_keys), sorted(keys.keys()), @@ -686,30 +679,20 @@ def mock_create_key(path, secret_id=None): container = u'\N{SNOWMAN}' obj = u'\N{SNOWFLAKE}' - if six.PY2: - container = container.encode('utf-8') - obj = obj.encode('utf-8') good_con_path = '/a/%s' % container good_path = '/a/%s/%s' % (container, obj) - if six.PY2: - mangled_con_path = ('/a/%s' % container).decode( - 'latin-1').encode('utf-8') - mangled_path = ('/a/%s/%s' % ( - container, obj)).decode('latin-1').encode('utf-8') - else: - mangled_con_path = ('/a/%s' % container).encode( - 'utf-8').decode('latin-1') - mangled_path = ('/a/%s/%s' % ( - container, obj)).encode('utf-8').decode('latin-1') + mangled_con_path = ('/a/%s' % container).encode( + 'utf-8').decode('latin-1') + mangled_path = ('/a/%s/%s' % ( + container, obj)).encode('utf-8').decode('latin-1') context = keymaster.KeyMasterContext(self.app, 'a', container, obj) for version in ('1', '2', '3'): with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': version, 'path': good_path}) - key_id_path = (good_path if version == '3' or six.PY2 - else mangled_path) + key_id_path = (good_path if version == '3' else mangled_path) expected_keys = { 'container': hmac.new(secrets[None], b'/a/\xe2\x98\x83', digestmod=hashlib.sha256).digest(), @@ -729,7 +712,7 @@ def mock_create_key(path, secret_id=None): with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': version, 'path': mangled_path}) - key_id_path = (good_path if six.PY2 else mangled_path) + key_id_path = mangled_path expected_keys = { 'container': hmac.new(secrets[None], b'/a/\xe2\x98\x83', digestmod=hashlib.sha256).digest(), diff --git a/test/unit/common/middleware/helpers.py b/test/unit/common/middleware/helpers.py index a3f77395ae..58e391420c 100644 --- a/test/unit/common/middleware/helpers.py +++ b/test/unit/common/middleware/helpers.py @@ -16,7 +16,7 @@ # This stuff can't live in test/unit/__init__.py due to its swob dependency. from collections import defaultdict, namedtuple -from six.moves.urllib import parse +from urllib import parse from swift.common import swob from swift.common.header_key_dict import HeaderKeyDict from swift.common.request_helpers import is_user_meta, \ @@ -49,8 +49,6 @@ def __next__(self): self.mark_read(self.key) raise - next = __next__ # for py2 - def close(self): self.mark_closed(self.key) diff --git a/test/unit/common/middleware/s3api/test_bucket.py b/test/unit/common/middleware/s3api/test_bucket.py index 3385aa9357..2534d8d363 100644 --- a/test/unit/common/middleware/s3api/test_bucket.py +++ b/test/unit/common/middleware/s3api/test_bucket.py @@ -17,8 +17,7 @@ import mock from hashlib import sha256 -import six -from six.moves.urllib.parse import quote, parse_qsl +from urllib.parse import quote, parse_qsl from swift.common import swob from swift.common.middleware.proxy_logging import ProxyLoggingMiddleware @@ -535,7 +534,7 @@ def test_bucket_GET(self): self.assertEqual('2011-01-05T02:19:15.000Z', o.find('./LastModified').text) expected = [ - (i[0].encode('utf-8') if six.PY2 else i[0], + (i[0], PFS_ETAG if i[0] == 'pfs-obj' else '"0-N"' if i[0] == 'slo' else '"0"') for i in self.objects @@ -646,12 +645,8 @@ def test_bucket_GET_is_truncated(self): status, headers, body = self.call_s3api(req) elem = fromstring(body, 'ListBucketResult') self.assertEqual(elem.find('./IsTruncated').text, 'true') - if six.PY2: - self.assertEqual(elem.find('./NextMarker').text, - u'but-\u062a/'.encode('utf-8')) - else: - self.assertEqual(elem.find('./NextMarker').text, - u'but-\u062a/') + self.assertEqual(elem.find('./NextMarker').text, + u'but-\u062a/') def test_bucket_GET_is_truncated_url_encoded(self): bucket_name = 'junk' @@ -1023,10 +1018,7 @@ def test_bucket_GET_with_versions_versioning_not_configured(self): self.assertEqual(elem.findall('./DeleteMarker'), []) versions = elem.findall('./Version') objects = list(self.objects) - if six.PY2: - expected = [v[0].encode('utf-8') for v in objects] - else: - expected = [v[0] for v in objects] + expected = [v[0] for v in objects] self.assertEqual([v.find('./Key').text for v in versions], expected) self.assertEqual([v.find('./IsLatest').text for v in versions], ['true' for v in objects]) @@ -1067,8 +1059,6 @@ def test_bucket_GET_with_versions(self): expected = [] for o in self.objects_list: name = o['name'] - if six.PY2: - name = name.encode('utf8') expected.append((name, 'true', 'null')) if name == 'rose': expected.append((name, 'false', '1')) @@ -1097,8 +1087,6 @@ def test_bucket_GET_with_versions_with_max_keys(self): expected = [] for o in self.objects_list[:5]: name = o['name'] - if six.PY2: - name = name.encode('utf8') expected.append((name, 'true', 'null')) if name == 'rose': expected.append((name, 'false', '1')) @@ -1265,7 +1253,7 @@ def test_bucket_GET_versions_with_version_id_marker(self): self.assertEqual(expected, discovered) expected = [ ('lily', 'true', 'null'), - (b'lily-\xd8\xaa', 'true', 'null'), + ('lily-\u062a', 'true', 'null'), ('mu', 'true', 'null'), ('pfs-obj', 'true', 'null'), ('rose', 'true', 'null'), @@ -1275,10 +1263,6 @@ def test_bucket_GET_versions_with_version_id_marker(self): ('with space', 'true', 'null'), ('with%20space', 'true', 'null'), ] - if not six.PY2: - item = list(expected[1]) - item[0] = item[0].decode('utf8') - expected[1] = tuple(item) discovered = [ tuple(e.find('./%s' % key).text for key in ( diff --git a/test/unit/common/middleware/s3api/test_etree.py b/test/unit/common/middleware/s3api/test_etree.py index dd8e9f80ee..fea608e35b 100644 --- a/test/unit/common/middleware/s3api/test_etree.py +++ b/test/unit/common/middleware/s3api/test_etree.py @@ -15,8 +15,6 @@ import unittest -import six - from swift.common.middleware.s3api import etree @@ -67,10 +65,7 @@ def test_fromstring_with_nonascii_text(self): b'\xef\xbc\xa1' elem = etree.fromstring(input_str) text = elem.find('FOO').text - if six.PY2: - self.assertEqual(text, b'\xef\xbc\xa1') - else: - self.assertEqual(text, b'\xef\xbc\xa1'.decode('utf8')) + self.assertEqual(text, b'\xef\xbc\xa1'.decode('utf8')) self.assertIsInstance(text, str) diff --git a/test/unit/common/middleware/s3api/test_multi_upload.py b/test/unit/common/middleware/s3api/test_multi_upload.py index 81e148cdf3..e520cec6ea 100644 --- a/test/unit/common/middleware/s3api/test_multi_upload.py +++ b/test/unit/common/middleware/s3api/test_multi_upload.py @@ -20,7 +20,7 @@ import os import time import unittest -from six.moves.urllib.parse import parse_qs, quote, quote_plus +from urllib.parse import parse_qs, quote, quote_plus from swift.common import swob from swift.common.swob import Request diff --git a/test/unit/common/middleware/s3api/test_obj.py b/test/unit/common/middleware/s3api/test_obj.py index 1f1da8302c..86f4085209 100644 --- a/test/unit/common/middleware/s3api/test_obj.py +++ b/test/unit/common/middleware/s3api/test_obj.py @@ -22,7 +22,6 @@ from os.path import join import time from mock import patch -import six import json from swift.common import swob @@ -693,9 +692,8 @@ def test_object_PUT_error(self): def test_object_PUT(self): etag = self.response_headers['etag'] - content_md5 = binascii.b2a_base64(binascii.a2b_hex(etag)).strip() - if not six.PY2: - content_md5 = content_md5.decode('ascii') + content_md5 = binascii.b2a_base64( + binascii.a2b_hex(etag)).strip().decode('ascii') req = Request.blank( '/bucket/object', @@ -724,9 +722,8 @@ def test_object_PUT_bad_hash(self): 'Unprocessable Entity') bad_etag = md5(b'not-same-content').hexdigest() - content_md5 = binascii.b2a_base64(binascii.a2b_hex(bad_etag)).strip() - if not six.PY2: - content_md5 = content_md5.decode('ascii') + content_md5 = binascii.b2a_base64( + binascii.a2b_hex(bad_etag)).strip().decode('ascii') req = Request.blank( '/bucket/object', @@ -747,9 +744,8 @@ def test_object_PUT_bad_hash(self): def test_object_PUT_quota_exceeded(self): etag = self.response_headers['etag'] - content_md5 = binascii.b2a_base64(binascii.a2b_hex(etag)).strip() - if not six.PY2: - content_md5 = content_md5.decode('ascii') + content_md5 = binascii.b2a_base64( + binascii.a2b_hex(etag)).strip().decode('ascii') self.swift.register( 'PUT', '/v1/AUTH_test/bucket/object', @@ -1347,9 +1343,8 @@ def test_object_PUT_with_version(self): self.assertEqual(headers['x-copy-from'], '/bucket/src_obj') def test_object_PUT_headers(self): - content_md5 = binascii.b2a_base64(binascii.a2b_hex(self.etag)).strip() - if not six.PY2: - content_md5 = content_md5.decode('ascii') + content_md5 = binascii.b2a_base64(binascii.a2b_hex( + self.etag)).strip().decode('ascii') self.swift.register('HEAD', '/v1/AUTH_test/some/source', swob.HTTPOk, {'last-modified': self.last_modified}, diff --git a/test/unit/common/middleware/s3api/test_s3api.py b/test/unit/common/middleware/s3api/test_s3api.py index c32b9f0743..c72fe060b1 100644 --- a/test/unit/common/middleware/s3api/test_s3api.py +++ b/test/unit/common/middleware/s3api/test_s3api.py @@ -22,9 +22,8 @@ import mock import requests import json -import six from paste.deploy import loadwsgi -from six.moves.urllib.parse import unquote, quote +from urllib.parse import unquote, quote import swift.common.middleware.s3api from swift.common.middleware.proxy_logging import ProxyLoggingMiddleware @@ -747,8 +746,7 @@ def test_non_ascii_user(self): _, _, headers = self.swift.calls_with_headers[-1] self.assertEqual(req.environ['s3api.auth_details'], { - 'access_key': (u'test:\N{SNOWMAN}'.encode('utf-8') if six.PY2 - else u'test:\N{SNOWMAN}'), + 'access_key': u'test:\N{SNOWMAN}', 'signature': 'sig', 'string_to_sign': b'\n'.join([ b'PUT', b'', b'', date_header.encode('ascii'), @@ -782,9 +780,7 @@ def test_object_create_bad_md5_unreadable(self): def test_object_create_bad_md5_too_short(self): too_short_digest = md5(b'hey', usedforsecurity=False).digest()[:-1] - md5_str = base64.b64encode(too_short_digest).strip() - if not six.PY2: - md5_str = md5_str.decode('ascii') + md5_str = base64.b64encode(too_short_digest).strip().decode('ascii') req = Request.blank( '/bucket/object', environ={'REQUEST_METHOD': 'PUT', @@ -800,9 +796,8 @@ def test_object_create_bad_md5_too_short(self): def test_object_create_bad_md5_bad_padding(self): too_short_digest = md5(b'hey', usedforsecurity=False).digest() - md5_str = base64.b64encode(too_short_digest).strip(b'=\n') - if not six.PY2: - md5_str = md5_str.decode('ascii') + md5_str = base64.b64encode(too_short_digest).strip( + b'=\n').decode('ascii') req = Request.blank( '/bucket/object', environ={'REQUEST_METHOD': 'PUT', @@ -819,9 +814,7 @@ def test_object_create_bad_md5_bad_padding(self): def test_object_create_bad_md5_too_long(self): too_long_digest = md5( b'hey', usedforsecurity=False).digest() + b'suffix' - md5_str = base64.b64encode(too_long_digest).strip() - if not six.PY2: - md5_str = md5_str.decode('ascii') + md5_str = base64.b64encode(too_long_digest).strip().decode('ascii') req = Request.blank( '/bucket/object', environ={'REQUEST_METHOD': 'PUT', diff --git a/test/unit/common/middleware/s3api/test_s3token.py b/test/unit/common/middleware/s3api/test_s3token.py index 6a467bd3a0..507b6881fb 100644 --- a/test/unit/common/middleware/s3api/test_s3token.py +++ b/test/unit/common/middleware/s3api/test_s3token.py @@ -22,7 +22,7 @@ import mock import requests from requests_mock.contrib import fixture as rm_fixture -from six.moves import urllib +import urllib.parse from swift.common.middleware.s3api import s3token from swift.common.swob import Request, Response diff --git a/test/unit/common/middleware/test_bulk.py b/test/unit/common/middleware/test_bulk.py index 5b3a324baf..7d1e056f08 100644 --- a/test/unit/common/middleware/test_bulk.py +++ b/test/unit/common/middleware/test_bulk.py @@ -21,7 +21,6 @@ import tarfile import zlib import mock -import six from io import BytesIO from shutil import rmtree from tempfile import mkdtemp @@ -50,9 +49,8 @@ def __call__(self, env, start_response): self.calls += 1 if env.get('swift.source') in ('EA', 'BD'): assert not env.get('swift.proxy_access_log_made') - if not six.PY2: - # Check that it's valid WSGI - assert all(0 <= ord(c) <= 255 for c in env['PATH_INFO']) + # Check that it's valid WSGI + assert all(0 <= ord(c) <= 255 for c in env['PATH_INFO']) if env['REQUEST_METHOD'] == 'PUT': self.put_paths.append(env['PATH_INFO']) @@ -116,8 +114,6 @@ def build_dir_tree(start_path, tree_obj): os.mkdir(dir_path) build_dir_tree(dir_path, obj) return - if six.PY2 and isinstance(tree_obj, six.text_type): - tree_obj = tree_obj.encode('utf8') if isinstance(tree_obj, str): obj_path = os.path.join(start_path, tree_obj) with open(obj_path, 'w+') as tree_file: @@ -127,16 +123,10 @@ def build_dir_tree(start_path, tree_obj): def build_tar_tree(tar, start_path, tree_obj, base_path=''): - if six.PY2: - if isinstance(start_path, six.text_type): - start_path = start_path.encode('utf8') - if isinstance(tree_obj, six.text_type): - tree_obj = tree_obj.encode('utf8') - else: - if isinstance(start_path, bytes): - start_path = start_path.decode('utf8', 'surrogateescape') - if isinstance(tree_obj, bytes): - tree_obj = tree_obj.decode('utf8', 'surrogateescape') + if isinstance(start_path, bytes): + start_path = start_path.decode('utf8', 'surrogateescape') + if isinstance(tree_obj, bytes): + tree_obj = tree_obj.decode('utf8', 'surrogateescape') if isinstance(tree_obj, list): for obj in tree_obj: @@ -144,9 +134,7 @@ def build_tar_tree(tar, start_path, tree_obj, base_path=''): return if isinstance(tree_obj, dict): for dir_name, obj in tree_obj.items(): - if six.PY2 and isinstance(dir_name, six.text_type): - dir_name = dir_name.encode('utf8') - elif not six.PY2 and isinstance(dir_name, bytes): + if isinstance(dir_name, bytes): dir_name = dir_name.decode('utf8', 'surrogateescape') dir_path = os.path.join(start_path, dir_name) tar_info = tarfile.TarInfo(dir_path[len(base_path):]) @@ -196,8 +184,7 @@ def test_extract_metadata(self): # With GNU tar 1.27.1 or later (possibly 1.27 as well), a file with # extended attribute user.thingy = dingy gets put into the tarfile # with pax_headers containing key/value pair - # (SCHILY.xattr.user.thingy, dingy), both unicode strings (py2: type - # unicode, not type str). + # (SCHILY.xattr.user.thingy, dingy), both unicode strings # # With BSD tar (libarchive), you get key/value pair # (LIBARCHIVE.xattr.user.thingy, dingy), which strikes me as diff --git a/test/unit/common/middleware/test_copy.py b/test/unit/common/middleware/test_copy.py index ef890761b6..a9010467fb 100644 --- a/test/unit/common/middleware/test_copy.py +++ b/test/unit/common/middleware/test_copy.py @@ -16,7 +16,7 @@ import mock import unittest -from six.moves import urllib +import urllib.parse from swift.common import swob from swift.common.middleware import copy diff --git a/test/unit/common/middleware/test_domain_remap.py b/test/unit/common/middleware/test_domain_remap.py index 317a20a440..61d549bc06 100644 --- a/test/unit/common/middleware/test_domain_remap.py +++ b/test/unit/common/middleware/test_domain_remap.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six import unittest from swift.common.swob import Request, HTTPMovedPermanently @@ -25,11 +24,7 @@ class FakeApp(object): def __call__(self, env, start_response): start_response('200 OK', []) - if six.PY2: - return [env['PATH_INFO']] - else: - print(env) - return [env['PATH_INFO'].encode('latin-1')] + return [env['PATH_INFO'].encode('latin-1')] class RedirectSlashApp(object): diff --git a/test/unit/common/middleware/test_formpost.py b/test/unit/common/middleware/test_formpost.py index f809e5efc7..522f000468 100644 --- a/test/unit/common/middleware/test_formpost.py +++ b/test/unit/common/middleware/test_formpost.py @@ -19,12 +19,8 @@ import unittest from time import time -import six -if six.PY3: - from unittest import mock -else: - import mock -from io import BytesIO +from unittest import mock +from io import BytesIO, StringIO from swift.common.swob import Request, Response, wsgi_quote from swift.common.middleware import tempauth, formpost @@ -38,9 +34,7 @@ def hmac_msg(path, redirect, max_file_size, max_file_count, expires): msg = '%s\n%s\n%s\n%s\n%s' % ( path, redirect, max_file_size, max_file_count, expires) - if six.PY3: - msg = msg.encode('utf-8') - return msg + return msg.encode('utf-8') class FakeApp(object): @@ -175,18 +169,13 @@ def _make_sig_env_body(self, path, redirect, max_file_size, max_file_count, expires, key, user_agent=True, algorithm='sha512', prefix=True): alg_name = algorithm - if six.PY2: - algorithm = getattr(hashlib, algorithm) mac = hmac.new( key, hmac_msg(path, redirect, max_file_size, max_file_count, expires), algorithm) if prefix: - if six.PY2: - sig = alg_name + ':' + base64.b64encode(mac.digest()) - else: - sig = alg_name + ':' + base64.b64encode( - mac.digest()).decode('ascii') + sig = alg_name + ':' + base64.b64encode( + mac.digest()).decode('ascii') else: sig = mac.hexdigest() body = [ @@ -231,9 +220,8 @@ def _make_sig_env_body(self, path, redirect, max_file_size, max_file_count, '------WebKitFormBoundaryNcxTqxSlX7t4TDkR--', '', ] - if six.PY3: - body = [line.encode('utf-8') for line in body] - wsgi_errors = six.StringIO() + body = [line.encode('utf-8') for line in body] + wsgi_errors = StringIO() env = { 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=----WebKitFormBoundaryNcxTqxSlX7t4TDkR', @@ -360,10 +348,8 @@ def test_safari(self): '------WebKitFormBoundaryNcxTqxSlX7t4TDkR--', '', ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - wsgi_input = BytesIO(wsgi_input) - wsgi_errors = six.StringIO() + wsgi_input = BytesIO(wsgi_input.encode('utf-8')) + wsgi_errors = StringIO() env = { 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=----WebKitFormBoundaryNcxTqxSlX7t4TDkR', @@ -478,10 +464,8 @@ def test_firefox(self): '-----------------------------168072824752491622650073--', '' ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - wsgi_input = BytesIO(wsgi_input) - wsgi_errors = six.StringIO() + wsgi_input = BytesIO(wsgi_input.encode('utf-8')) + wsgi_errors = StringIO() env = { 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=---------------------------168072824752491622650073', @@ -595,10 +579,8 @@ def test_chrome(self): '------WebKitFormBoundaryq3CFxUjfsDMu8XsA--', '' ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - wsgi_input = BytesIO(wsgi_input) - wsgi_errors = six.StringIO() + wsgi_input = BytesIO(wsgi_input.encode('utf-8')) + wsgi_errors = StringIO() env = { 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=----WebKitFormBoundaryq3CFxUjfsDMu8XsA', @@ -715,10 +697,8 @@ def test_explorer(self): '-----------------------------7db20d93017c--', '' ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - wsgi_input = BytesIO(wsgi_input) - wsgi_errors = six.StringIO() + wsgi_input = BytesIO(wsgi_input.encode('utf-8')) + wsgi_errors = StringIO() env = { 'CONTENT_TYPE': 'multipart/form-data; ' 'boundary=---------------------------7db20d93017c', @@ -782,8 +762,6 @@ def start_response(s, h, e=None): def test_curl_with_unicode(self): key = b'abc' path = u'/v1/AUTH_test/container/let_it_\N{SNOWFLAKE}/' - if six.PY2: - path = path.encode('utf-8') redirect = 'http://brim.net' max_file_size = 1024 max_file_count = 10 @@ -832,11 +810,9 @@ def test_curl_with_unicode(self): '', '--------------------------dea19ac8502ca805--', '' - ]) - if not six.PY2: - wsgi_input = wsgi_input.encode('latin1') + ]).encode('latin1') wsgi_input = BytesIO(wsgi_input) - wsgi_errors = six.StringIO() + wsgi_errors = StringIO() env = { 'CONTENT_LENGTH': str(len(wsgi_input.getvalue())), 'CONTENT_TYPE': 'multipart/form-data; ' @@ -1166,9 +1142,7 @@ def test_truncated_attr_value(self): '------WebKitFormBoundaryNcxTqxSlX7t4TDkR--', '', ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - env['wsgi.input'] = BytesIO(wsgi_input) + env['wsgi.input'] = BytesIO(wsgi_input.encode('utf-8')) env['swift.infocache'][get_cache_key('AUTH_test')] = ( self._fake_cache_env('AUTH_test', [key])) env['swift.infocache'][get_cache_key( @@ -1238,9 +1212,7 @@ def test_no_file_to_process(self): '------WebKitFormBoundaryNcxTqxSlX7t4TDkR--', '', ]) - if six.PY3: - wsgi_input = wsgi_input.encode('utf-8') - env['wsgi.input'] = BytesIO(wsgi_input) + env['wsgi.input'] = BytesIO(wsgi_input.encode('utf-8')) env['swift.infocache'][get_cache_key('AUTH_test')] = ( self._fake_cache_env('AUTH_test', [key])) env['swift.infocache'][get_cache_key( @@ -1958,9 +1930,8 @@ def test_x_delete_at(self): '', str(delete_at), ] - if six.PY3: - x_delete_body_part = [line.encode('utf-8') - for line in x_delete_body_part] + x_delete_body_part = [line.encode('utf-8') + for line in x_delete_body_part] key = b'abc' sig, env, body = self._make_sig_env_body( '/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key) @@ -2005,9 +1976,8 @@ def test_x_delete_at_not_int(self): '', str(delete_at), ] - if six.PY3: - x_delete_body_part = [line.encode('utf-8') - for line in x_delete_body_part] + x_delete_body_part = [line.encode('utf-8') + for line in x_delete_body_part] key = b'abc' sig, env, body = self._make_sig_env_body( '/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key) @@ -2043,9 +2013,8 @@ def test_x_delete_after(self): '', str(delete_after), ] - if six.PY3: - x_delete_body_part = [line.encode('utf-8') - for line in x_delete_body_part] + x_delete_body_part = [line.encode('utf-8') + for line in x_delete_body_part] key = b'abc' sig, env, body = self._make_sig_env_body( '/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key) @@ -2090,9 +2059,8 @@ def test_x_delete_after_not_int(self): '', str(delete_after), ] - if six.PY3: - x_delete_body_part = [line.encode('utf-8') - for line in x_delete_body_part] + x_delete_body_part = [line.encode('utf-8') + for line in x_delete_body_part] key = b'abc' sig, env, body = self._make_sig_env_body( '/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key) @@ -2131,8 +2099,7 @@ def test_global_content_type_encoding(self): '', 'text/html', ] - if six.PY3: - body_part = [line.encode('utf-8') for line in body_part] + body_part = [line.encode('utf-8') for line in body_part] key = b'abc' sig, env, body = self._make_sig_env_body( @@ -2231,8 +2198,7 @@ def test_multiple_content_type_encoding(self): '', '{"four": 4}\n', ] - if six.PY3: - body_part = [line.encode('utf-8') for line in body_part] + body_part = [line.encode('utf-8') for line in body_part] key = b'abc' sig, env, body = self._make_sig_env_body( diff --git a/test/unit/common/middleware/test_object_versioning.py b/test/unit/common/middleware/test_object_versioning.py index c21fe4a91e..c128d597e1 100644 --- a/test/unit/common/middleware/test_object_versioning.py +++ b/test/unit/common/middleware/test_object_versioning.py @@ -19,8 +19,7 @@ import time import mock import unittest -import six -from six.moves import urllib +import urllib.parse from swift.common import swob, utils from swift.common.middleware import versioned_writes, copy, symlink, \ listing_formats @@ -142,11 +141,6 @@ def assertRequestEqual(self, req, other): self.assertEqual(req.method, other.method) self.assertEqual(req.path, other.path) - def str_to_wsgi(self, native_str): - if six.PY2 and isinstance(native_str, six.text_type): - native_str = native_str.encode('utf8') - return str_to_wsgi(native_str) - def build_container_name(self, cont): return get_reserved_name('versions', cont) @@ -156,14 +150,14 @@ def build_object_name(self, obj, version): def build_symlink_path(self, cont, obj, version): cont = self.build_container_name(cont) obj = self.build_object_name(obj, version) - return wsgi_quote(self.str_to_wsgi("%s/%s" % (cont, obj))) + return wsgi_quote(str_to_wsgi("%s/%s" % (cont, obj))) def build_versions_path(self, acc='a', cont='c', obj=None, version=None): cont = self.build_container_name(cont) if not obj: - return self.str_to_wsgi("/v1/%s/%s" % (acc, cont)) + return str_to_wsgi("/v1/%s/%s" % (acc, cont)) obj = self.build_object_name(obj, version) - return self.str_to_wsgi("/v1/%s/%s/%s" % (acc, cont, obj)) + return str_to_wsgi("/v1/%s/%s/%s" % (acc, cont, obj)) class ObjectVersioningTestCase(ObjectVersioningBaseTestCase): @@ -188,7 +182,7 @@ def test_put_container(self): self.assertEqual('/v1/a/c', path) self.assertIn(SYSMETA_VERSIONS_CONT, headers) self.assertEqual(headers[SYSMETA_VERSIONS_CONT], - wsgi_quote(self.str_to_wsgi( + wsgi_quote(str_to_wsgi( self.build_container_name('c')))) self.assertIn(SYSMETA_VERSIONS_ENABLED, headers) self.assertEqual(headers[SYSMETA_VERSIONS_ENABLED], 'True') @@ -229,7 +223,7 @@ def test_same_policy_as_existing_container(self): self.assertEqual('/v1/a/c', path) self.assertIn(SYSMETA_VERSIONS_CONT, headers) self.assertEqual(headers[SYSMETA_VERSIONS_CONT], - wsgi_quote(self.str_to_wsgi( + wsgi_quote(str_to_wsgi( self.build_container_name('c')))) self.assertIn(SYSMETA_VERSIONS_ENABLED, headers) self.assertEqual(headers[SYSMETA_VERSIONS_ENABLED], 'True') @@ -309,7 +303,7 @@ def test_same_policy_as_primary_container(self): self.assertEqual('/v1/a/c', path) self.assertIn(SYSMETA_VERSIONS_CONT, headers) self.assertEqual(headers[SYSMETA_VERSIONS_CONT], - wsgi_quote(self.str_to_wsgi( + wsgi_quote(str_to_wsgi( self.build_container_name('c')))) self.assertIn(SYSMETA_VERSIONS_ENABLED, headers) self.assertEqual(headers[SYSMETA_VERSIONS_ENABLED], 'True') @@ -2376,7 +2370,7 @@ def test_listing_translation_utf8(self): self.app.register( 'GET', '/v1/a/\xe2\x98\x83-test', swob.HTTPOk, {SYSMETA_VERSIONS_CONT: wsgi_quote( - self.str_to_wsgi(self.build_container_name( + str_to_wsgi(self.build_container_name( u'\N{COMET}-container'))), SYSMETA_VERSIONS_ENABLED: True}, json.dumps(listing_body).encode('utf8')) @@ -3184,7 +3178,7 @@ def test_list_containers(self): params = { 'format': 'json', - 'prefix': self.str_to_wsgi(get_reserved_name('versions')), + 'prefix': str_to_wsgi(get_reserved_name('versions')), } path = '/v1/a?%s' % urllib.parse.urlencode(params) @@ -3250,7 +3244,7 @@ def test_list_containers_prefix(self): json.dumps(listing_body).encode('utf8')) path = '/v1/a?%s' % urllib.parse.urlencode({ - 'format': 'json', 'prefix': self.str_to_wsgi( + 'format': 'json', 'prefix': str_to_wsgi( self.build_container_name('versioned-'))}) self.app.register( @@ -3325,7 +3319,7 @@ def test_list_orphan_hidden_containers(self): params = { 'format': 'json', - 'prefix': self.str_to_wsgi(get_reserved_name('versions')), + 'prefix': str_to_wsgi(get_reserved_name('versions')), } path = '/v1/a?%s' % urllib.parse.urlencode(params) diff --git a/test/unit/common/middleware/test_proxy_logging.py b/test/unit/common/middleware/test_proxy_logging.py index ac40a2fc59..f3543685be 100644 --- a/test/unit/common/middleware/test_proxy_logging.py +++ b/test/unit/common/middleware/test_proxy_logging.py @@ -20,8 +20,7 @@ from io import BytesIO from logging.handlers import SysLogHandler -import six -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.common.utils import get_swift_logger, split_path from swift.common.statsd_client import StatsdClient @@ -42,7 +41,7 @@ def __init__(self, body=None, response_str='200 OK', policy_idx='0', chunked=False, environ_updates=None): if body is None: body = [b'FAKE APP'] - elif isinstance(body, six.binary_type): + elif isinstance(body, bytes): body = [body] self.body = body @@ -919,8 +918,6 @@ def __next__(self): result, self.msg = self.msg, b'' return result - next = __next__ # py2 - body = CloseableBody() app = proxy_logging.ProxyLoggingMiddleware(FakeApp(body), {}) req = Request.blank('/', environ={'REQUEST_METHOD': 'GET', diff --git a/test/unit/common/middleware/test_recon.py b/test/unit/common/middleware/test_recon.py index 293d8b1517..8da39c61d3 100644 --- a/test/unit/common/middleware/test_recon.py +++ b/test/unit/common/middleware/test_recon.py @@ -90,8 +90,6 @@ def __next__(self): self.index += 1 return line - next = __next__ - def read(self, *args, **kwargs): self.read_calls.append((args, kwargs)) try: diff --git a/test/unit/common/middleware/test_slo.py b/test/unit/common/middleware/test_slo.py index a6b8dc7eb0..89b49b9044 100644 --- a/test/unit/common/middleware/test_slo.py +++ b/test/unit/common/middleware/test_slo.py @@ -21,10 +21,8 @@ import unittest import string -import mock -from mock import patch +from unittest.mock import patch -import six from io import BytesIO from swift.common import swob, registry @@ -2503,10 +2501,8 @@ def test_get_raw_manifest(self): 'path': '/gettest/not_checked'}, {'etag': md5hex(md5hex("fizz") + md5hex("buzz")), 'size_bytes': '2099', - 'path': '/gettest/made_up'}], sort_keys=True) + 'path': '/gettest/made_up'}], sort_keys=True).encode('utf8') expected_etag = md5hex(expected_body) - if six.PY3: - expected_body = expected_body.encode('utf-8') self.assertEqual(body, expected_body) self.assertEqual(status, '200 OK') @@ -2829,8 +2825,7 @@ def test_multiple_ranges_get_manifest(self): self.assertEqual(ct, 'multipart/byteranges') boundary = params.get('boundary') self.assertTrue(boundary is not None) - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = boundary.encode('utf-8') self.assertEqual(len(body), int(headers['Content-Length'])) # this is a multi-range resp @@ -2910,8 +2905,7 @@ def test_multiple_ranges_including_suffix_get_manifest(self): self.assertEqual(ct, 'multipart/byteranges') boundary = params.get('boundary') self.assertTrue(boundary is not None) - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = boundary.encode('utf-8') got_mime_docs = [] for mime_doc_fh in iter_multipart_mime_documents( @@ -3086,11 +3080,8 @@ def test_old_swift_range_get_beyond_manifest(self): self.assertEqual(headers['X-Manifest-Etag'], self.manifest_big_man_json_md5) self.assertEqual(int(headers['Content-Length']), len(body)) - if six.PY3: - count_e = sum(1 if x == 'e' else 0 - for x in body.decode('ascii', errors='replace')) - else: - count_e = sum(1 if x == 'e' else 0 for x in body) + count_e = sum(1 if x == 'e' else 0 + for x in body.decode('ascii', errors='replace')) self.assertEqual(count_e, 100000) self.assertEqual(len(body) - count_e, 0) @@ -3424,10 +3415,7 @@ def test_range_get_manifest_unsatisfiable(self): def test_get_segment_with_non_ascii_path(self): segment_body = u"a møøse once bit my sister".encode("utf-8") segment_etag = md5(segment_body, usedforsecurity=False).hexdigest() - if six.PY2: - path = u'/v1/AUTH_test/ünicode/öbject-segment'.encode('utf-8') - else: - path = str_to_wsgi(u'/v1/AUTH_test/ünicode/öbject-segment') + path = str_to_wsgi(u'/v1/AUTH_test/ünicode/öbject-segment') self.app.register( 'GET', path, swob.HTTPOk, {'Content-Length': str(len(segment_body)), @@ -3438,10 +3426,7 @@ def test_get_segment_with_non_ascii_path(self): 'hash': segment_etag, 'content_type': 'text/plain', 'bytes': len(segment_body)}]) - if six.PY2: - path = u'/v1/AUTH_test/ünicode/manifest'.encode('utf-8') - else: - path = str_to_wsgi(u'/v1/AUTH_test/ünicode/manifest') + path = str_to_wsgi(u'/v1/AUTH_test/ünicode/manifest') self.app.register( 'GET', path, swob.HTTPOk, {'Content-Type': 'application/json', @@ -3746,9 +3731,8 @@ def __init__(self, inner_iter): def __iter__(self): return self - def next(self): + def __next__(self): return next(self.inner_iter) - __next__ = next def close(self): leaks[0] -= 1 @@ -4110,21 +4094,13 @@ def test_invalid_json_submanifest(self): self.assertEqual('200 OK', status) self.assertEqual(body, b'aaaaa') - lines = self.slo.logger.get_lines_for_level('error') - self.assertEqual(lines, [ - mock.ANY, + self.assertEqual(self.slo.logger.get_lines_for_level('error'), [ + 'Unable to load SLO manifest: ' + 'Expecting value: line 1 column 2 (char 1)', 'while fetching /v1/AUTH_test/gettest/manifest-abcd, ' 'JSON-decoding of submanifest /v1/AUTH_test/gettest/manifest-bc ' 'failed with 500 Internal Error' ]) - self.assertIn(lines[0], [ - # py2 - 'Unable to load SLO manifest: ' - 'No JSON object could be decoded', - # py3 - 'Unable to load SLO manifest: ' - 'Expecting value: line 1 column 2 (char 1)', - ]) def test_mismatched_etag(self): self._setup_manifest('a-b-badetag-c', [ @@ -6627,9 +6603,7 @@ def test_non_slo_multi_range_passthrough(self): self.assertEqual(ct, 'multipart/byteranges') params = dict(params) - boundary = params.get('boundary') - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = params.get('boundary').encode('utf-8') self.assertEqual(len(body), int(headers['Content-Length'])) @@ -6669,9 +6643,7 @@ def test_non_slo_multi_range_partially_satisfiable_passthrough(self): self.assertEqual(ct, 'multipart/byteranges') params = dict(params) - boundary = params.get('boundary') - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = params.get('boundary').encode('utf-8') self.assertEqual(len(body), int(headers['Content-Length'])) @@ -6722,9 +6694,7 @@ def test_non_slo_multi_range_starting_beyond_multipart_resp_length(self): self.assertEqual(ct, 'multipart/byteranges') params = dict(params) - boundary = params.get('boundary') - if six.PY3: - boundary = boundary.encode('utf-8') + boundary = params.get('boundary').encode('utf-8') self.assertEqual(len(body), int(headers['Content-Length'])) diff --git a/test/unit/common/middleware/test_staticweb.py b/test/unit/common/middleware/test_staticweb.py index 70fa214f6d..4e893f27b5 100644 --- a/test/unit/common/middleware/test_staticweb.py +++ b/test/unit/common/middleware/test_staticweb.py @@ -17,7 +17,7 @@ import unittest import mock -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from swift.common.swob import Request, Response, HTTPUnauthorized from swift.common.middleware import staticweb diff --git a/test/unit/common/middleware/test_symlink.py b/test/unit/common/middleware/test_symlink.py index 35e967c377..2d9754d4ab 100644 --- a/test/unit/common/middleware/test_symlink.py +++ b/test/unit/common/middleware/test_symlink.py @@ -19,7 +19,7 @@ import json import mock -from six.moves.urllib.parse import parse_qs +from urllib.parse import parse_qs from swift.common import swob from swift.common.middleware import symlink, copy, versioned_writes, \ listing_formats diff --git a/test/unit/common/middleware/test_tempauth.py b/test/unit/common/middleware/test_tempauth.py index 5ed83953f9..c1e63ef0f7 100644 --- a/test/unit/common/middleware/test_tempauth.py +++ b/test/unit/common/middleware/test_tempauth.py @@ -19,8 +19,7 @@ from base64 import b64encode as _b64encode from time import time -import six -from six.moves.urllib.parse import quote, urlparse +from urllib.parse import quote, urlparse from swift.common.middleware import tempauth as auth from swift.common.middleware.acl import format_acl from swift.common.swob import Request, Response, bytes_to_wsgi @@ -311,10 +310,6 @@ def test_auth_with_s3api_unicode_authorization_good(self): local_app = FakeApp() conf = {u'user_t\u00e9st_t\u00e9ster': u'p\u00e1ss .admin'} access_key = u't\u00e9st:t\u00e9ster' - if six.PY2: - conf = {k.encode('utf8'): v.encode('utf8') - for k, v in conf.items()} - access_key = access_key.encode('utf8') local_auth = auth.filter_factory(conf)(local_app) req = self._make_request('/v1/t\xc3\xa9st:t\xc3\xa9ster', environ={ 's3api.auth_details': { @@ -1024,9 +1019,6 @@ def test_auth_scheme(self): def test_successful_token_unicode_user(self): app = FakeApp(iter(NO_CONTENT_RESP * 2)) conf = {u'user_t\u00e9st_t\u00e9ster': u'p\u00e1ss .admin'} - if six.PY2: - conf = {k.encode('utf8'): v.encode('utf8') - for k, v in conf.items()} ath = auth.filter_factory(conf)(app) quoted_acct = quote(u'/v1/AUTH_t\u00e9st'.encode('utf8')) memcache = FakeMemcache() diff --git a/test/unit/common/middleware/test_tempurl.py b/test/unit/common/middleware/test_tempurl.py index 2e2ff0727f..32031cc538 100644 --- a/test/unit/common/middleware/test_tempurl.py +++ b/test/unit/common/middleware/test_tempurl.py @@ -34,8 +34,7 @@ import mock import unittest import hashlib -import six -from six.moves.urllib.parse import quote +from urllib.parse import quote from time import time, strftime, gmtime from swift.common.middleware import tempauth, tempurl, proxy_logging @@ -134,7 +133,7 @@ def assert_valid_sig(self, expires, path, keys, sig, environ=None, prefix=None): if not environ: environ = {} - if six.PY3 and isinstance(sig, six.binary_type): + if isinstance(sig, bytes): sig = sig.decode('utf-8') environ['QUERY_STRING'] = 'temp_url_sig=%s&temp_url_expires=%s' % ( sig.replace('+', '%2B'), expires) diff --git a/test/unit/common/ring/test_builder.py b/test/unit/common/ring/test_builder.py index 3a9c86e877..65ec32e67d 100644 --- a/test/unit/common/ring/test_builder.py +++ b/test/unit/common/ring/test_builder.py @@ -19,7 +19,7 @@ import operator import os import unittest -import six.moves.cPickle as pickle +import pickle from array import array from collections import Counter, defaultdict from math import ceil @@ -30,8 +30,6 @@ import uuid import itertools -from six.moves import range - from swift.common import exceptions from swift.common import ring from swift.common.ring import utils @@ -2064,7 +2062,7 @@ def test_save_load(self): self.assertEqual(loaded_rb.to_dict(), rb.to_dict()) self.assertEqual(loaded_rb.overload, 3.14159) - @mock.patch('six.moves.builtins.open', autospec=True) + @mock.patch('builtins.open', autospec=True) @mock.patch('swift.common.ring.builder.pickle.dump', autospec=True) def test_save(self, mock_pickle_dump, mock_open): mock_open.return_value = mock_fh = mock.MagicMock() diff --git a/test/unit/common/ring/test_ring.py b/test/unit/common/ring/test_ring.py index 55f45862e0..de3b39dd25 100644 --- a/test/unit/common/ring/test_ring.py +++ b/test/unit/common/ring/test_ring.py @@ -15,7 +15,7 @@ import array import collections -import six.moves.cPickle as pickle +import pickle import os import unittest import stat @@ -28,7 +28,6 @@ import copy import mock -from six.moves import range from swift.common import ring, utils from swift.common.ring import utils as ring_utils from swift.common.utils import md5 @@ -960,9 +959,6 @@ def __next__(self): self.count += 1 return next(self._iter) - # complete the api - next = __next__ - def __getitem__(self, key): return self.table[key] diff --git a/test/unit/common/test_constraints.py b/test/unit/common/test_constraints.py index d0dde93e53..570460e13a 100644 --- a/test/unit/common/test_constraints.py +++ b/test/unit/common/test_constraints.py @@ -18,7 +18,6 @@ import tempfile import time -from six.moves import range from test.unit import mock_check_drive from swift.common.swob import Request, HTTPException diff --git a/test/unit/common/test_container_sync_realms.py b/test/unit/common/test_container_sync_realms.py index b883b66fe6..50f10dcbbf 100644 --- a/test/unit/common/test_container_sync_realms.py +++ b/test/unit/common/test_container_sync_realms.py @@ -18,8 +18,6 @@ import unittest import uuid -import six - from mock import ANY, patch from swift.common.container_sync_realms import ContainerSyncRealms from test.debug_logger import debug_logger @@ -80,16 +78,10 @@ def test_error_parsing(self): logger = debug_logger() fpath = os.path.join(tempdir, fname) csr = ContainerSyncRealms(fpath, logger) - if six.PY2: - fmt = "Could not load '%s': " \ - "File contains no section headers.\n" \ - "file: %s, line: 1\n" \ - "'invalid'" - else: - fmt = "Could not load '%s': " \ - "File contains no section headers.\n" \ - "file: '%s', line: 1\n" \ - "'invalid'" + fmt = "Could not load '%s': " \ + "File contains no section headers.\n" \ + "file: '%s', line: 1\n" \ + "'invalid'" self.assertEqual( logger.all_log_lines(), {'error': [fmt % (fpath, fpath)]}) diff --git a/test/unit/common/test_daemon.py b/test/unit/common/test_daemon.py index 37085d292f..7a1e0dc697 100644 --- a/test/unit/common/test_daemon.py +++ b/test/unit/common/test_daemon.py @@ -13,13 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +import configparser import os -import six +from io import StringIO import time import unittest from getpass import getuser import logging -from test.unit import tmpfile, with_tempdir, ConfigAssertMixin +from test.unit import tmpfile, with_tempdir import mock import signal from contextlib import contextmanager @@ -107,7 +108,7 @@ def test_my_worker_daemon(self): self.assertTrue(d.is_healthy()) -class TestRunDaemon(unittest.TestCase, ConfigAssertMixin): +class TestRunDaemon(unittest.TestCase): def setUp(self): for patcher in [ @@ -177,7 +178,7 @@ def test_run_daemon(self): conf_file, once=True) # test user quit - sio = six.StringIO() + sio = StringIO() logger = logging.getLogger('server') logger.addHandler(logging.StreamHandler(sio)) logger = utils.get_logger(None, 'server', log_route='server') @@ -260,9 +261,12 @@ def test_run_daemon_from_conf_file_with_duplicate_var(self, tempdir): with mock.patch('swift.common.utils.eventlet'), \ mock.patch('eventlet.hubs.use_hub'), \ mock.patch('eventlet.debug'): - app_config = lambda: daemon.run_daemon(MyDaemon, tempdir) - # N.B. CLIENT_TIMEOUT/client_timeout are unique options - self.assertDuplicateOption(app_config, 'conn_timeout', '1.2') + with self.assertRaises( + configparser.DuplicateOptionError) as ctx: + daemon.run_daemon(MyDaemon, tempdir) + msg = str(ctx.exception) + self.assertIn('conn_timeout', msg) + self.assertIn('already exists', msg) @with_tempdir def test_run_deamon_from_conf_dir(self, tempdir): @@ -316,9 +320,12 @@ def test_run_daemon_from_conf_dir_with_duplicate_var(self, tempdir): with mock.patch('swift.common.utils.eventlet'), \ mock.patch('eventlet.hubs.use_hub'), \ mock.patch('eventlet.debug'): - app_config = lambda: daemon.run_daemon(MyDaemon, tempdir) - # N.B. CLIENT_TIMEOUT/client_timeout are unique options - self.assertDuplicateOption(app_config, 'conn_timeout', '1.2') + with self.assertRaises( + configparser.DuplicateOptionError) as ctx: + daemon.run_daemon(MyDaemon, tempdir) + msg = str(ctx.exception) + self.assertIn('conn_timeout', msg) + self.assertIn('already exists', msg) @contextmanager def mock_os(self, child_worker_cycles=3): diff --git a/test/unit/common/test_db.py b/test/unit/common/test_db.py index 22484cc533..a1e949c722 100644 --- a/test/unit/common/test_db.py +++ b/test/unit/common/test_db.py @@ -16,14 +16,12 @@ """Tests for swift.common.db""" import contextlib import os -import sys import unittest from tempfile import mkdtemp from shutil import rmtree, copy from uuid import uuid4 - +import pickle import mock -import six.moves.cPickle as pickle import base64 import json @@ -34,9 +32,6 @@ from mock import patch, MagicMock from eventlet.timeout import Timeout -from six.moves import range - -import six import swift.common.db from swift.common.constraints import \ @@ -557,19 +552,8 @@ def test_get_raw_metadata(self): storage_policy_index=int(self.policy)) self.assertEqual(broker.metadata, {}) self.assertEqual(broker.get_raw_metadata(), '') - # This is not obvious. The actual JSON in the database is the same: - # '{"test\\u062a": ["value\\u062a", "0000000001.00000"]}' - # The only difference is what reading it produces on py2 and py3. - # We use native strings for metadata (see native_str_keys_and_values), - # so types are different. - if six.PY2: - key = u'test\u062a'.encode('utf-8') - value = u'value\u062a'.encode('utf-8') - else: - key = u'test\u062a' - value = u'value\u062a' metadata = { - key: [value, Timestamp(1).internal] + 'test\u062a': ['value\u062a', Timestamp(1).internal] } broker.update_metadata(metadata) self.assertEqual(broker.metadata, metadata) @@ -1492,15 +1476,12 @@ def test_possibly_quarantine_db_errors(self): mkdirs(dbpath) broker = DatabaseBroker(os.path.join(dbpath, '%d.db' % (i))) broker.db_type = 'test' - try: - raise ex - except sqlite3.DatabaseError: - with self.assertRaises(sqlite3.DatabaseError) as raised: - broker.possibly_quarantine(*sys.exc_info()) - self.assertEqual( - str(raised.exception), - 'Quarantined %s to %s due to %s database' % - (dbpath, qpath, hint)) + with self.assertRaises(sqlite3.DatabaseError) as raised: + broker.possibly_quarantine(ex) + self.assertEqual( + str(raised.exception), + 'Quarantined %s to %s due to %s database' % + (dbpath, qpath, hint)) def test_skip_commits(self): broker = DatabaseBroker(self.db_path) @@ -1585,8 +1566,6 @@ def test_commit_puts(self): broker._commit_puts([]) expected_name = (u'\u8509\u0902\ub30b\ub30b\u9409\u0901\u5608\u5606' u'\u3706\u0903\u3704\u2603\uf10f\ub30d\ud20e') - if six.PY2: - expected_name = expected_name.encode('utf8') mock_merge_items.assert_called_once_with([ (expected_name, '1559241846.46601', '0', '0', '0', 0, '0')]) self.assertEqual(0, os.path.getsize(broker.pending_file)) diff --git a/test/unit/common/test_db_replicator.py b/test/unit/common/test_db_replicator.py index 34011ef6ea..39a1c3c510 100644 --- a/test/unit/common/test_db_replicator.py +++ b/test/unit/common/test_db_replicator.py @@ -29,8 +29,7 @@ import mock from mock import patch, call -import six -from six.moves import reload_module +from importlib import reload as reload_module from swift.container.backend import DATADIR from swift.common import db_replicator @@ -164,7 +163,7 @@ def _mock_process(*args): class ReplHttp(object): def __init__(self, response=None, set_status=200): - if isinstance(response, six.text_type): + if isinstance(response, str): response = response.encode('ascii') self.response = response self.set_status = set_status diff --git a/test/unit/common/test_direct_client.py b/test/unit/common/test_direct_client.py index 5d1393bf29..f51298378a 100644 --- a/test/unit/common/test_direct_client.py +++ b/test/unit/common/test_direct_client.py @@ -22,7 +22,7 @@ import pickle import mock -from six.moves import urllib +import urllib.parse from swift.common import direct_client from swift.common.direct_client import DirectClientException @@ -31,7 +31,7 @@ from swift.common.utils import Timestamp, quote, md5 from swift.common.swob import RESPONSE_REASONS from swift.common.storage_policy import POLICIES -from six.moves.http_client import HTTPException +from http.client import HTTPException from test.debug_logger import debug_logger from test.unit import patch_policies diff --git a/test/unit/common/test_http_protocol.py b/test/unit/common/test_http_protocol.py index cb9772dd2c..c86b53cee6 100644 --- a/test/unit/common/test_http_protocol.py +++ b/test/unit/common/test_http_protocol.py @@ -20,7 +20,6 @@ import types import unittest import eventlet.wsgi as wsgi -import six from test.debug_logger import debug_logger from swift.common import http_protocol, swob @@ -322,12 +321,6 @@ def reflecting_app(env, start_response): def test_request_lines(self): def app(env, start_response): start_response("200 OK", []) - if six.PY2: - return [json.dumps({ - 'RAW_PATH_INFO': env['RAW_PATH_INFO'].decode('latin1'), - 'QUERY_STRING': (None if 'QUERY_STRING' not in env else - env['QUERY_STRING'].decode('latin1')), - }).encode('ascii')] return [json.dumps({ 'RAW_PATH_INFO': env['RAW_PATH_INFO'], 'QUERY_STRING': env.get('QUERY_STRING'), diff --git a/test/unit/common/test_internal_client.py b/test/unit/common/test_internal_client.py index 774edc6d86..f6b0912a9e 100644 --- a/test/unit/common/test_internal_client.py +++ b/test/unit/common/test_internal_client.py @@ -22,9 +22,8 @@ from io import BytesIO from textwrap import dedent -import six -from six.moves import range, zip_longest -from six.moves.urllib.parse import quote, parse_qsl +from itertools import zip_longest +from urllib.parse import quote, parse_qsl from swift.common import exceptions, internal_client, request_helpers, swob from swift.common.header_key_dict import HeaderKeyDict from swift.common.storage_policy import StoragePolicy @@ -35,10 +34,8 @@ from test.unit import with_tempdir, write_fake_ring, patch_policies from test.unit.common.middleware.helpers import FakeSwift, LeakTrackingIter -if six.PY3: - from eventlet.green.urllib import request as urllib2 -else: - from eventlet.green import urllib2 +from eventlet.green.urllib import request as urllib_request +from eventlet.green.http import client as http_client class FakeConn(object): @@ -59,7 +56,7 @@ def not_sleep(seconds): def unicode_string(start, length): - return u''.join([six.unichr(x) for x in range(start, start + length)]) + return u''.join([chr(x) for x in range(start, start + length)]) def path_parts(): @@ -653,7 +650,7 @@ def test_base_request_timeout(self): body = {"some": "content"} for timeout in (0.0, 42.0, None): - mocked_func = 'swift.common.internal_client.urllib2.urlopen' + mocked_func = 'swift.common.internal_client.urllib_request.urlopen' with mock.patch(mocked_func) as mock_urlopen: mock_urlopen.side_effect = [FakeConn(body)] sc = internal_client.SimpleClient('http://0.0.0.0/') @@ -667,7 +664,7 @@ def test_base_full_listing(self): body2 = [{'name': 'd'}] body3 = [] - mocked_func = 'swift.common.internal_client.urllib2.urlopen' + mocked_func = 'swift.common.internal_client.urllib_request.urlopen' with mock.patch(mocked_func) as mock_urlopen: mock_urlopen.side_effect = [ FakeConn(body1), FakeConn(body2), FakeConn(body3)] @@ -676,21 +673,11 @@ def test_base_full_listing(self): self.assertEqual(body1 + body2, resp_body) self.assertEqual(3, mock_urlopen.call_count) actual_requests = [call[0][0] for call in mock_urlopen.call_args_list] - if six.PY2: - # The get_selector method was deprecated in favor of a selector - # attribute in py31 and removed in py34 - self.assertEqual( - '/?format=json', actual_requests[0].get_selector()) - self.assertEqual( - '/?format=json&marker=c', actual_requests[1].get_selector()) - self.assertEqual( - '/?format=json&marker=d', actual_requests[2].get_selector()) - else: - self.assertEqual('/?format=json', actual_requests[0].selector) - self.assertEqual( - '/?format=json&marker=c', actual_requests[1].selector) - self.assertEqual( - '/?format=json&marker=d', actual_requests[2].selector) + self.assertEqual('/?format=json', actual_requests[0].selector) + self.assertEqual( + '/?format=json&marker=c', actual_requests[1].selector) + self.assertEqual( + '/?format=json&marker=d', actual_requests[2].selector) def test_make_request_method_path_headers(self): class FakeApp(FakeSwift): @@ -1759,8 +1746,8 @@ def make_request( class TestGetAuth(unittest.TestCase): - @mock.patch.object(urllib2, 'urlopen') - @mock.patch.object(urllib2, 'Request') + @mock.patch.object(urllib_request, 'urlopen') + @mock.patch.object(urllib_request, 'Request') def test_ok(self, request, urlopen): def getheader(name): d = {'X-Storage-Url': 'url', 'X-Auth-Token': 'token'} @@ -1851,38 +1838,38 @@ def mock_time(): data=None) self.assertEqual([{'content-length': '345'}, {}], retval) - @mock.patch.object(urllib2, 'urlopen') - @mock.patch.object(urllib2, 'Request') + @mock.patch.object(urllib_request, 'urlopen') + @mock.patch.object(urllib_request, 'Request') def test_get(self, request, urlopen): self._test_get_head(request, urlopen, 'GET') - @mock.patch.object(urllib2, 'urlopen') - @mock.patch.object(urllib2, 'Request') + @mock.patch.object(urllib_request, 'urlopen') + @mock.patch.object(urllib_request, 'Request') def test_head(self, request, urlopen): self._test_get_head(request, urlopen, 'HEAD') - @mock.patch.object(urllib2, 'urlopen') - @mock.patch.object(urllib2, 'Request') + @mock.patch.object(urllib_request, 'urlopen') + @mock.patch.object(urllib_request, 'Request') def test_get_with_retries_all_failed(self, request, urlopen): # Simulate a failing request, ensure retries done request.return_value.get_type.return_value = "http" - urlopen.side_effect = urllib2.URLError('') + urlopen.side_effect = urllib_request.URLError('') sc = internal_client.SimpleClient(url='http://127.0.0.1', retries=1) with mock.patch('swift.common.internal_client.sleep') as mock_sleep: - self.assertRaises(urllib2.URLError, sc.retry_request, 'GET') + self.assertRaises(urllib_request.URLError, sc.retry_request, 'GET') self.assertEqual(mock_sleep.call_count, 1) self.assertEqual(request.call_count, 2) self.assertEqual(urlopen.call_count, 2) - @mock.patch.object(urllib2, 'urlopen') - @mock.patch.object(urllib2, 'Request') + @mock.patch.object(urllib_request, 'urlopen') + @mock.patch.object(urllib_request, 'Request') def test_get_with_retries(self, request, urlopen): # First request fails, retry successful request.return_value.get_type.return_value = "http" mock_resp = mock.MagicMock() mock_resp.read.return_value = b'' mock_resp.info.return_value = {} - urlopen.side_effect = [urllib2.URLError(''), mock_resp] + urlopen.side_effect = [urllib_request.URLError(''), mock_resp] sc = internal_client.SimpleClient(url='http://127.0.0.1', retries=1, token='token') @@ -1896,31 +1883,31 @@ def test_get_with_retries(self, request, urlopen): self.assertEqual([{}, None], retval) self.assertEqual(sc.attempts, 2) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_get_with_retries_param(self, mock_urlopen): mock_response = mock.MagicMock() mock_response.read.return_value = b'' mock_response.info.return_value = {} - mock_urlopen.side_effect = internal_client.httplib.BadStatusLine('') + mock_urlopen.side_effect = http_client.BadStatusLine('') c = internal_client.SimpleClient(url='http://127.0.0.1', token='token') self.assertEqual(c.retries, 5) # first without retries param with mock.patch('swift.common.internal_client.sleep') as mock_sleep: - self.assertRaises(internal_client.httplib.BadStatusLine, + self.assertRaises(http_client.BadStatusLine, c.retry_request, 'GET') self.assertEqual(mock_sleep.call_count, 5) self.assertEqual(mock_urlopen.call_count, 6) # then with retries param mock_urlopen.reset_mock() with mock.patch('swift.common.internal_client.sleep') as mock_sleep: - self.assertRaises(internal_client.httplib.BadStatusLine, + self.assertRaises(http_client.BadStatusLine, c.retry_request, 'GET', retries=2) self.assertEqual(mock_sleep.call_count, 2) self.assertEqual(mock_urlopen.call_count, 3) # and this time with a real response mock_urlopen.reset_mock() - mock_urlopen.side_effect = [internal_client.httplib.BadStatusLine(''), + mock_urlopen.side_effect = [http_client.BadStatusLine(''), mock_response] with mock.patch('swift.common.internal_client.sleep') as mock_sleep: retval = c.retry_request('GET', retries=1) @@ -1928,7 +1915,7 @@ def test_get_with_retries_param(self, mock_urlopen): self.assertEqual(mock_urlopen.call_count, 2) self.assertEqual([{}, None], retval) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_request_with_retries_with_HTTPError(self, mock_urlopen): mock_response = mock.MagicMock() mock_response.read.return_value = b'' @@ -1937,7 +1924,7 @@ def test_request_with_retries_with_HTTPError(self, mock_urlopen): for request_method in 'GET PUT POST DELETE HEAD COPY'.split(): mock_urlopen.reset_mock() - mock_urlopen.side_effect = urllib2.HTTPError(*[None] * 5) + mock_urlopen.side_effect = urllib_request.HTTPError(*[None] * 5) with mock.patch('swift.common.internal_client.sleep') \ as mock_sleep: self.assertRaises(exceptions.ClientException, @@ -1945,7 +1932,7 @@ def test_request_with_retries_with_HTTPError(self, mock_urlopen): self.assertEqual(mock_sleep.call_count, 1) self.assertEqual(mock_urlopen.call_count, 2) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_request_container_with_retries_with_HTTPError(self, mock_urlopen): mock_response = mock.MagicMock() @@ -1955,7 +1942,7 @@ def test_request_container_with_retries_with_HTTPError(self, for request_method in 'GET PUT POST DELETE HEAD COPY'.split(): mock_urlopen.reset_mock() - mock_urlopen.side_effect = urllib2.HTTPError(*[None] * 5) + mock_urlopen.side_effect = urllib_request.HTTPError(*[None] * 5) with mock.patch('swift.common.internal_client.sleep') \ as mock_sleep: self.assertRaises(exceptions.ClientException, @@ -1964,7 +1951,7 @@ def test_request_container_with_retries_with_HTTPError(self, self.assertEqual(mock_sleep.call_count, 1) self.assertEqual(mock_urlopen.call_count, 2) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_request_object_with_retries_with_HTTPError(self, mock_urlopen): mock_response = mock.MagicMock() @@ -1974,7 +1961,7 @@ def test_request_object_with_retries_with_HTTPError(self, for request_method in 'GET PUT POST DELETE HEAD COPY'.split(): mock_urlopen.reset_mock() - mock_urlopen.side_effect = urllib2.HTTPError(*[None] * 5) + mock_urlopen.side_effect = urllib_request.HTTPError(*[None] * 5) with mock.patch('swift.common.internal_client.sleep') \ as mock_sleep: self.assertRaises(exceptions.ClientException, @@ -1983,12 +1970,12 @@ def test_request_object_with_retries_with_HTTPError(self, self.assertEqual(mock_sleep.call_count, 1) self.assertEqual(mock_urlopen.call_count, 2) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_delete_object_with_404_no_retry(self, mock_urlopen): mock_response = mock.MagicMock() mock_response.read.return_value = b'' err_args = [None, 404, None, None, None] - mock_urlopen.side_effect = urllib2.HTTPError(*err_args) + mock_urlopen.side_effect = urllib_request.HTTPError(*err_args) with mock.patch('swift.common.internal_client.sleep') as mock_sleep, \ self.assertRaises(exceptions.ClientException) as caught: @@ -1998,12 +1985,12 @@ def test_delete_object_with_404_no_retry(self, mock_urlopen): self.assertEqual(mock_sleep.call_count, 0) self.assertEqual(mock_urlopen.call_count, 1) - @mock.patch.object(urllib2, 'urlopen') + @mock.patch.object(urllib_request, 'urlopen') def test_delete_object_with_409_no_retry(self, mock_urlopen): mock_response = mock.MagicMock() mock_response.read.return_value = b'' err_args = [None, 409, None, None, None] - mock_urlopen.side_effect = urllib2.HTTPError(*err_args) + mock_urlopen.side_effect = urllib_request.HTTPError(*err_args) with mock.patch('swift.common.internal_client.sleep') as mock_sleep, \ self.assertRaises(exceptions.ClientException) as caught: @@ -2020,7 +2007,7 @@ def test_proxy(self): proxy = '%s://%s' % (scheme, proxy_host) url = 'https://127.0.0.1:1/a' - mocked = 'swift.common.internal_client.urllib2.urlopen' + mocked = 'swift.common.internal_client.urllib_request.urlopen' # module level methods for func in (internal_client.put_object, @@ -2034,14 +2021,12 @@ def test_proxy(self): self.assertEqual(1, len(args)) self.assertEqual(1, len(kwargs)) self.assertEqual(0.1, kwargs['timeout']) - self.assertIsInstance(args[0], urllib2.Request) + self.assertIsInstance(args[0], urllib_request.Request) self.assertEqual(proxy_host, args[0].host) - if six.PY2: - self.assertEqual(scheme, args[0].type) - else: - # TODO: figure out why this happens, whether py2 or py3 is - # messed up, whether we care, and what can be done about it - self.assertEqual('https', args[0].type) + # TODO: figure out why this doesn't match `scheme`, whether + # py2 (where it did) or py3 is messed up, whether we care, + # and what can be done about it + self.assertEqual('https', args[0].type) # class methods content = mock.MagicMock() @@ -2059,13 +2044,10 @@ def test_proxy(self): self.assertEqual(1, len(args)) self.assertEqual(1, len(kwargs)) self.assertEqual(0.1, kwargs['timeout']) - self.assertIsInstance(args[0], urllib2.Request) + self.assertIsInstance(args[0], urllib_request.Request) self.assertEqual(proxy_host, args[0].host) - if six.PY2: - self.assertEqual(scheme, args[0].type) - else: - # See above - self.assertEqual('https', args[0].type) + # See above + self.assertEqual('https', args[0].type) if __name__ == '__main__': diff --git a/test/unit/common/test_manager.py b/test/unit/common/test_manager.py index 4ec0fb87dc..94dfb57118 100644 --- a/test/unit/common/test_manager.py +++ b/test/unit/common/test_manager.py @@ -27,7 +27,7 @@ from time import sleep, time import tempfile -from six.moves import reload_module +from importlib import reload as reload_module from swift.common import manager from swift.common.exceptions import InvalidPidFileException diff --git a/test/unit/common/test_memcached.py b/test/unit/common/test_memcached.py index 86548ed2a5..278fbb036e 100644 --- a/test/unit/common/test_memcached.py +++ b/test/unit/common/test_memcached.py @@ -20,14 +20,13 @@ import errno import io import logging -import six import socket import time import unittest import os import mock -from six.moves.configparser import NoSectionError, NoOptionError +from configparser import NoSectionError, NoOptionError from eventlet import GreenPool, sleep, Queue from eventlet.pools import Pool @@ -496,7 +495,7 @@ def test_get_failed_connection_mid_request(self): # Now lets return an empty string, and make sure we aren't logging # the error. - fake_stdout = six.StringIO() + fake_stdout = io.StringIO() # force the logging through the DebugLogger instead of the nose # handler. This will use stdout, so we can assert that no stack trace # is logged. @@ -542,7 +541,7 @@ def test_incr_failed_connection_mid_request(self): # Now lets return an empty string, and make sure we aren't logging # the error. - fake_stdout = six.StringIO() + fake_stdout = io.StringIO() # force the logging through the DebugLogger instead of the nose # handler. This will use stdout, so we can assert that no stack trace # is logged. @@ -978,7 +977,7 @@ def test_multi(self): # Now lets simulate a lost connection and make sure we don't get # the index out of range stack trace when it does - mock_stderr = six.StringIO() + mock_stderr = io.StringIO() not_expected = "IndexError: list index out of range" with patch("sys.stderr", mock_stderr): mock.read_return_empty_str = True diff --git a/test/unit/common/test_splice.py b/test/unit/common/test_splice.py index 8c4ba9b67d..4888a6d35f 100644 --- a/test/unit/common/test_splice.py +++ b/test/unit/common/test_splice.py @@ -25,26 +25,12 @@ import re import mock -import six from swift.common.splice import splice, tee LOGGER = logging.getLogger(__name__) -def NamedTemporaryFile(): - '''Wrapper to tempfile.NamedTemporaryFile() disabling bufferring. - - The wrapper is used to support Python 2 and Python 3 in the same - code base. - ''' - - if six.PY3: - return tempfile.NamedTemporaryFile(buffering=0) - else: - return tempfile.NamedTemporaryFile(bufsize=0) - - def safe_close(fd): '''Close a file descriptor, ignoring any exceptions''' @@ -102,7 +88,7 @@ def test_splice_pipe_to_pipe(self): def test_splice_file_to_pipe(self): '''Test `splice` from a file to a pipe''' - with NamedTemporaryFile() as fd: + with tempfile.NamedTemporaryFile(buffering=0) as fd: with pipe() as (pa, pb): fd.write(b'abcdef') fd.seek(0, os.SEEK_SET) @@ -122,7 +108,7 @@ def test_splice_file_to_pipe(self): def test_splice_pipe_to_file(self): '''Test `splice` from a pipe to a file''' - with NamedTemporaryFile() as fd: + with tempfile.NamedTemporaryFile(buffering=0) as fd: with pipe() as (pa, pb): os.write(pb, b'abcdef') diff --git a/test/unit/common/test_statsd_client.py b/test/unit/common/test_statsd_client.py index 7ee5c9745b..d06922bbe6 100644 --- a/test/unit/common/test_statsd_client.py +++ b/test/unit/common/test_statsd_client.py @@ -23,11 +23,9 @@ import warnings import mock -import six -from six.moves.queue import Queue, Empty +from queue import Queue, Empty -from swift.common import utils from swift.common import statsd_client from swift.common.statsd_client import StatsdClient, get_statsd_client @@ -118,8 +116,6 @@ def test_init_host_is_none(self): def test_statsd_set_prefix_deprecation(self): with warnings.catch_warnings(record=True) as cm: - if six.PY2: - getattr(utils, '__warningregistry__', {}).clear() warnings.resetwarnings() warnings.simplefilter('always', DeprecationWarning) client = StatsdClient(None, None) @@ -352,9 +348,7 @@ def test_sample_rates_with_sample_rate_factor(self): self.assertEqual(len(mock_socket.sent), 1) payload = mock_socket.sent[0][0] - suffix = "|@%s" % effective_sample_rate - if six.PY3: - suffix = suffix.encode('utf-8') + suffix = ("|@%s" % effective_sample_rate).encode('utf-8') self.assertTrue(payload.endswith(suffix), payload) effective_sample_rate = 0.587 * 0.91 @@ -363,9 +357,7 @@ def test_sample_rates_with_sample_rate_factor(self): self.assertEqual(len(mock_socket.sent), 2) payload = mock_socket.sent[1][0] - suffix = "|@%s" % effective_sample_rate - if six.PY3: - suffix = suffix.encode('utf-8') + suffix = ("|@%s" % effective_sample_rate).encode('utf-8') self.assertTrue(payload.endswith(suffix), payload) @@ -419,15 +411,11 @@ def _send_and_get(self, sender_fn, *args, **kwargs): return got def assertStat(self, expected, sender_fn, *args, **kwargs): - got = self._send_and_get(sender_fn, *args, **kwargs) - if six.PY3: - got = got.decode('utf-8') + got = self._send_and_get(sender_fn, *args, **kwargs).decode('utf-8') return self.assertEqual(expected, got) def assertStatMatches(self, expected_regexp, sender_fn, *args, **kwargs): - got = self._send_and_get(sender_fn, *args, **kwargs) - if six.PY3: - got = got.decode('utf-8') + got = self._send_and_get(sender_fn, *args, **kwargs).decode('utf-8') return self.assertTrue(re.search(expected_regexp, got), [got, expected_regexp]) diff --git a/test/unit/common/test_storage_policy.py b/test/unit/common/test_storage_policy.py index 2b2f6978c3..0be6d26689 100644 --- a/test/unit/common/test_storage_policy.py +++ b/test/unit/common/test_storage_policy.py @@ -12,15 +12,15 @@ # limitations under the License. """ Tests for swift.common.storage_policies """ +from configparser import ConfigParser import contextlib -import six +import io import logging import unittest import os import mock from functools import partial -from six.moves.configparser import ConfigParser from tempfile import NamedTemporaryFile from test.debug_logger import debug_logger from test.unit import ( @@ -72,12 +72,8 @@ def __init__(self, idx, name='', is_default=False, is_deprecated=False, class TestStoragePolicies(unittest.TestCase): def _conf(self, conf_str): conf_str = "\n".join(line.strip() for line in conf_str.split("\n")) - if six.PY2: - conf = ConfigParser() - conf.readfp(six.StringIO(conf_str)) - else: - conf = ConfigParser(strict=False) - conf.read_file(six.StringIO(conf_str)) + conf = ConfigParser(strict=False) + conf.read_file(io.StringIO(conf_str)) return conf def assertRaisesWithMessage(self, exc_class, message, f, *args, **kwargs): diff --git a/test/unit/common/test_swob.py b/test/unit/common/test_swob.py index 8768bc5e61..267fe976e9 100644 --- a/test/unit/common/test_swob.py +++ b/test/unit/common/test_swob.py @@ -22,9 +22,8 @@ from io import BytesIO +from urllib.parse import quote import mock -import six -from six.moves.urllib.parse import quote import swift.common.swob as swob from swift.common import utils, exceptions @@ -357,10 +356,7 @@ def test_normalize_etag(self): def test_normalize_bytes(self): some_etag = b'"some-etag"' - if six.PY2: - self.assertEqual('some-etag', swob.normalize_etag(some_etag)) - else: - self.assertRaises(TypeError, swob.normalize_etag, some_etag) + self.assertRaises(TypeError, swob.normalize_etag, some_etag) class TestTransferEncoding(unittest.TestCase): @@ -990,66 +986,44 @@ def test_unicode_path(self): self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') - if six.PY2: - # Unicode is encoded to UTF-8 on py2, to paper over deserialized - # JSON slipping into subrequests + # Arbitrary Unicode *is not* supported on py3 -- only latin-1 + # encodable is supported, because PEP-3333. + with self.assertRaises(UnicodeEncodeError): req = swob.Request.blank(u'/\u2661') - self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) - self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') - req = swob.Request.blank('/') + req = swob.Request.blank('/') + with self.assertRaises(UnicodeEncodeError): req.path_info = u'/\u2661' - self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) - self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') + # Update didn't take + self.assertEqual(req.path, '/') + self.assertEqual(req.environ['PATH_INFO'], '/') - else: - # Arbitrary Unicode *is not* supported on py3 -- only latin-1 - # encodable is supported, because PEP-3333. - with self.assertRaises(UnicodeEncodeError): - req = swob.Request.blank(u'/\u2661') - - req = swob.Request.blank('/') - with self.assertRaises(UnicodeEncodeError): - req.path_info = u'/\u2661' - # Update didn't take - self.assertEqual(req.path, '/') - self.assertEqual(req.environ['PATH_INFO'], '/') - - # Needs to be a "WSGI string" - req = swob.Request.blank('/\xe2\x99\xa1') - self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) - self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') - - req = swob.Request.blank('/') - req.path_info = '/\xe2\x99\xa1' - self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) - self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') + # Needs to be a "WSGI string" + req = swob.Request.blank('/\xe2\x99\xa1') + self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) + self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') + + req = swob.Request.blank('/') + req.path_info = '/\xe2\x99\xa1' + self.assertEqual(req.path, quote(u'/\u2661'.encode('utf-8'))) + self.assertEqual(req.environ['PATH_INFO'], '/\xe2\x99\xa1') def test_unicode_query(self): # Bytes are always OK req = swob.Request.blank('/') encoded = u'\u2661'.encode('utf-8') req.query_string = b'x=' + encoded - if six.PY2: - self.assertEqual(req.params['x'], encoded) - else: - self.assertEqual(req.params['x'], encoded.decode('latin1')) + self.assertEqual(req.params['x'], encoded.decode('latin1')) - if six.PY2: - # Unicode will be UTF-8-encoded on py2 - req = swob.Request.blank('/') + # Note that py3 requires "WSGI strings" + req = swob.Request.blank('/') + with self.assertRaises(UnicodeEncodeError): req.query_string = u'x=\u2661' - self.assertEqual(req.params['x'], encoded) - else: - # ...but py3 requires "WSGI strings" - req = swob.Request.blank('/') - with self.assertRaises(UnicodeEncodeError): - req.query_string = u'x=\u2661' - self.assertEqual(req.params, {}) - - req = swob.Request.blank('/') - req.query_string = 'x=' + encoded.decode('latin-1') - self.assertEqual(req.params['x'], encoded.decode('latin-1')) + self.assertEqual(req.params, {}) + + req = swob.Request.blank('/') + req.query_string = 'x=' + encoded.decode('latin-1') + self.assertEqual(req.params['x'], encoded.decode('latin-1')) def test_url2(self): pi = '/hi/there' diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index e369e7c9e2..8e2f3b0692 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -46,10 +46,6 @@ import inspect import warnings -import six -from six import StringIO -from six.moves import range - import tempfile import time import unittest @@ -57,12 +53,12 @@ import shutil from getpass import getuser -from io import BytesIO +from io import BytesIO, StringIO from shutil import rmtree from functools import partial from tempfile import TemporaryFile, NamedTemporaryFile, mkdtemp from mock import MagicMock, patch -from six.moves.configparser import NoSectionError, NoOptionError +from configparser import NoSectionError, NoOptionError from uuid import uuid4 from swift.common.exceptions import Timeout, LockTimeout, \ @@ -581,8 +577,6 @@ def __iter__(self): def __next__(self): return next(self._body) - next = __next__ # py2 - def close(self): self.close_calls.append(True) @@ -1917,7 +1911,7 @@ def test_get_valid_utf8_str(self): def do_test(input_value, expected): actual = utils.get_valid_utf8_str(input_value) self.assertEqual(expected, actual) - self.assertIsInstance(actual, six.binary_type) + self.assertIsInstance(actual, bytes) actual.decode('utf-8') do_test(b'abc', b'abc') @@ -2802,8 +2796,6 @@ def test_md5_without_data(self): digest = test_md5.hexdigest() self.assertEqual(digest, self.md5_digest) - @unittest.skipIf(sys.version_info.major == 2, - "hashlib.md5 does not raise TypeError here in py2") def test_string_data_raises_type_error(self): if not self.fips_enabled: self.assertRaises(TypeError, hashlib.md5, u'foo') @@ -3029,7 +3021,7 @@ def test_close(self): self.assertEqual(next(iter_file), b'a') iter_file.close() self.assertTrue(iter_file.closed) - self.assertRaises(ValueError, iter_file.next) + self.assertRaises(ValueError, next, iter_file) self.assertRaises(ValueError, iter_file.read) self.assertRaises(ValueError, iter_file.readline) self.assertRaises(ValueError, iter_file.readlines) @@ -3084,7 +3076,7 @@ def __init__(self, upper_bound): def __iter__(self): return self - def next(self): + def __next__(self): if self.concurrent_calls > 0: self.concurrent_call = True @@ -3099,7 +3091,6 @@ def next(self): return val finally: self.concurrent_calls -= 1 - __next__ = next class TestEventletRateLimiter(unittest.TestCase): @@ -3917,7 +3908,7 @@ def test_pending(self): next(pile) self.assertEqual(i, pile._pending) # sanity check - the pile is empty - self.assertRaises(StopIteration, pile.next) + self.assertRaises(StopIteration, next, pile) # pending remains 0 self.assertEqual(0, pile._pending) @@ -4357,8 +4348,6 @@ def test_parse_mime_headers(self): """) headers = utils.parse_mime_headers(doc_file) utf8 = u'\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440' - if six.PY2: - utf8 = utf8.encode('utf-8') expected_headers = { 'Content-Disposition': 'form-data; name="file_size"', @@ -4807,14 +4796,9 @@ class BaseNamespaceShardRange(object): def _check_name_account_container(self, nsr, exp_name): # check that the name, account, container properties are consistent exp_account, exp_container = exp_name.split('/') - if six.PY2: - self.assertEqual(exp_name.encode('utf8'), nsr.name) - self.assertEqual(exp_account.encode('utf8'), nsr.account) - self.assertEqual(exp_container.encode('utf8'), nsr.container) - else: - self.assertEqual(exp_name, nsr.name) - self.assertEqual(exp_account, nsr.account) - self.assertEqual(exp_container, nsr.container) + self.assertEqual(exp_name, nsr.name) + self.assertEqual(exp_account, nsr.account) + self.assertEqual(exp_container, nsr.container) class TestNamespace(unittest.TestCase, BaseNamespaceShardRange): @@ -4841,8 +4825,6 @@ def do_test(good_value, expected): do_test(u'y', 'y') expected = u'\N{SNOWMAN}' - if six.PY2: - expected = expected.encode('utf-8') with warnings.catch_warnings(record=True) as captured_warnings: do_test(u'\N{SNOWMAN}', expected) do_test(u'\N{SNOWMAN}'.encode('utf-8'), expected) @@ -4891,8 +4873,6 @@ def do_test(good_value, expected): do_test(u'b', 'b') expected = u'\N{SNOWMAN}' - if six.PY2: - expected = expected.encode('utf-8') with warnings.catch_warnings(record=True) as captured_warnings: do_test(u'\N{SNOWMAN}', expected) do_test(u'\N{SNOWMAN}'.encode('utf-8'), expected) @@ -4941,9 +4921,6 @@ def test_bounds_serialization(self): ns = utils.Namespace('a/%s-%s' % (lower, upper), lower, upper) exp_lower = lower exp_upper = upper - if six.PY2: - exp_lower = exp_lower.encode('utf-8') - exp_upper = exp_upper.encode('utf-8') self.assertEqual(exp_lower, ns.lower) self.assertEqual(exp_lower, ns.lower_str) self.assertEqual(exp_upper, ns.upper) @@ -4973,14 +4950,10 @@ def test_name_unexpected_format(self): def test_unicode_name(self): shard_bounds = ('', 'ham', 'pie', u'\N{SNOWMAN}', u'\U0001F334', '') - bounds = [(l, u) for l, u in zip(shard_bounds[:-1], shard_bounds[1:])] + exp_bounds = [(l, u) + for l, u in zip(shard_bounds[:-1], shard_bounds[1:])] namespaces = [utils.Namespace('.shards_a/c_%s' % upper, lower, upper) - for lower, upper in bounds] - if six.PY2: - exp_bounds = [(l.encode('utf8'), u.encode('utf8')) - for l, u in bounds] - else: - exp_bounds = bounds + for lower, upper in exp_bounds] for i in range(len(exp_bounds)): self.assertEqual(namespaces[i].name, '.shards_a/c_%s' % exp_bounds[i][1]) @@ -5534,8 +5507,8 @@ def _check_to_from_dict(self, lower, upper): 'state': utils.ShardRange.FOUND, 'state_timestamp': ts_3.internal, 'epoch': ts_4, 'reported': 0, 'tombstones': -1} self.assertEqual(expected, sr_dict) - self.assertIsInstance(sr_dict['lower'], six.string_types) - self.assertIsInstance(sr_dict['upper'], six.string_types) + self.assertIsInstance(sr_dict['lower'], str) + self.assertIsInstance(sr_dict['upper'], str) sr_new = utils.ShardRange.from_dict(sr_dict) self.assertEqual(sr, sr_new) self.assertEqual(sr_dict, dict(sr_new)) diff --git a/test/unit/common/test_wsgi.py b/test/unit/common/test_wsgi.py index e5476c98b5..e579edd045 100644 --- a/test/unit/common/test_wsgi.py +++ b/test/unit/common/test_wsgi.py @@ -15,6 +15,7 @@ """Tests for swift.common.wsgi""" +import configparser import errno import logging import socket @@ -25,7 +26,7 @@ from io import BytesIO from textwrap import dedent -from six.moves.urllib.parse import quote +from urllib.parse import quote import mock @@ -43,7 +44,7 @@ from test import listen_zero from test.debug_logger import debug_logger from test.unit import ( - temptree, with_tempdir, write_fake_ring, patch_policies, ConfigAssertMixin) + temptree, with_tempdir, write_fake_ring, patch_policies) from paste.deploy import loadwsgi @@ -60,7 +61,7 @@ def _fake_rings(tmpdir): @patch_policies -class TestWSGI(unittest.TestCase, ConfigAssertMixin): +class TestWSGI(unittest.TestCase): """Tests for swift.common.wsgi""" def test_init_request_processor(self): @@ -164,8 +165,12 @@ def test_loadapp_from_file_with_duplicate_var(self, tempdir): contents = dedent(conf_body) with open(conf_path, 'w') as f: f.write(contents) - app_config = lambda: wsgi.loadapp(conf_path) - self.assertDuplicateOption(app_config, 'client_timeout', 3.0) + with self.assertRaises( + configparser.DuplicateOptionError) as ctx: + wsgi.loadapp(conf_path) + msg = str(ctx.exception) + self.assertIn('client_timeout', msg) + self.assertIn('already exists', msg) @with_tempdir def test_loadapp_from_file_with_global_conf(self, tempdir): @@ -308,10 +313,12 @@ def test_loadapp_from_dir_with_duplicate_var(self, tempdir): path = os.path.join(tempdir, filename + '.conf') with open(path, 'wt') as fd: fd.write(dedent(conf_body)) - app_config = lambda: wsgi.loadapp(tempdir) - # N.B. our paste conf.d parsing re-uses readconf, - # so, CLIENT_TIMEOUT/client_timeout are unique options - self.assertDuplicateOption(app_config, 'conn_timeout', 4.0) + with self.assertRaises( + configparser.DuplicateOptionError) as ctx: + wsgi.loadapp(tempdir) + msg = str(ctx.exception) + self.assertIn('conn_timeout', msg) + self.assertIn('already exists', msg) @with_tempdir def test_load_app_config(self, tempdir): diff --git a/test/unit/common/utils/test_config.py b/test/unit/common/utils/test_config.py index bc3ae7f8e2..1ee97ad4fb 100644 --- a/test/unit/common/utils/test_config.py +++ b/test/unit/common/utils/test_config.py @@ -23,7 +23,7 @@ from swift.common.utils import config -from six import StringIO +from io import StringIO from test import annotate_failure from test.unit import temptree diff --git a/test/unit/common/utils/test_logs.py b/test/unit/common/utils/test_logs.py index b7a3f60dce..04c24dfbc8 100644 --- a/test/unit/common/utils/test_logs.py +++ b/test/unit/common/utils/test_logs.py @@ -18,7 +18,6 @@ import contextlib import errno -import hashlib import logging import os import socket @@ -29,19 +28,15 @@ import functools import mock -import six -from six import StringIO -from six.moves import http_client +from io import StringIO +import http.client from test.unit import with_tempdir from test.unit import quiet_eventlet_exceptions from test.unit.common.test_utils import MockOs, MockSys from swift.common.exceptions import Timeout, MessageTimeout, ConnectionTimeout -if six.PY2: - import eventlet.green.httplib as green_http_client -else: - import eventlet.green.http.client as green_http_client +import eventlet.green.http.client as green_http_client from swift.common import utils @@ -557,7 +552,7 @@ def log_exception(exc): self.assertTrue('my error message' in log_msg) # test BadStatusLine - log_exception(http_client.BadStatusLine('')) + log_exception(http.client.BadStatusLine('')) log_msg = strip_value(sio) self.assertNotIn('Traceback', log_msg) self.assertIn('''BadStatusLine("''"''', log_msg) @@ -568,25 +563,24 @@ def log_exception(exc): self.assertNotIn('Traceback', log_msg) self.assertIn('''BadStatusLine("''"''', log_msg) - if not six.PY2: - # py3 introduced RemoteDisconnected exceptions which inherit - # from both BadStatusLine *and* OSError; make sure those are - # handled as BadStatusLine, not OSError - log_exception(http_client.RemoteDisconnected( - 'Remote end closed connection')) - log_msg = strip_value(sio) - self.assertNotIn('Traceback', log_msg) - self.assertIn( - "RemoteDisconnected('Remote end closed connection'", - log_msg) + # py3 introduced RemoteDisconnected exceptions which inherit + # from both BadStatusLine *and* OSError; make sure those are + # handled as BadStatusLine, not OSError + log_exception(http.client.RemoteDisconnected( + 'Remote end closed connection')) + log_msg = strip_value(sio) + self.assertNotIn('Traceback', log_msg) + self.assertIn( + "RemoteDisconnected('Remote end closed connection'", + log_msg) - log_exception(green_http_client.RemoteDisconnected( - 'Remote end closed connection')) - log_msg = strip_value(sio) - self.assertNotIn('Traceback', log_msg) - self.assertIn( - "RemoteDisconnected('Remote end closed connection'", - log_msg) + log_exception(green_http_client.RemoteDisconnected( + 'Remote end closed connection')) + log_msg = strip_value(sio) + self.assertNotIn('Traceback', log_msg) + self.assertIn( + "RemoteDisconnected('Remote end closed connection'", + log_msg) # test unhandled log_exception(Exception('my error message')) @@ -782,7 +776,7 @@ def log_exception(exc): log_msg_lines[0]) # BadStatusLine - exc = http_client.BadStatusLine('my error message') + exc = http.client.BadStatusLine('my error message') log_msg_lines = log_exception(exc) self.assertEqual(1, len(log_msg_lines)) self.assertEqual("some prefix: blah: %r" % exc, log_msg_lines[0]) @@ -1071,20 +1065,9 @@ def test_str_anonymizer(self): 'Swift is great!', 'sha257', '') def test_str_anonymizer_python_maddness(self): - with mock.patch('swift.common.utils.base.hashlib') as mocklib: - if six.PY2: - # python <2.7.9 doesn't have this algorithms_guaranteed, but - # our if block short-circuts before we explode - mocklib.algorithms = hashlib.algorithms - mocklib.algorithms_guaranteed.sideEffect = AttributeError() - else: - # python 3 doesn't have this algorithms but our if block - # short-circuts before we explode - mocklib.algorithms.sideEffect.sideEffect = AttributeError() - mocklib.algorithms_guaranteed = hashlib.algorithms_guaranteed - utils.StrAnonymizer('Swift is great!', 'sha1', '') - self.assertRaises(ValueError, utils.StrAnonymizer, - 'Swift is great!', 'sha257', '') + utils.StrAnonymizer('Swift is great!', 'sha1', '') + self.assertRaises(ValueError, utils.StrAnonymizer, + 'Swift is great!', 'sha257', '') def test_str_format_time(self): dt = utils.StrFormatTime(10000.123456789) diff --git a/test/unit/container/test_backend.py b/test/unit/container/test_backend.py index 7b7e6a66f4..fc169c6884 100644 --- a/test/unit/container/test_backend.py +++ b/test/unit/container/test_backend.py @@ -31,8 +31,6 @@ import json import itertools -import six - from swift.common.exceptions import LockTimeout from swift.container.backend import ContainerBroker, \ update_new_item_from_existing, UNSHARDED, SHARDING, SHARDED, \ @@ -756,7 +754,7 @@ def test_batch_reclaim(self): now = time() top_of_the_minute = now - (now % 60) c = itertools.cycle([True, False]) - for m, is_deleted in six.moves.zip(range(num_of_objects), c): + for m, is_deleted in zip(range(num_of_objects), c): offset = top_of_the_minute - (m * 60) obj_specs.append((Timestamp(offset), is_deleted)) random.seed(now) @@ -3618,8 +3616,6 @@ def test_merge_items_is_green(self, tempdir): def test_merge_items_overwrite_unicode(self): # test DatabaseBroker.merge_items snowman = u'\N{SNOWMAN}' - if six.PY2: - snowman = snowman.encode('utf-8') broker1 = ContainerBroker(self.get_db_path(), account='a', container='c') broker1.initialize(Timestamp('1').internal, 0) diff --git a/test/unit/container/test_reconciler.py b/test/unit/container/test_reconciler.py index 7d85caf169..ebf608be96 100644 --- a/test/unit/container/test_reconciler.py +++ b/test/unit/container/test_reconciler.py @@ -30,8 +30,7 @@ from collections import defaultdict from datetime import datetime -import six -from six.moves import urllib +import urllib.parse from swift.common.storage_policy import StoragePolicy, ECStoragePolicy from swift.common.swob import Request @@ -120,8 +119,6 @@ def parse(self, listings): else: timestamp, content_type = timestamp, 'application/x-put' storage_policy_index, path = item - if six.PY2 and isinstance(path, six.text_type): - path = path.encode('utf-8') account, container_name, obj_name = split_path( path, 0, 3, rest_with_last=True) self.accounts[account][container_name].append( @@ -157,9 +154,6 @@ def parse(self, listings): # strings, so normalize here if isinstance(timestamp, numbers.Number): timestamp = '%f' % timestamp - if six.PY2: - obj_name = obj_name.decode('utf-8') - timestamp = timestamp.decode('utf-8') obj_data = { 'bytes': 0, # listing data is unicode @@ -1319,10 +1313,7 @@ def test_object_move_with_unicode_and_spaces(self): # functions where we call them with (account, container, obj) obj_name = u"AUTH_bob/c \u062a/o1 \u062a" # anytime we talk about a call made to swift for a path - if six.PY2: - obj_path = obj_name.encode('utf-8') - else: - obj_path = obj_name.encode('utf-8').decode('latin-1') + obj_path = obj_name.encode('utf-8').decode('latin-1') # this mock expects unquoted unicode because it handles container # listings as well as paths self._mock_listing({ diff --git a/test/unit/container/test_server.py b/test/unit/container/test_server.py index f9e34b747d..760fbcae01 100644 --- a/test/unit/container/test_server.py +++ b/test/unit/container/test_server.py @@ -23,16 +23,14 @@ import time import random from contextlib import contextmanager -from io import BytesIO +from io import BytesIO, StringIO from shutil import rmtree from tempfile import mkdtemp from xml.dom import minidom from eventlet import spawn, Timeout import json -import six -from six import StringIO -from six.moves.urllib.parse import quote +from urllib.parse import quote from swift import __version__ as swift_version from swift.common.header_key_dict import HeaderKeyDict @@ -5644,12 +5642,12 @@ def test_GET_delimiter_xml_with_quotes(self): container = dom.getElementsByTagName('container')[0] self.assertTrue(len(container.getElementsByTagName('subdir')) == 1) subdir = container.getElementsByTagName('subdir')[0] - self.assertEqual(six.text_type(subdir.attributes['name'].value), - u'<\'sub\' "dir">/') + self.assertEqual(subdir.attributes['name'].value, + '<\'sub\' "dir">/') self.assertTrue(len(subdir.getElementsByTagName('name')) == 1) name = subdir.getElementsByTagName('name')[0] - self.assertEqual(six.text_type(name.childNodes[0].data), - u'<\'sub\' "dir">/') + self.assertEqual(name.childNodes[0].data, + '<\'sub\' "dir">/') def test_GET_path(self): req = Request.blank( diff --git a/test/unit/container/test_sharder.py b/test/unit/container/test_sharder.py index 46ca3c916c..613638a47e 100644 --- a/test/unit/container/test_sharder.py +++ b/test/unit/container/test_sharder.py @@ -32,8 +32,6 @@ from copy import deepcopy -import six - from swift.common import internal_client from swift.container import replicator from swift.container.backend import ContainerBroker, UNSHARDED, SHARDING, \ @@ -8265,7 +8263,7 @@ def test_cursor(self): for curs in ('curs', u'curs\u00e4\u00fb'): with annotate_failure('%r' % curs): - expected = curs.encode('utf-8') if six.PY2 else curs + expected = curs ctx = CleavingContext(ref, curs, 12, 11, 10, False, True) self.assertEqual(dict(ctx), { 'cursor': expected, diff --git a/test/unit/container/test_updater.py b/test/unit/container/test_updater.py index 177477c713..52430d9b72 100644 --- a/test/unit/container/test_updater.py +++ b/test/unit/container/test_updater.py @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import six -import six.moves.cPickle as pickle +import pickle import mock import os import unittest @@ -313,8 +312,6 @@ def test_unicode(self): container='\xce\xa9') cb.initialize(normalize_timestamp(1), 0) obj_name = u'\N{GREEK CAPITAL LETTER OMEGA}' - if six.PY2: - obj_name = obj_name.encode('utf-8') cb.put_object(obj_name, normalize_timestamp(2), 3, 'text/plain', '68b329da9893e34099c7d8ad5cb9c940') diff --git a/test/unit/helpers.py b/test/unit/helpers.py index 63ada0aa28..00504a396f 100644 --- a/test/unit/helpers.py +++ b/test/unit/helpers.py @@ -30,7 +30,7 @@ from eventlet import spawn, wsgi import mock from shutil import rmtree -import six.moves.cPickle as pickle +import pickle import swift from swift.account import server as account_server diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py index 9f6810d8fe..949ce377e6 100644 --- a/test/unit/obj/test_diskfile.py +++ b/test/unit/obj/test_diskfile.py @@ -15,9 +15,8 @@ """Tests for swift.obj.diskfile""" -from __future__ import print_function +import pickle import binascii -import six.moves.cPickle as pickle import os import errno import itertools @@ -29,7 +28,6 @@ import uuid import xattr import re -import six import sys from collections import defaultdict from random import shuffle, randint @@ -805,10 +803,7 @@ def raw_xattr(output): with open(path, 'rb') as fd: actual = diskfile.read_metadata(fd) # name should come out as native strings - expected_name = b'/AUTH_test/\xe2\x98\x83/\xe2\x98\x83' - if not six.PY2: - expected_name = expected_name.decode('utf8') - self.assertEqual(actual['name'], expected_name) + self.assertEqual(actual['name'], '/AUTH_test/\u2603/\u2603') # other meta will be WSGI strings, though self.assertEqual( actual['X-Object-Meta-\xe2\x98\x83'], '\xe2\x98\x83') @@ -830,13 +825,10 @@ def test_write_read_metadata(self): b'X-Object-Meta-Strange': b'should be bytes', b'X-Object-Meta-x\xff': b'not utf8 \xff', b'X-Object-Meta-y\xc3\xa8': b'not ascii \xc3\xa8'} - if six.PY2: - as_native = as_bytes - else: - as_native = dict((k.decode('utf-8', 'surrogateescape'), - v if isinstance(v, int) else - v.decode('utf-8', 'surrogateescape')) - for k, v in as_bytes.items()) + as_native = dict((k.decode('utf-8', 'surrogateescape'), + v if isinstance(v, int) else + v.decode('utf-8', 'surrogateescape')) + for k, v in as_bytes.items()) def check_metadata(expected, typ): with open(path, 'rb') as fd: @@ -4407,10 +4399,7 @@ def test_disk_file_large_app_iter_ranges(self): value = header + b''.join(it) self.assertEqual(quarantine_msgs, []) - if six.PY2: - message = email.message_from_string(value) - else: - message = email.message_from_bytes(value) + message = email.message_from_bytes(value) parts = [p.get_payload(decode=True) for p in message.walk()][1:3] self.assertEqual(parts, target_strs) @@ -7694,8 +7683,7 @@ def watch_open(*args, **kargs): df_mgr.get_hashes('sda1', '0', [], policy) open_log = defaultdict(list) - open_loc = '__builtin__.open' if six.PY2 else 'builtins.open' - with mock.patch(open_loc, watch_open): + with mock.patch('builtins.open', watch_open): self.assertTrue(os.path.exists(inv_file)) # no new suffixes get invalidated... so no write iop df_mgr.get_hashes('sda1', '0', [], policy) diff --git a/test/unit/obj/test_expirer.py b/test/unit/obj/test_expirer.py index 0902260dc0..60867b2c2a 100644 --- a/test/unit/obj/test_expirer.py +++ b/test/unit/obj/test_expirer.py @@ -26,8 +26,7 @@ from copy import deepcopy import mock -import six -from six.moves import urllib +import urllib.parse from swift.common import internal_client, utils, swob from swift.common.utils import Timestamp @@ -85,7 +84,7 @@ def get_account_info(self, account): def iter_containers(self, account, prefix=''): acc_dict = self.aco_dict[account] - return [{'name': six.text_type(container)} + return [{'name': str(container)} for container in sorted(acc_dict) if container.startswith(prefix)] @@ -105,7 +104,7 @@ def iter_objects(self, account, container, **kwargs): resp = [] for obj in obj_iter: if not isinstance(obj, dict): - obj = {'name': six.text_type(obj)} + obj = {'name': str(obj)} resp.append(obj) return resp diff --git a/test/unit/obj/test_reconstructor.py b/test/unit/obj/test_reconstructor.py index 27c4daf495..859109ad0b 100644 --- a/test/unit/obj/test_reconstructor.py +++ b/test/unit/obj/test_reconstructor.py @@ -17,8 +17,7 @@ import unittest import os import mock -import six -import six.moves.cPickle as pickle +import pickle import tempfile import time import shutil @@ -32,7 +31,7 @@ from contextlib import closing, contextmanager from gzip import GzipFile from shutil import rmtree -from six.moves.urllib.parse import unquote +from urllib.parse import unquote from swift.common import utils from swift.common.exceptions import DiskFileError, DiskFileQuarantined from swift.common.header_key_dict import HeaderKeyDict @@ -5175,10 +5174,7 @@ def setUp(self): def _create_fragment(self, frag_index, body=b'test data'): utils.mkdirs(os.path.join(self.devices, 'sda1')) df_mgr = self.reconstructor._df_router[self.policy] - if six.PY2: - obj_name = self.obj_name - else: - obj_name = self.obj_name.decode('utf8') + obj_name = self.obj_name.decode('utf8') self.df = df_mgr.get_diskfile('sda1', 9, 'a', 'c', obj_name, policy=self.policy) write_diskfile(self.df, self.obj_timestamp, data=body, @@ -6633,8 +6629,6 @@ def test_missing_header(missing_header, warning_extra): ) expected_warning = 'Invalid resp from %s policy#0%s' % ( path, warning_extra) - if six.PY2: - expected_warning = expected_warning.decode('utf8') self.assertIn(expected_warning, warning_log_lines) test_missing_header( @@ -6704,8 +6698,6 @@ def test_invalid_ec_frag_index_header(invalid_frag_index): 'Invalid resp from %s policy#0 ' '(invalid X-Object-Sysmeta-Ec-Frag-Index: %r)' % (path, invalid_frag_index)) - if six.PY2: - expected_warning = expected_warning.decode('utf8') self.assertIn(expected_warning, warning_log_lines) for value in ('None', 'invalid'): diff --git a/test/unit/obj/test_replicator.py b/test/unit/obj/test_replicator.py index be51b26500..10697d76bb 100644 --- a/test/unit/obj/test_replicator.py +++ b/test/unit/obj/test_replicator.py @@ -21,8 +21,7 @@ import mock from gzip import GzipFile from shutil import rmtree -import six -import six.moves.cPickle as pickle +import pickle import time import tempfile from contextlib import contextmanager, closing @@ -131,8 +130,7 @@ def _mock_process(ret): MockProcess.captured_log = captured_log orig_process = subprocess.Popen MockProcess.ret_code = (i[0] for i in ret) - MockProcess.ret_log = (i[1] if six.PY2 else i[1].encode('utf8') - for i in ret) + MockProcess.ret_log = (i[1].encode('utf8') for i in ret) MockProcess.check_args = (i[2] for i in ret) object_replicator.subprocess.Popen = MockProcess yield captured_log diff --git a/test/unit/obj/test_server.py b/test/unit/obj/test_server.py index 4e9f8737f4..3d8c745f9e 100644 --- a/test/unit/obj/test_server.py +++ b/test/unit/obj/test_server.py @@ -16,15 +16,14 @@ """Tests for swift.obj.server""" -import six.moves.cPickle as pickle +import pickle import datetime import json import errno import operator import os import mock -import six -from six import StringIO +from io import StringIO import unittest import math import random @@ -36,7 +35,7 @@ from textwrap import dedent from eventlet import sleep, spawn, wsgi, Timeout, tpool, greenthread -from eventlet.green import httplib +from eventlet.green.http import client as http_client from swift import __version__ as swift_version from swift.common.http import is_success @@ -223,9 +222,8 @@ def check_all_api_methods(self, obj_name='o', alt_res=None): def test_REQUEST_SPECIAL_CHARS(self): obj = 'special昆%20/%' - if six.PY3: - # The path argument of Request.blank() is a WSGI string, somehow - obj = obj.encode('utf-8').decode('latin-1') + # The path argument of Request.blank() is a WSGI string, somehow + obj = obj.encode('utf-8').decode('latin-1') self.check_all_api_methods(obj) def test_device_unavailable(self): @@ -9382,10 +9380,7 @@ def test_expect_on_multiphase_put_diconnect(self): conn.send(b'c\r\n--boundary123\r\n') # disconnect client - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() for i in range(2): sleep(0) self.assertFalse(self.logger.get_lines_for_level('error')) @@ -9495,10 +9490,7 @@ def test_multiphase_put_client_disconnect_right_before_commit(self): with self._check_multiphase_put_commit_handling() as context: conn = context['conn'] # just bail straight out - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() sleep(0) put_timestamp = context['put_timestamp'] @@ -9539,10 +9531,7 @@ def test_multiphase_put_client_disconnect_in_the_middle_of_commit(self): conn.send(to_send) # and then bail out - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() sleep(0) put_timestamp = context['put_timestamp'] @@ -9669,12 +9658,8 @@ def test_multiphase_put_metadata_footer(self): 'Content-Type': 'text/plain'} for k, v in actual_meta.items(): # See diskfile.py:_decode_metadata - if six.PY2: - self.assertIsInstance(k, six.binary_type) - self.assertIsInstance(v, six.binary_type) - else: - self.assertIsInstance(k, six.text_type) - self.assertIsInstance(v, six.text_type) + self.assertIsInstance(k, str) + self.assertIsInstance(v, str) self.assertIsNotNone(actual_meta.pop('ETag', None)) self.assertEqual(expected_meta, actual_meta) # but no other files @@ -9722,10 +9707,7 @@ def test_multiphase_put_metadata_footer_disconnect(self): conn.send(to_send) # and then bail out - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() sleep(0) # and make sure it demonstrates the client disconnect @@ -9920,10 +9902,7 @@ def test_multiphase_put_drains_extra_commit_junk_disconnect(self): conn.send(to_send) # and then bail out - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() # the object server needs to recognize the socket is closed # or at least timeout, we'll have to wait @@ -9996,7 +9975,7 @@ def setUp(self): self.wsgi_greenlet = spawn( wsgi.server, listener, self.object_controller, NullLogger()) - self.http_conn = httplib.HTTPConnection('127.0.0.1', port) + self.http_conn = http_client.HTTPConnection('127.0.0.1', port) self.http_conn.connect() def tearDown(self): diff --git a/test/unit/obj/test_ssync.py b/test/unit/obj/test_ssync.py index d5da5a6e49..f4793d3b5c 100644 --- a/test/unit/obj/test_ssync.py +++ b/test/unit/obj/test_ssync.py @@ -19,7 +19,7 @@ import unittest import eventlet -from six.moves import urllib +import urllib.parse from swift.common.exceptions import DiskFileNotExist, DiskFileError, \ DiskFileDeleted, DiskFileExpired diff --git a/test/unit/obj/test_ssync_receiver.py b/test/unit/obj/test_ssync_receiver.py index 74ae43064c..1d6b42a147 100644 --- a/test/unit/obj/test_ssync_receiver.py +++ b/test/unit/obj/test_ssync_receiver.py @@ -21,7 +21,7 @@ import eventlet import mock -import six +import itertools from swift.common import bufferedhttp from swift.common import exceptions @@ -41,10 +41,7 @@ from test.unit.obj.common import write_diskfile -if six.PY2: - UNPACK_ERR = b":ERROR: 0 'need more than 1 value to unpack'" -else: - UNPACK_ERR = b":ERROR: 0 'not enough values to unpack (expected 2, got 1)'" +UNPACK_ERR = b":ERROR: 0 'not enough values to unpack (expected 2, got 1)'" @unit.patch_policies() @@ -116,16 +113,10 @@ def test_SSYNC_semaphore_locked(self): req = swob.Request.blank( '/device/partition', environ={'REQUEST_METHOD': 'SSYNC'}) resp = req.get_response(self.controller) - if six.PY2: - last_line = ( - b":ERROR: 503 '

Service Unavailable

The " - b"server is currently unavailable. Please try again at a " - b"later time.

'") - else: - last_line = ( - b":ERROR: 503 b'

Service Unavailable

The " - b"server is currently unavailable. Please try again at a " - b"later time.

'") + last_line = ( + b":ERROR: 503 b'

Service Unavailable

The " + b"server is currently unavailable. Please try again at a " + b"later time.

'") self.assertEqual( self.body_lines(resp.body), [last_line]) @@ -353,7 +344,7 @@ def _concurrent_ssync(path1, path2): body_lines1 = [] body_lines2 = [] - for chunk1, chunk2 in six.moves.zip_longest(rcvr1(), rcvr2()): + for chunk1, chunk2 in itertools.zip_longest(rcvr1(), rcvr2()): if chunk1 and chunk1.strip(): body_lines1.append(chunk1.strip()) if chunk2 and chunk2.strip(): @@ -1586,12 +1577,8 @@ def _DELETE(request): 'DELETE /a/c/o\r\n\r\n' 'DELETE /a/c/o\r\n\r\n') resp = req.get_response(self.controller) - if six.PY2: - final_line = (b":ERROR: 500 'ERROR: With :UPDATES: " - b"3 failures to 0 successes'") - else: - final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " - b"3 failures to 0 successes'") + final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " + b"3 failures to 0 successes'") self.assertEqual( self.body_lines(resp.body), [b':MISSING_CHECK: START', b':MISSING_CHECK: END', final_line]) @@ -1650,12 +1637,8 @@ def _DELETE(request): 'DELETE /a/c/o\r\n\r\n' ':UPDATES: END\r\n') resp = req.get_response(self.controller) - if six.PY2: - final_line = (b":ERROR: 500 'ERROR: With :UPDATES: " - b"4 failures to 3 successes'") - else: - final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " - b"4 failures to 3 successes'") + final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " + b"4 failures to 3 successes'") self.assertEqual( self.body_lines(resp.body), [b':MISSING_CHECK: START', b':MISSING_CHECK: END', @@ -2254,12 +2237,8 @@ def readline(self, hint=-1): '1') req.environ['wsgi.input'] = _IgnoreReadlineHint(req.body) resp = req.get_response(self.controller) - if six.PY2: - final_line = (b":ERROR: 500 'ERROR: With :UPDATES: " - b"2 failures to 0 successes'") - else: - final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " - b"2 failures to 0 successes'") + final_line = (b":ERROR: 500 b'ERROR: With :UPDATES: " + b"2 failures to 0 successes'") self.assertEqual( self.body_lines(resp.body), [b':MISSING_CHECK: START', b':MISSING_CHECK: END', final_line]) @@ -2354,7 +2333,7 @@ def test_SSYNC_disconnect(self): swob.HTTPInternalServerError() success, _ = sender() self.assertFalse(success) - stderr = six.StringIO() + stderr = io.StringIO() with mock.patch('sys.stderr', stderr): # let gc and eventlet spin a bit del sender diff --git a/test/unit/obj/test_ssync_sender.py b/test/unit/obj/test_ssync_sender.py index 2de393a4d1..f15c2f6e98 100644 --- a/test/unit/obj/test_ssync_sender.py +++ b/test/unit/obj/test_ssync_sender.py @@ -19,7 +19,7 @@ import eventlet import mock -import six +import urllib.parse from swift.common import exceptions, utils from swift.common.storage_policy import POLICIES @@ -59,8 +59,7 @@ class FakeResponse(ssync_sender.SsyncBufferedHTTPResponse): def __init__(self, chunk_body='', headers=None): self.status = 200 self.close_called = False - if not six.PY2: - chunk_body = chunk_body.encode('ascii') + chunk_body = chunk_body.encode('ascii') if chunk_body: self.fp = io.BytesIO( b'%x\r\n%s\r\n0\r\n\r\n' % (len(chunk_body), chunk_body)) @@ -1706,11 +1705,11 @@ def _check_send_put(self, obj_name, meta_value, extra_metadata=extra_metadata, commit=durable) expected = dict(df.get_metadata()) - expected['body'] = body if six.PY2 else body.decode('ascii') + expected['body'] = body.decode('ascii') expected['chunk_size'] = len(body) expected['meta'] = meta_value expected['meta_name'] = meta_name - path = six.moves.urllib.parse.quote(expected['name']) + path = urllib.parse.quote(expected['name']) expected['path'] = path no_commit = '' if durable else 'X-Backend-No-Commit: True\r\n' expected['no_commit'] = no_commit @@ -1773,7 +1772,7 @@ def _check_send_post(self, obj_name, meta_value): # Note that diskfile expects obj_name to be a native string # but metadata to be wsgi strings df.write_metadata(newer_metadata) - path = six.moves.urllib.parse.quote(df.read_metadata()['name']) + path = urllib.parse.quote(df.read_metadata()['name']) wire_meta = wsgi_to_bytes(meta_value) length = format(61 + len(path) + len(wire_meta), 'x') diff --git a/test/unit/obj/test_updater.py b/test/unit/obj/test_updater.py index c4bea6a352..e9a10c346f 100644 --- a/test/unit/obj/test_updater.py +++ b/test/unit/obj/test_updater.py @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. import eventlet -import six.moves.cPickle as pickle -from six.moves.queue import PriorityQueue +import pickle +from queue import PriorityQueue import mock import os import unittest diff --git a/test/unit/proxy/controllers/test_base.py b/test/unit/proxy/controllers/test_base.py index f168996219..a3ad0c29e4 100644 --- a/test/unit/proxy/controllers/test_base.py +++ b/test/unit/proxy/controllers/test_base.py @@ -21,8 +21,6 @@ import unittest import mock -import six - from swift.proxy import server as proxy_server from swift.proxy.controllers.base import headers_to_container_info, \ headers_to_account_info, headers_to_object_info, get_container_info, \ @@ -585,8 +583,6 @@ def test_get_container_info_no_cache(self): self.assertEqual(resp['bytes'], 6666) self.assertEqual(resp['object_count'], 1000) expected = u'\U0001F334' - if six.PY2: - expected = expected.encode('utf8') self.assertEqual(resp['versions'], expected) def test_get_container_info_no_account(self): @@ -659,8 +655,6 @@ def test_get_container_info_cache(self): self.assertEqual(resp['object_count'], 10) self.assertEqual(resp['status'], 404) expected = u'\U0001F4A9' - if six.PY2: - expected = expected.encode('utf8') self.assertEqual(resp['versions'], expected) for subdict in resp.values(): @@ -702,8 +696,6 @@ def test_get_container_info_only_lookup_cache(self): self.assertEqual(resp['object_count'], 10) self.assertEqual(resp['status'], 404) expected = u'\U0001F4A9' - if six.PY2: - expected = expected.encode('utf8') self.assertEqual(resp['versions'], expected) for subdict in resp.values(): if isinstance(subdict, dict): @@ -726,8 +718,6 @@ def test_get_cache_key(self): # Expected result should always be native string expected = u'container/\N{SNOWMAN}/\U0001F334' - if six.PY2: - expected = expected.encode('utf8') self.assertEqual(get_cache_key(u"\N{SNOWMAN}", u"\U0001F334"), expected) @@ -1724,7 +1714,7 @@ def mock_find_source(): resp = handler.get_working_response() resp.app_iter.close() # verify that iter exited - self.assertEqual({1: ['next', 'close', '__del__']}, + self.assertEqual({1: ['__next__', 'close', '__del__']}, factory.captured_calls) self.assertEqual(["Client disconnected on read of 'some-path'"], self.logger.get_lines_for_level('info')) @@ -1742,7 +1732,7 @@ def mock_find_source(): resp = handler.get_working_response() next(resp.app_iter) resp.app_iter.close() - self.assertEqual({1: ['next', 'close', '__del__']}, + self.assertEqual({1: ['__next__', 'close', '__del__']}, factory.captured_calls) self.assertEqual([], self.logger.get_lines_for_level('warning')) self.assertEqual([], self.logger.get_lines_for_level('info')) diff --git a/test/unit/proxy/controllers/test_container.py b/test/unit/proxy/controllers/test_container.py index b94c6f4804..74b4f18e9f 100644 --- a/test/unit/proxy/controllers/test_container.py +++ b/test/unit/proxy/controllers/test_container.py @@ -19,12 +19,8 @@ import unittest from eventlet import Timeout -import six -from six.moves import urllib -if six.PY2: - from itertools import izip_longest as zip_longest -else: - from itertools import zip_longest +import urllib.parse +from itertools import zip_longest from swift.common.constraints import CONTAINER_LISTING_LIMIT from swift.common.swob import Request, bytes_to_wsgi, str_to_wsgi, wsgi_quote @@ -537,18 +533,12 @@ def _make_shard_resp_hdrs(self, sr_objs, extra_hdrs=None): return hdrs def _make_shard_objects(self, shard_range): - if six.PY2: - lower = ord(shard_range.lower.decode('utf8')[0] - if shard_range.lower else '@') - upper = ord(shard_range.upper.decode('utf8')[0] - if shard_range.upper else u'\U0001ffff') - else: - lower = ord(shard_range.lower[0] if shard_range.lower else '@') - upper = ord(shard_range.upper[0] if shard_range.upper - else '\U0001ffff') + lower = ord(shard_range.lower[0] if shard_range.lower else '@') + upper = ord(shard_range.upper[0] if shard_range.upper + else '\U0001ffff') - objects = [{'name': six.unichr(i), 'bytes': i, - 'hash': 'hash%s' % six.unichr(i), + objects = [{'name': chr(i), 'bytes': i, + 'hash': 'hash%s' % chr(i), 'content_type': 'text/plain', 'deleted': 0, 'last_modified': next(self.ts_iter).isoformat} for i in range(lower + 1, upper + 1)][:1024] @@ -603,11 +593,8 @@ def name(obj): with annotate_failure('Request check at index %d.' % i): # strip off /sdx/0/ from path self.assertEqual(exp_path, req['path'][7:]) - if six.PY2: - got_params = dict(urllib.parse.parse_qsl(req['qs'], True)) - else: - got_params = dict(urllib.parse.parse_qsl( - req['qs'], True, encoding='latin1')) + got_params = dict(urllib.parse.parse_qsl( + req['qs'], True, encoding='latin1')) self.assertEqual(dict(exp_params, format='json'), got_params) for k, v in exp_headers.items(): self.assertIn(k, req['headers']) @@ -3126,12 +3113,8 @@ def _check_backend_req(self, req, backend_req, extra_params=None, expected_params = {'states': 'listing', 'format': 'json'} if extra_params: expected_params.update(extra_params) - if six.PY2: - backend_params = dict(urllib.parse.parse_qsl( - backend_req['qs'], True)) - else: - backend_params = dict(urllib.parse.parse_qsl( - backend_req['qs'], True, encoding='latin1')) + backend_params = dict(urllib.parse.parse_qsl( + backend_req['qs'], True, encoding='latin1')) self.assertEqual(expected_params, backend_params) backend_hdrs = backend_req['headers'] diff --git a/test/unit/proxy/controllers/test_obj.py b/test/unit/proxy/controllers/test_obj.py index da76d907b4..f434a96c3a 100644 --- a/test/unit/proxy/controllers/test_obj.py +++ b/test/unit/proxy/controllers/test_obj.py @@ -29,14 +29,9 @@ from eventlet import Timeout, sleep from eventlet.queue import Empty -import six -from six import StringIO -from six.moves import range -from six.moves.urllib.parse import quote, parse_qsl -if six.PY2: - from email.parser import FeedParser as EmailFeedParser -else: - from email.parser import BytesFeedParser as EmailFeedParser +from io import StringIO +from urllib.parse import quote, parse_qsl +from email.parser import BytesFeedParser as EmailFeedParser import swift from swift.common import utils, swob, exceptions @@ -1814,35 +1809,23 @@ def do_test(statuses): req, log_lines = do_test((201, (100, Exception('boom')), 201)) self.assertIn('ERROR with Object server', log_lines[0]) - if six.PY3: - self.assertIn(req.path, log_lines[0]) - else: - self.assertIn(req.path.decode('utf-8'), log_lines[0]) + self.assertIn(req.path, log_lines[0]) self.assertIn('Trying to get final status of PUT', log_lines[0]) req, log_lines = do_test((201, (100, Timeout()), 201)) self.assertIn('ERROR with Object server', log_lines[0]) - if six.PY3: - self.assertIn(req.path, log_lines[0]) - else: - self.assertIn(req.path.decode('utf-8'), log_lines[0]) + self.assertIn(req.path, log_lines[0]) self.assertIn('Trying to get final status of PUT', log_lines[0]) req, log_lines = do_test((201, (100, 507), 201)) self.assertIn('ERROR Insufficient Storage', log_lines[0]) req, log_lines = do_test((201, (100, 500), 201)) - if six.PY3: - # We allow the b'' in logs because we want to see bad characters. - self.assertIn( - "ERROR 500 b'' Trying to PUT /v1/AUTH_kilroy/%ED%88%8E/" - "%E9%90%89 From Object Server", log_lines[0]) - self.assertIn(req.path, log_lines[0]) - else: - self.assertIn( - 'ERROR 500 Trying to PUT /v1/AUTH_kilroy/%ED%88%8E/%E9%90%89 ' - 'From Object Server', log_lines[0]) - self.assertIn(req.path.decode('utf-8'), log_lines[0]) + # We allow the b'' in logs because we want to see bad characters. + self.assertIn( + "ERROR 500 b'' Trying to PUT /v1/AUTH_kilroy/%ED%88%8E/" + "%E9%90%89 From Object Server", log_lines[0]) + self.assertIn(req.path, log_lines[0]) def test_DELETE_errors(self): # verify logged errors with and without non-ascii characters in path @@ -1863,19 +1846,13 @@ def do_test(path, statuses): req, log_lines = do_test('/AUTH_kilroy/ascii/ascii', (201, 500, 201, 201)) self.assertIn('Trying to DELETE', log_lines[0]) - if six.PY3: - self.assertIn(req.swift_entity_path, log_lines[0]) - else: - self.assertIn(req.swift_entity_path.decode('utf-8'), log_lines[0]) + self.assertIn(req.swift_entity_path, log_lines[0]) self.assertIn(' From Object Server', log_lines[0]) req, log_lines = do_test('/AUTH_kilroy/%ED%88%8E/%E9%90%89', (201, 500, 201, 201)) self.assertIn('Trying to DELETE', log_lines[0]) - if six.PY3: - self.assertIn(req.swift_entity_path, log_lines[0]) - else: - self.assertIn(req.swift_entity_path.decode('utf-8'), log_lines[0]) + self.assertIn(req.swift_entity_path, log_lines[0]) self.assertIn(' From Object Server', log_lines[0]) req, log_lines = do_test('/AUTH_kilroy/ascii/ascii', @@ -1889,19 +1866,13 @@ def do_test(path, statuses): req, log_lines = do_test('/AUTH_kilroy/ascii/ascii', (201, Exception(), 201, 201)) self.assertIn('Trying to DELETE', log_lines[0]) - if six.PY3: - self.assertIn(req.swift_entity_path, log_lines[0]) - else: - self.assertIn(req.swift_entity_path.decode('utf-8'), log_lines[0]) + self.assertIn(req.swift_entity_path, log_lines[0]) self.assertIn('ERROR with Object server', log_lines[0]) req, log_lines = do_test('/AUTH_kilroy/%ED%88%8E/%E9%90%89', (201, Exception(), 201, 201)) self.assertIn('Trying to DELETE', log_lines[0]) - if six.PY3: - self.assertIn(req.swift_entity_path, log_lines[0]) - else: - self.assertIn(req.swift_entity_path.decode('utf-8'), log_lines[0]) + self.assertIn(req.swift_entity_path, log_lines[0]) self.assertIn('ERROR with Object server', log_lines[0]) def test_DELETE_with_write_affinity(self): @@ -3158,7 +3129,7 @@ def _make_ec_archive_bodies(self, test_body, policy=None): def _make_ec_object_stub(self, pattern='test', policy=None, timestamp=None): policy = policy or self.policy - if isinstance(pattern, six.text_type): + if isinstance(pattern, str): pattern = pattern.encode('utf-8') test_body = pattern * policy.ec_segment_size test_body = test_body[:-random.randint(1, 1000)] @@ -3895,7 +3866,7 @@ def test_GET_with_body(self): self.assertEqual(len(real_body), len(sanity_body)) self.assertEqual(real_body, sanity_body) - # list(zip(...)) for py3 compatibility (zip is lazy there) + # list(zip(...)) since zip is lazy node_fragments = list(zip(*fragment_payloads)) self.assertEqual(len(node_fragments), self.replicas()) # sanity headers = {'X-Object-Sysmeta-Ec-Content-Length': str(len(real_body))} @@ -8121,10 +8092,7 @@ def test_get_namespaces_empty_body(self): 'includes': '1_test', 'states': 'updating'}, actual_params) - if six.PY2: - self.assertIn('No JSON', err) - else: - self.assertIn('JSONDecodeError', err) + self.assertIn('JSONDecodeError', err) self.assertFalse(error_lines[1:]) def test_get_namespaces_not_a_list(self): diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 13d2ce3f1e..fadc735d65 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -45,12 +45,10 @@ import mock from eventlet import sleep, spawn, wsgi, Timeout, debug -from eventlet.green import httplib +from eventlet.green.http import client as http_client from io import BytesIO -import six -from six.moves import range -from six.moves.urllib.parse import quote, parse_qsl +from urllib.parse import quote, parse_qsl from test import listen_zero from test.debug_logger import debug_logger, FakeStatsdClient @@ -147,13 +145,10 @@ def sortHeaderNames(headerNames): def parse_headers_string(headers_str): headers_dict = HeaderKeyDict() - for line in headers_str.split(b'\r\n'): - if b': ' in line: - header, value = line.split(b': ', 1) - if six.PY2: - headers_dict[header] = value - else: - headers_dict[header.decode('utf8')] = value.decode('utf8') + for line in headers_str.decode('utf8').split('\r\n'): + if ': ' in line: + header, value = line.split(': ', 1) + headers_dict[header] = value return headers_dict @@ -1190,7 +1185,7 @@ def test_exception_occurred_replication_ip_port_logging(self): for node in annotated_nodes])) def test_exception_occurred(self): - def do_test(additional_info): + def do_test(expected_info): logger = debug_logger('test') suppression_limit = 10 app = proxy_server.Application( @@ -1202,11 +1197,6 @@ def do_test(additional_info): node_key = app.error_limiter.node_key(node) self.assertNotIn(node_key, app.error_limiter.stats) # sanity - if six.PY2: - expected_info = additional_info.decode('utf8') - else: - expected_info = additional_info - incremented_limit_samples = [] for i in range(suppression_limit + 1): try: @@ -1214,7 +1204,7 @@ def do_test(additional_info): except Exception as err: caught_exc = err app.exception_occurred( - node, 'server-type', additional_info) + node, 'server-type', expected_info) self.assertEqual(i + 1, node_error_count(app, node)) line = logger.get_lines_for_level('error')[i] self.assertIn('server-type server', line) @@ -1251,10 +1241,7 @@ def do_test(msg): node_key = app.error_limiter.node_key(node) self.assertNotIn(node_key, app.error_limiter.stats) # sanity - if six.PY2: - expected_msg = msg.decode('utf8') - else: - expected_msg = msg + expected_msg = msg incremented_limit_samples = [] for i in range(suppression_limit + 1): app.error_occurred(node, msg) @@ -6978,10 +6965,7 @@ def request_init(self, *args, **kwargs): exp = b'HTTP/1.1 200' self.assertEqual(headers[:len(exp)], exp) fd.read(1) - if six.PY2: - sock.fd._sock.close() - else: - sock.fd._real_close() + sock.fd._real_close() # Make sure the GC is run again for pythons without reference # counting for i in range(4): @@ -8590,10 +8574,7 @@ def __exit__(self, typ, value, tb): # read most of the object, and disconnect fd.read(10) - if six.PY2: - sock.fd._sock.close() - else: - sock.fd._real_close() + sock.fd._real_close() self._sleep_enough( lambda: _test_servers[0].logger.get_lines_for_level('warning')) @@ -9293,7 +9274,7 @@ def _check_disconnect_cleans_up(self, policy_name, is_chunked=False): proxy_port = _test_sockets[0].getsockname()[1] def put(path, headers=None, body=None): - conn = httplib.HTTPConnection('localhost', proxy_port) + conn = http_client.HTTPConnection('localhost', proxy_port) try: conn.connect() conn.putrequest('PUT', path) @@ -9310,10 +9291,7 @@ def put(path, headers=None, body=None): finally: # seriously - shut this mother down if conn.sock: - if six.PY2: - conn.sock.fd._sock.close() - else: - conn.sock.fd._real_close() + conn.sock.fd._real_close() return resp, body # ensure container @@ -9509,10 +9487,7 @@ def _get_obj(self, range_value, obj_name=None, ignore_range_if=''): return (status_code, headers, gotten_obj) def _parse_multipart(self, content_type, body): - if six.PY2: - parser = email.parser.FeedParser() - else: - parser = email.parser.BytesFeedParser() + parser = email.parser.BytesFeedParser() if not isinstance(content_type, bytes): content_type = content_type.encode('utf8') parser.feed(b"Content-Type: %s\r\n\r\n" % content_type) @@ -9627,9 +9602,7 @@ def test_unsatisfiable_socket_leak(self): class LeakTrackingHTTPResponse(BufferedHTTPResponse): def begin(self): - # no super(); we inherit from an old-style class (it's - # httplib's fault; don't try and fix it). - retval = BufferedHTTPResponse.begin(self) + retval = super(BufferedHTTPResponse, self).begin() if self.status != 204: # This mock is overly broad and catches account and # container HEAD requests too. We don't care about diff --git a/test/unit/proxy/test_sysmeta.py b/test/unit/proxy/test_sysmeta.py index c7f433ca3f..c672140d37 100644 --- a/test/unit/proxy/test_sysmeta.py +++ b/test/unit/proxy/test_sysmeta.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from six.moves.urllib.parse import quote +from urllib.parse import quote import unittest import os