From aa764b9a2d24be71861713ed187f81592f3df4786ee50584c42437dbeff2c06d Mon Sep 17 00:00:00 2001 From: Robert Schweikert Date: Tue, 11 Oct 2022 12:30:09 +0000 Subject: [PATCH] Accepting request 1009776 from home:mcepl:branches:devel:languages:python:aws - Add remove-six.patch, which eliminates need for the six dependency. OBS-URL: https://build.opensuse.org/request/show/1009776 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:aws/python-botocore?expand=0&rev=150 --- python-botocore.changes | 5 + python-botocore.spec | 8 +- remove-six.patch | 1918 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1928 insertions(+), 3 deletions(-) create mode 100644 remove-six.patch diff --git a/python-botocore.changes b/python-botocore.changes index a3d07a3..065f1d4 100644 --- a/python-botocore.changes +++ b/python-botocore.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Oct 11 11:46:31 UTC 2022 - Matej Cepl + +- Add remove-six.patch, which eliminates need for the six dependency. + ------------------------------------------------------------------- Tue Oct 4 09:36:03 UTC 2022 - John Paul Adrian Glaubitz diff --git a/python-botocore.spec b/python-botocore.spec index a19e7c8..4835ae7 100644 --- a/python-botocore.spec +++ b/python-botocore.spec @@ -34,6 +34,9 @@ Summary: Python interface for AWS License: Apache-2.0 URL: https://github.com/boto/botocore Source: https://files.pythonhosted.org/packages/source/b/botocore/botocore-%{version}.tar.gz +# PATCH-FIX-UPSTREAM remove-six.patch mcepl@suse.com +# Removes dependency on six. +Patch0: remove-six.patch BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -42,7 +45,6 @@ Requires: python-jmespath >= 0.7.1 Requires: python-python-dateutil < 3.0.0 Requires: python-python-dateutil >= 2.1 Requires: python-requests -Requires: python-six Requires: python-urllib3 < 1.27 Requires: python-urllib3 >= 1.25.4 BuildArch: noarch @@ -58,7 +60,7 @@ BuildRequires: procps A low-level interface to a growing number of Amazon Web Services. %prep -%setup -q -n botocore-%{version} +%autosetup -p1 -n botocore-%{version} # remove bundled cacert.pem rm botocore/cacert.pem @@ -82,7 +84,7 @@ sed -i 's/botocore\.vendored\.//' botocore/*.py tests/functional/*.py tests/inte %check # TODO: Figure out whether integration tests are possible offline # no_bare_six_imports: we "fixed" that above. -%pytest --ignore tests/integration -k "not no_bare_six_imports" +%pytest --ignore tests/integration %endif %if !%{with test} diff --git a/remove-six.patch b/remove-six.patch new file mode 100644 index 0000000..34f3b5f --- /dev/null +++ b/remove-six.patch @@ -0,0 +1,1918 @@ +--- + botocore/compat.py | 6 + botocore/configloader.py | 6 + botocore/docs/bcdoc/docstringparser.py | 13 + botocore/httpsession.py | 2 + botocore/parsers.py | 7 + botocore/utils.py | 2 + botocore/vendored/six.py | 998 --------------------------------- + tests/functional/test_six_imports.py | 58 - + tests/functional/test_six_threading.py | 61 -- + tests/integration/test_client_http.py | 9 + tests/integration/test_glacier.py | 4 + tests/unit/auth/test_signers.py | 9 + tests/unit/auth/test_sigv4.py | 14 + tests/unit/docs/bcdoc/test_style.py | 12 + tests/unit/test_awsrequest.py | 6 + tests/unit/test_client.py | 6 + tests/unit/test_configloader.py | 6 + tests/unit/test_credentials.py | 4 + tests/unit/test_endpoint.py | 8 + tests/unit/test_handlers.py | 19 + tests/unit/test_response.py | 3 + tests/unit/test_serialize.py | 4 + tests/unit/test_utils.py | 18 + tests/unit/test_validate.py | 4 + tests/unit/test_waiters.py | 4 + 25 files changed, 81 insertions(+), 1202 deletions(-) + +--- a/botocore/compat.py ++++ b/botocore/compat.py +@@ -17,6 +17,7 @@ import sys + import inspect + import warnings + import hashlib ++import http.client + import logging + import shlex + import re +@@ -25,7 +26,6 @@ from collections import OrderedDict + from collections.abc import MutableMapping + from math import floor + +-from botocore.vendored import six + from botocore.exceptions import MD5UnavailableError + from dateutil.tz import tzlocal + from urllib3 import exceptions +@@ -33,9 +33,7 @@ from urllib3 import exceptions + logger = logging.getLogger(__name__) + + +-from botocore.vendored.six.moves import http_client +- +-class HTTPHeaders(http_client.HTTPMessage): ++class HTTPHeaders(http.client.HTTPMessage): + pass + + from urllib.parse import ( +--- a/botocore/configloader.py ++++ b/botocore/configloader.py +@@ -11,13 +11,13 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. ++import configparser + import copy + import os + import shlex + import sys + + import botocore.exceptions +-from botocore.compat import six + + + def multi_file_load_config(*filenames): +@@ -143,10 +143,10 @@ def raw_config_parse(config_filename, pa + path = os.path.expanduser(path) + if not os.path.isfile(path): + raise botocore.exceptions.ConfigNotFound(path=_unicode_path(path)) +- cp = six.moves.configparser.RawConfigParser() ++ cp = configparser.RawConfigParser() + try: + cp.read([path]) +- except (six.moves.configparser.Error, UnicodeDecodeError) as e: ++ except (configparser.Error, UnicodeDecodeError) as e: + raise botocore.exceptions.ConfigParseError( + path=_unicode_path(path), error=e + ) from None +--- a/botocore/docs/bcdoc/docstringparser.py ++++ b/botocore/docs/bcdoc/docstringparser.py +@@ -10,10 +10,9 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. +-from botocore.compat import six ++import html.parser + +- +-class DocStringParser(six.moves.html_parser.HTMLParser): ++class DocStringParser(html.parser.HTMLParser): + """ + A simple HTML parser. Focused on converting the subset of HTML + that appears in the documentation strings of the JSON models into +@@ -23,20 +22,20 @@ class DocStringParser(six.moves.html_par + def __init__(self, doc): + self.tree = None + self.doc = doc +- six.moves.html_parser.HTMLParser.__init__(self) ++ html.parser.HTMLParser.__init__(self) + + def reset(self): +- six.moves.html_parser.HTMLParser.reset(self) ++ html.parser.HTMLParser.reset(self) + self.tree = HTMLTree(self.doc) + + def feed(self, data): + # HTMLParser is an old style class, so the super() method will not work. +- six.moves.html_parser.HTMLParser.feed(self, data) ++ html.parser.HTMLParser.feed(self, data) + self.tree.write() + self.tree = HTMLTree(self.doc) + + def close(self): +- six.moves.html_parser.HTMLParser.close(self) ++ html.parser.HTMLParser.close(self) + # Write if there is anything remaining. + self.tree.write() + self.tree = HTMLTree(self.doc) +--- a/botocore/httpsession.py ++++ b/botocore/httpsession.py +@@ -66,7 +66,7 @@ from botocore.exceptions import ( + ReadTimeoutError, + SSLError, + ) +-from botocore.vendored.six.moves.urllib_parse import unquote ++from urllib.parse import unquote + + filter_ssl_warnings() + logger = logging.getLogger(__name__) +--- a/botocore/parsers.py ++++ b/botocore/parsers.py +@@ -115,11 +115,12 @@ Each call to ``parse()`` returns a dict + + """ + import base64 ++import http.client + import json + import logging + import re + +-from botocore.compat import ETree, XMLParseError, six ++from botocore.compat import ETree, XMLParseError + from botocore.eventstream import EventStream, NoInitialResponseError + from botocore.utils import ( + is_json_value_header, +@@ -306,7 +307,7 @@ class ResponseParser: + return { + 'Error': { + 'Code': str(response['status_code']), +- 'Message': six.moves.http_client.responses.get( ++ 'Message': http.client.responses.get( + response['status_code'], '' + ), + }, +@@ -1053,7 +1054,7 @@ class RestXMLParser(BaseRestParser, Base + return { + 'Error': { + 'Code': str(response['status_code']), +- 'Message': six.moves.http_client.responses.get( ++ 'Message': http.client.responses.get( + response['status_code'], '' + ), + }, +--- a/botocore/utils.py ++++ b/botocore/utils.py +@@ -82,7 +82,7 @@ from botocore.exceptions import ( + UnsupportedS3ControlArnError, + UnsupportedS3ControlConfigurationError, + ) +-from botocore.vendored.six.moves.urllib.request import getproxies, proxy_bypass ++from urllib.request import getproxies, proxy_bypass + + logger = logging.getLogger(__name__) + DEFAULT_METADATA_SERVICE_TIMEOUT = 1 +--- a/botocore/vendored/six.py ++++ /dev/null +@@ -1,998 +0,0 @@ +-# Copyright (c) 2010-2020 Benjamin Peterson +-# +-# Permission is hereby granted, free of charge, to any person obtaining a copy +-# of this software and associated documentation files (the "Software"), to deal +-# in the Software without restriction, including without limitation the rights +-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-# copies of the Software, and to permit persons to whom the Software is +-# furnished to do so, subject to the following conditions: +-# +-# The above copyright notice and this permission notice shall be included in all +-# copies or substantial portions of the Software. +-# +-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-# SOFTWARE. +- +-"""Utilities for writing code that runs on Python 2 and 3""" +- +-from __future__ import absolute_import +- +-import functools +-import itertools +-import operator +-import sys +-import types +- +-__author__ = "Benjamin Peterson " +-__version__ = "1.16.0" +- +- +-# Useful for very coarse version differentiation. +-PY2 = sys.version_info[0] == 2 +-PY3 = sys.version_info[0] == 3 +-PY34 = sys.version_info[0:2] >= (3, 4) +- +-if PY3: +- string_types = str, +- integer_types = int, +- class_types = type, +- text_type = str +- binary_type = bytes +- +- MAXSIZE = sys.maxsize +-else: +- string_types = basestring, +- integer_types = (int, long) +- class_types = (type, types.ClassType) +- text_type = unicode +- binary_type = str +- +- if sys.platform.startswith("java"): +- # Jython always uses 32 bits. +- MAXSIZE = int((1 << 31) - 1) +- else: +- # It's possible to have sizeof(long) != sizeof(Py_ssize_t). +- class X(object): +- +- def __len__(self): +- return 1 << 31 +- try: +- len(X()) +- except OverflowError: +- # 32-bit +- MAXSIZE = int((1 << 31) - 1) +- else: +- # 64-bit +- MAXSIZE = int((1 << 63) - 1) +- del X +- +-if PY34: +- from importlib.util import spec_from_loader +-else: +- spec_from_loader = None +- +- +-def _add_doc(func, doc): +- """Add documentation to a function.""" +- func.__doc__ = doc +- +- +-def _import_module(name): +- """Import module, returning the module after the last dot.""" +- __import__(name) +- return sys.modules[name] +- +- +-class _LazyDescr(object): +- +- def __init__(self, name): +- self.name = name +- +- def __get__(self, obj, tp): +- result = self._resolve() +- setattr(obj, self.name, result) # Invokes __set__. +- try: +- # This is a bit ugly, but it avoids running this again by +- # removing this descriptor. +- delattr(obj.__class__, self.name) +- except AttributeError: +- pass +- return result +- +- +-class MovedModule(_LazyDescr): +- +- def __init__(self, name, old, new=None): +- super(MovedModule, self).__init__(name) +- if PY3: +- if new is None: +- new = name +- self.mod = new +- else: +- self.mod = old +- +- def _resolve(self): +- return _import_module(self.mod) +- +- def __getattr__(self, attr): +- _module = self._resolve() +- value = getattr(_module, attr) +- setattr(self, attr, value) +- return value +- +- +-class _LazyModule(types.ModuleType): +- +- def __init__(self, name): +- super(_LazyModule, self).__init__(name) +- self.__doc__ = self.__class__.__doc__ +- +- def __dir__(self): +- attrs = ["__doc__", "__name__"] +- attrs += [attr.name for attr in self._moved_attributes] +- return attrs +- +- # Subclasses should override this +- _moved_attributes = [] +- +- +-class MovedAttribute(_LazyDescr): +- +- def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): +- super(MovedAttribute, self).__init__(name) +- if PY3: +- if new_mod is None: +- new_mod = name +- self.mod = new_mod +- if new_attr is None: +- if old_attr is None: +- new_attr = name +- else: +- new_attr = old_attr +- self.attr = new_attr +- else: +- self.mod = old_mod +- if old_attr is None: +- old_attr = name +- self.attr = old_attr +- +- def _resolve(self): +- module = _import_module(self.mod) +- return getattr(module, self.attr) +- +- +-class _SixMetaPathImporter(object): +- +- """ +- A meta path importer to import six.moves and its submodules. +- +- This class implements a PEP302 finder and loader. It should be compatible +- with Python 2.5 and all existing versions of Python3 +- """ +- +- def __init__(self, six_module_name): +- self.name = six_module_name +- self.known_modules = {} +- +- def _add_module(self, mod, *fullnames): +- for fullname in fullnames: +- self.known_modules[self.name + "." + fullname] = mod +- +- def _get_module(self, fullname): +- return self.known_modules[self.name + "." + fullname] +- +- def find_module(self, fullname, path=None): +- if fullname in self.known_modules: +- return self +- return None +- +- def find_spec(self, fullname, path, target=None): +- if fullname in self.known_modules: +- return spec_from_loader(fullname, self) +- return None +- +- def __get_module(self, fullname): +- try: +- return self.known_modules[fullname] +- except KeyError: +- raise ImportError("This loader does not know module " + fullname) +- +- def load_module(self, fullname): +- try: +- # in case of a reload +- return sys.modules[fullname] +- except KeyError: +- pass +- mod = self.__get_module(fullname) +- if isinstance(mod, MovedModule): +- mod = mod._resolve() +- else: +- mod.__loader__ = self +- sys.modules[fullname] = mod +- return mod +- +- def is_package(self, fullname): +- """ +- Return true, if the named module is a package. +- +- We need this method to get correct spec objects with +- Python 3.4 (see PEP451) +- """ +- return hasattr(self.__get_module(fullname), "__path__") +- +- def get_code(self, fullname): +- """Return None +- +- Required, if is_package is implemented""" +- self.__get_module(fullname) # eventually raises ImportError +- return None +- get_source = get_code # same as get_code +- +- def create_module(self, spec): +- return self.load_module(spec.name) +- +- def exec_module(self, module): +- pass +- +-_importer = _SixMetaPathImporter(__name__) +- +- +-class _MovedItems(_LazyModule): +- +- """Lazy loading of moved objects""" +- __path__ = [] # mark as package +- +- +-_moved_attributes = [ +- MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), +- MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), +- MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), +- MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), +- MovedAttribute("intern", "__builtin__", "sys"), +- MovedAttribute("map", "itertools", "builtins", "imap", "map"), +- MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), +- MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), +- MovedAttribute("getoutput", "commands", "subprocess"), +- MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), +- MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), +- MovedAttribute("reduce", "__builtin__", "functools"), +- MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), +- MovedAttribute("StringIO", "StringIO", "io"), +- MovedAttribute("UserDict", "UserDict", "collections"), +- MovedAttribute("UserList", "UserList", "collections"), +- MovedAttribute("UserString", "UserString", "collections"), +- MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), +- MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), +- MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), +- MovedModule("builtins", "__builtin__"), +- MovedModule("configparser", "ConfigParser"), +- MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), +- MovedModule("copyreg", "copy_reg"), +- MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), +- MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), +- MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), +- MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), +- MovedModule("http_cookies", "Cookie", "http.cookies"), +- MovedModule("html_entities", "htmlentitydefs", "html.entities"), +- MovedModule("html_parser", "HTMLParser", "html.parser"), +- MovedModule("http_client", "httplib", "http.client"), +- MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), +- MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), +- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), +- MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), +- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), +- MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), +- MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), +- MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), +- MovedModule("cPickle", "cPickle", "pickle"), +- MovedModule("queue", "Queue"), +- MovedModule("reprlib", "repr"), +- MovedModule("socketserver", "SocketServer"), +- MovedModule("_thread", "thread", "_thread"), +- MovedModule("tkinter", "Tkinter"), +- MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), +- MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), +- MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), +- MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), +- MovedModule("tkinter_tix", "Tix", "tkinter.tix"), +- MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), +- MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), +- MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), +- MovedModule("tkinter_colorchooser", "tkColorChooser", +- "tkinter.colorchooser"), +- MovedModule("tkinter_commondialog", "tkCommonDialog", +- "tkinter.commondialog"), +- MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), +- MovedModule("tkinter_font", "tkFont", "tkinter.font"), +- MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), +- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", +- "tkinter.simpledialog"), +- MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), +- MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), +- MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), +- MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), +- MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), +- MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +-] +-# Add windows specific modules. +-if sys.platform == "win32": +- _moved_attributes += [ +- MovedModule("winreg", "_winreg"), +- ] +- +-for attr in _moved_attributes: +- setattr(_MovedItems, attr.name, attr) +- if isinstance(attr, MovedModule): +- _importer._add_module(attr, "moves." + attr.name) +-del attr +- +-_MovedItems._moved_attributes = _moved_attributes +- +-moves = _MovedItems(__name__ + ".moves") +-_importer._add_module(moves, "moves") +- +- +-class Module_six_moves_urllib_parse(_LazyModule): +- +- """Lazy loading of moved objects in six.moves.urllib_parse""" +- +- +-_urllib_parse_moved_attributes = [ +- MovedAttribute("ParseResult", "urlparse", "urllib.parse"), +- MovedAttribute("SplitResult", "urlparse", "urllib.parse"), +- MovedAttribute("parse_qs", "urlparse", "urllib.parse"), +- MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), +- MovedAttribute("urldefrag", "urlparse", "urllib.parse"), +- MovedAttribute("urljoin", "urlparse", "urllib.parse"), +- MovedAttribute("urlparse", "urlparse", "urllib.parse"), +- MovedAttribute("urlsplit", "urlparse", "urllib.parse"), +- MovedAttribute("urlunparse", "urlparse", "urllib.parse"), +- MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), +- MovedAttribute("quote", "urllib", "urllib.parse"), +- MovedAttribute("quote_plus", "urllib", "urllib.parse"), +- MovedAttribute("unquote", "urllib", "urllib.parse"), +- MovedAttribute("unquote_plus", "urllib", "urllib.parse"), +- MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), +- MovedAttribute("urlencode", "urllib", "urllib.parse"), +- MovedAttribute("splitquery", "urllib", "urllib.parse"), +- MovedAttribute("splittag", "urllib", "urllib.parse"), +- MovedAttribute("splituser", "urllib", "urllib.parse"), +- MovedAttribute("splitvalue", "urllib", "urllib.parse"), +- MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), +- MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), +- MovedAttribute("uses_params", "urlparse", "urllib.parse"), +- MovedAttribute("uses_query", "urlparse", "urllib.parse"), +- MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +-] +-for attr in _urllib_parse_moved_attributes: +- setattr(Module_six_moves_urllib_parse, attr.name, attr) +-del attr +- +-Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes +- +-_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), +- "moves.urllib_parse", "moves.urllib.parse") +- +- +-class Module_six_moves_urllib_error(_LazyModule): +- +- """Lazy loading of moved objects in six.moves.urllib_error""" +- +- +-_urllib_error_moved_attributes = [ +- MovedAttribute("URLError", "urllib2", "urllib.error"), +- MovedAttribute("HTTPError", "urllib2", "urllib.error"), +- MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +-] +-for attr in _urllib_error_moved_attributes: +- setattr(Module_six_moves_urllib_error, attr.name, attr) +-del attr +- +-Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes +- +-_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), +- "moves.urllib_error", "moves.urllib.error") +- +- +-class Module_six_moves_urllib_request(_LazyModule): +- +- """Lazy loading of moved objects in six.moves.urllib_request""" +- +- +-_urllib_request_moved_attributes = [ +- MovedAttribute("urlopen", "urllib2", "urllib.request"), +- MovedAttribute("install_opener", "urllib2", "urllib.request"), +- MovedAttribute("build_opener", "urllib2", "urllib.request"), +- MovedAttribute("pathname2url", "urllib", "urllib.request"), +- MovedAttribute("url2pathname", "urllib", "urllib.request"), +- MovedAttribute("getproxies", "urllib", "urllib.request"), +- MovedAttribute("Request", "urllib2", "urllib.request"), +- MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), +- MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), +- MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), +- MovedAttribute("BaseHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), +- MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), +- MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), +- MovedAttribute("FileHandler", "urllib2", "urllib.request"), +- MovedAttribute("FTPHandler", "urllib2", "urllib.request"), +- MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), +- MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), +- MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), +- MovedAttribute("urlretrieve", "urllib", "urllib.request"), +- MovedAttribute("urlcleanup", "urllib", "urllib.request"), +- MovedAttribute("URLopener", "urllib", "urllib.request"), +- MovedAttribute("FancyURLopener", "urllib", "urllib.request"), +- MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +- MovedAttribute("parse_http_list", "urllib2", "urllib.request"), +- MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +-] +-for attr in _urllib_request_moved_attributes: +- setattr(Module_six_moves_urllib_request, attr.name, attr) +-del attr +- +-Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes +- +-_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), +- "moves.urllib_request", "moves.urllib.request") +- +- +-class Module_six_moves_urllib_response(_LazyModule): +- +- """Lazy loading of moved objects in six.moves.urllib_response""" +- +- +-_urllib_response_moved_attributes = [ +- MovedAttribute("addbase", "urllib", "urllib.response"), +- MovedAttribute("addclosehook", "urllib", "urllib.response"), +- MovedAttribute("addinfo", "urllib", "urllib.response"), +- MovedAttribute("addinfourl", "urllib", "urllib.response"), +-] +-for attr in _urllib_response_moved_attributes: +- setattr(Module_six_moves_urllib_response, attr.name, attr) +-del attr +- +-Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes +- +-_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), +- "moves.urllib_response", "moves.urllib.response") +- +- +-class Module_six_moves_urllib_robotparser(_LazyModule): +- +- """Lazy loading of moved objects in six.moves.urllib_robotparser""" +- +- +-_urllib_robotparser_moved_attributes = [ +- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +-] +-for attr in _urllib_robotparser_moved_attributes: +- setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +-del attr +- +-Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes +- +-_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), +- "moves.urllib_robotparser", "moves.urllib.robotparser") +- +- +-class Module_six_moves_urllib(types.ModuleType): +- +- """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" +- __path__ = [] # mark as package +- parse = _importer._get_module("moves.urllib_parse") +- error = _importer._get_module("moves.urllib_error") +- request = _importer._get_module("moves.urllib_request") +- response = _importer._get_module("moves.urllib_response") +- robotparser = _importer._get_module("moves.urllib_robotparser") +- +- def __dir__(self): +- return ['parse', 'error', 'request', 'response', 'robotparser'] +- +-_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), +- "moves.urllib") +- +- +-def add_move(move): +- """Add an item to six.moves.""" +- setattr(_MovedItems, move.name, move) +- +- +-def remove_move(name): +- """Remove item from six.moves.""" +- try: +- delattr(_MovedItems, name) +- except AttributeError: +- try: +- del moves.__dict__[name] +- except KeyError: +- raise AttributeError("no such move, %r" % (name,)) +- +- +-if PY3: +- _meth_func = "__func__" +- _meth_self = "__self__" +- +- _func_closure = "__closure__" +- _func_code = "__code__" +- _func_defaults = "__defaults__" +- _func_globals = "__globals__" +-else: +- _meth_func = "im_func" +- _meth_self = "im_self" +- +- _func_closure = "func_closure" +- _func_code = "func_code" +- _func_defaults = "func_defaults" +- _func_globals = "func_globals" +- +- +-try: +- advance_iterator = next +-except NameError: +- def advance_iterator(it): +- return it.next() +-next = advance_iterator +- +- +-try: +- callable = callable +-except NameError: +- def callable(obj): +- return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) +- +- +-if PY3: +- def get_unbound_function(unbound): +- return unbound +- +- create_bound_method = types.MethodType +- +- def create_unbound_method(func, cls): +- return func +- +- Iterator = object +-else: +- def get_unbound_function(unbound): +- return unbound.im_func +- +- def create_bound_method(func, obj): +- return types.MethodType(func, obj, obj.__class__) +- +- def create_unbound_method(func, cls): +- return types.MethodType(func, None, cls) +- +- class Iterator(object): +- +- def next(self): +- return type(self).__next__(self) +- +- callable = callable +-_add_doc(get_unbound_function, +- """Get the function out of a possibly unbound function""") +- +- +-get_method_function = operator.attrgetter(_meth_func) +-get_method_self = operator.attrgetter(_meth_self) +-get_function_closure = operator.attrgetter(_func_closure) +-get_function_code = operator.attrgetter(_func_code) +-get_function_defaults = operator.attrgetter(_func_defaults) +-get_function_globals = operator.attrgetter(_func_globals) +- +- +-if PY3: +- def iterkeys(d, **kw): +- return iter(d.keys(**kw)) +- +- def itervalues(d, **kw): +- return iter(d.values(**kw)) +- +- def iteritems(d, **kw): +- return iter(d.items(**kw)) +- +- def iterlists(d, **kw): +- return iter(d.lists(**kw)) +- +- viewkeys = operator.methodcaller("keys") +- +- viewvalues = operator.methodcaller("values") +- +- viewitems = operator.methodcaller("items") +-else: +- def iterkeys(d, **kw): +- return d.iterkeys(**kw) +- +- def itervalues(d, **kw): +- return d.itervalues(**kw) +- +- def iteritems(d, **kw): +- return d.iteritems(**kw) +- +- def iterlists(d, **kw): +- return d.iterlists(**kw) +- +- viewkeys = operator.methodcaller("viewkeys") +- +- viewvalues = operator.methodcaller("viewvalues") +- +- viewitems = operator.methodcaller("viewitems") +- +-_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +-_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +-_add_doc(iteritems, +- "Return an iterator over the (key, value) pairs of a dictionary.") +-_add_doc(iterlists, +- "Return an iterator over the (key, [values]) pairs of a dictionary.") +- +- +-if PY3: +- def b(s): +- return s.encode("latin-1") +- +- def u(s): +- return s +- unichr = chr +- import struct +- int2byte = struct.Struct(">B").pack +- del struct +- byte2int = operator.itemgetter(0) +- indexbytes = operator.getitem +- iterbytes = iter +- import io +- StringIO = io.StringIO +- BytesIO = io.BytesIO +- del io +- _assertCountEqual = "assertCountEqual" +- if sys.version_info[1] <= 1: +- _assertRaisesRegex = "assertRaisesRegexp" +- _assertRegex = "assertRegexpMatches" +- _assertNotRegex = "assertNotRegexpMatches" +- else: +- _assertRaisesRegex = "assertRaisesRegex" +- _assertRegex = "assertRegex" +- _assertNotRegex = "assertNotRegex" +-else: +- def b(s): +- return s +- # Workaround for standalone backslash +- +- def u(s): +- return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") +- unichr = unichr +- int2byte = chr +- +- def byte2int(bs): +- return ord(bs[0]) +- +- def indexbytes(buf, i): +- return ord(buf[i]) +- iterbytes = functools.partial(itertools.imap, ord) +- import StringIO +- StringIO = BytesIO = StringIO.StringIO +- _assertCountEqual = "assertItemsEqual" +- _assertRaisesRegex = "assertRaisesRegexp" +- _assertRegex = "assertRegexpMatches" +- _assertNotRegex = "assertNotRegexpMatches" +-_add_doc(b, """Byte literal""") +-_add_doc(u, """Text literal""") +- +- +-def assertCountEqual(self, *args, **kwargs): +- return getattr(self, _assertCountEqual)(*args, **kwargs) +- +- +-def assertRaisesRegex(self, *args, **kwargs): +- return getattr(self, _assertRaisesRegex)(*args, **kwargs) +- +- +-def assertRegex(self, *args, **kwargs): +- return getattr(self, _assertRegex)(*args, **kwargs) +- +- +-def assertNotRegex(self, *args, **kwargs): +- return getattr(self, _assertNotRegex)(*args, **kwargs) +- +- +-if PY3: +- exec_ = getattr(moves.builtins, "exec") +- +- def reraise(tp, value, tb=None): +- try: +- if value is None: +- value = tp() +- if value.__traceback__ is not tb: +- raise value.with_traceback(tb) +- raise value +- finally: +- value = None +- tb = None +- +-else: +- def exec_(_code_, _globs_=None, _locs_=None): +- """Execute code in a namespace.""" +- if _globs_ is None: +- frame = sys._getframe(1) +- _globs_ = frame.f_globals +- if _locs_ is None: +- _locs_ = frame.f_locals +- del frame +- elif _locs_ is None: +- _locs_ = _globs_ +- exec("""exec _code_ in _globs_, _locs_""") +- +- exec_("""def reraise(tp, value, tb=None): +- try: +- raise tp, value, tb +- finally: +- tb = None +-""") +- +- +-if sys.version_info[:2] > (3,): +- exec_("""def raise_from(value, from_value): +- try: +- raise value from from_value +- finally: +- value = None +-""") +-else: +- def raise_from(value, from_value): +- raise value +- +- +-print_ = getattr(moves.builtins, "print", None) +-if print_ is None: +- def print_(*args, **kwargs): +- """The new-style print function for Python 2.4 and 2.5.""" +- fp = kwargs.pop("file", sys.stdout) +- if fp is None: +- return +- +- def write(data): +- if not isinstance(data, basestring): +- data = str(data) +- # If the file has an encoding, encode unicode with it. +- if (isinstance(fp, file) and +- isinstance(data, unicode) and +- fp.encoding is not None): +- errors = getattr(fp, "errors", None) +- if errors is None: +- errors = "strict" +- data = data.encode(fp.encoding, errors) +- fp.write(data) +- want_unicode = False +- sep = kwargs.pop("sep", None) +- if sep is not None: +- if isinstance(sep, unicode): +- want_unicode = True +- elif not isinstance(sep, str): +- raise TypeError("sep must be None or a string") +- end = kwargs.pop("end", None) +- if end is not None: +- if isinstance(end, unicode): +- want_unicode = True +- elif not isinstance(end, str): +- raise TypeError("end must be None or a string") +- if kwargs: +- raise TypeError("invalid keyword arguments to print()") +- if not want_unicode: +- for arg in args: +- if isinstance(arg, unicode): +- want_unicode = True +- break +- if want_unicode: +- newline = unicode("\n") +- space = unicode(" ") +- else: +- newline = "\n" +- space = " " +- if sep is None: +- sep = space +- if end is None: +- end = newline +- for i, arg in enumerate(args): +- if i: +- write(sep) +- write(arg) +- write(end) +-if sys.version_info[:2] < (3, 3): +- _print = print_ +- +- def print_(*args, **kwargs): +- fp = kwargs.get("file", sys.stdout) +- flush = kwargs.pop("flush", False) +- _print(*args, **kwargs) +- if flush and fp is not None: +- fp.flush() +- +-_add_doc(reraise, """Reraise an exception.""") +- +-if sys.version_info[0:2] < (3, 4): +- # This does exactly the same what the :func:`py3:functools.update_wrapper` +- # function does on Python versions after 3.2. It sets the ``__wrapped__`` +- # attribute on ``wrapper`` object and it doesn't raise an error if any of +- # the attributes mentioned in ``assigned`` and ``updated`` are missing on +- # ``wrapped`` object. +- def _update_wrapper(wrapper, wrapped, +- assigned=functools.WRAPPER_ASSIGNMENTS, +- updated=functools.WRAPPER_UPDATES): +- for attr in assigned: +- try: +- value = getattr(wrapped, attr) +- except AttributeError: +- continue +- else: +- setattr(wrapper, attr, value) +- for attr in updated: +- getattr(wrapper, attr).update(getattr(wrapped, attr, {})) +- wrapper.__wrapped__ = wrapped +- return wrapper +- _update_wrapper.__doc__ = functools.update_wrapper.__doc__ +- +- def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, +- updated=functools.WRAPPER_UPDATES): +- return functools.partial(_update_wrapper, wrapped=wrapped, +- assigned=assigned, updated=updated) +- wraps.__doc__ = functools.wraps.__doc__ +- +-else: +- wraps = functools.wraps +- +- +-def with_metaclass(meta, *bases): +- """Create a base class with a metaclass.""" +- # This requires a bit of explanation: the basic idea is to make a dummy +- # metaclass for one level of class instantiation that replaces itself with +- # the actual metaclass. +- class metaclass(type): +- +- def __new__(cls, name, this_bases, d): +- if sys.version_info[:2] >= (3, 7): +- # This version introduced PEP 560 that requires a bit +- # of extra care (we mimic what is done by __build_class__). +- resolved_bases = types.resolve_bases(bases) +- if resolved_bases is not bases: +- d['__orig_bases__'] = bases +- else: +- resolved_bases = bases +- return meta(name, resolved_bases, d) +- +- @classmethod +- def __prepare__(cls, name, this_bases): +- return meta.__prepare__(name, bases) +- return type.__new__(metaclass, 'temporary_class', (), {}) +- +- +-def add_metaclass(metaclass): +- """Class decorator for creating a class with a metaclass.""" +- def wrapper(cls): +- orig_vars = cls.__dict__.copy() +- slots = orig_vars.get('__slots__') +- if slots is not None: +- if isinstance(slots, str): +- slots = [slots] +- for slots_var in slots: +- orig_vars.pop(slots_var) +- orig_vars.pop('__dict__', None) +- orig_vars.pop('__weakref__', None) +- if hasattr(cls, '__qualname__'): +- orig_vars['__qualname__'] = cls.__qualname__ +- return metaclass(cls.__name__, cls.__bases__, orig_vars) +- return wrapper +- +- +-def ensure_binary(s, encoding='utf-8', errors='strict'): +- """Coerce **s** to six.binary_type. +- +- For Python 2: +- - `unicode` -> encoded to `str` +- - `str` -> `str` +- +- For Python 3: +- - `str` -> encoded to `bytes` +- - `bytes` -> `bytes` +- """ +- if isinstance(s, binary_type): +- return s +- if isinstance(s, text_type): +- return s.encode(encoding, errors) +- raise TypeError("not expecting type '%s'" % type(s)) +- +- +-def ensure_str(s, encoding='utf-8', errors='strict'): +- """Coerce *s* to `str`. +- +- For Python 2: +- - `unicode` -> encoded to `str` +- - `str` -> `str` +- +- For Python 3: +- - `str` -> `str` +- - `bytes` -> decoded to `str` +- """ +- # Optimization: Fast return for the common case. +- if type(s) is str: +- return s +- if PY2 and isinstance(s, text_type): +- return s.encode(encoding, errors) +- elif PY3 and isinstance(s, binary_type): +- return s.decode(encoding, errors) +- elif not isinstance(s, (text_type, binary_type)): +- raise TypeError("not expecting type '%s'" % type(s)) +- return s +- +- +-def ensure_text(s, encoding='utf-8', errors='strict'): +- """Coerce *s* to six.text_type. +- +- For Python 2: +- - `unicode` -> `unicode` +- - `str` -> `unicode` +- +- For Python 3: +- - `str` -> `str` +- - `bytes` -> decoded to `str` +- """ +- if isinstance(s, binary_type): +- return s.decode(encoding, errors) +- elif isinstance(s, text_type): +- return s +- else: +- raise TypeError("not expecting type '%s'" % type(s)) +- +- +-def python_2_unicode_compatible(klass): +- """ +- A class decorator that defines __unicode__ and __str__ methods under Python 2. +- Under Python 3 it does nothing. +- +- To support Python 2 and 3 with a single code base, define a __str__ method +- returning text and apply this decorator to the class. +- """ +- if PY2: +- if '__str__' not in klass.__dict__: +- raise ValueError("@python_2_unicode_compatible cannot be applied " +- "to %s because it doesn't define __str__()." % +- klass.__name__) +- klass.__unicode__ = klass.__str__ +- klass.__str__ = lambda self: self.__unicode__().encode('utf-8') +- return klass +- +- +-# Complete the moves implementation. +-# This code is at the end of this module to speed up module loading. +-# Turn this module into a package. +-__path__ = [] # required for PEP 302 and PEP 451 +-__package__ = __name__ # see PEP 366 @ReservedAssignment +-if globals().get("__spec__") is not None: +- __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +-# Remove other six meta path importers, since they cause problems. This can +-# happen if six is removed from sys.modules and then reloaded. (Setuptools does +-# this for some reason.) +-if sys.meta_path: +- for i, importer in enumerate(sys.meta_path): +- # Here's some real nastiness: Another "instance" of the six module might +- # be floating around. Therefore, we can't use isinstance() to check for +- # the six meta path importer, since the other six instance will have +- # inserted an importer with different class. +- if (type(importer).__name__ == "_SixMetaPathImporter" and +- importer.name == __name__): +- del sys.meta_path[i] +- break +- del i, importer +-# Finally, add the importer to the meta path import hook. +-sys.meta_path.append(_importer) +--- a/tests/functional/test_six_imports.py ++++ /dev/null +@@ -1,58 +0,0 @@ +-import ast +-import os +- +-import pytest +- +-import botocore +- +-ROOTDIR = os.path.dirname(botocore.__file__) +- +- +-def _all_files(): +- for rootdir, dirnames, filenames in os.walk(ROOTDIR): +- if 'vendored' in dirnames: +- # We don't need to lint our vendored packages. +- dirnames.remove('vendored') +- for filename in filenames: +- if not filename.endswith('.py'): +- continue +- yield os.path.join(rootdir, filename) +- +- +-@pytest.mark.parametrize("filename", _all_files()) +-def test_no_bare_six_imports(filename): +- with open(filename) as f: +- contents = f.read() +- parsed = ast.parse(contents, filename) +- SixImportChecker(filename).visit(parsed) +- +- +-class SixImportChecker(ast.NodeVisitor): +- def __init__(self, filename): +- self.filename = filename +- +- def visit_Import(self, node): +- for alias in node.names: +- if getattr(alias, 'name', '') == 'six': +- line = self._get_line_content(self.filename, node.lineno) +- raise AssertionError( +- "A bare 'import six' was found in %s:\n" +- "\n%s: %s\n" +- "Please use 'from botocore.compat import six' instead" +- % (self.filename, node.lineno, line) +- ) +- +- def visit_ImportFrom(self, node): +- if node.module == 'six': +- line = self._get_line_content(self.filename, node.lineno) +- raise AssertionError( +- "A bare 'from six import ...' was found in %s:\n" +- "\n%s:%s\n" +- "Please use 'from botocore.compat import six' instead" +- % (self.filename, node.lineno, line) +- ) +- +- def _get_line_content(self, filename, lineno): +- with open(filename) as f: +- contents = f.readlines() +- return contents[lineno - 1] +--- a/tests/functional/test_six_threading.py ++++ /dev/null +@@ -1,61 +0,0 @@ +-""" +-Regression test for six issue #98 (https://github.com/benjaminp/six/issues/98) +-""" +-import sys +-import threading +-import time +- +-from botocore.vendored import six +-from tests import mock +- +-_original_setattr = six.moves.__class__.__setattr__ +- +- +-def _wrapped_setattr(key, value): +- # Monkey patch six.moves.__setattr__ to simulate +- # a poorly-timed thread context switch +- time.sleep(0.1) +- return _original_setattr(six.moves, key, value) +- +- +-def _reload_six(): +- # Issue #98 is caused by a race condition in six._LazyDescr.__get__ +- # which is only called once per moved module. Reload six so all the +- # moved modules are reset. +- import importlib +- +- importlib.reload(six) +- +- +-class _ExampleThread(threading.Thread): +- def __init__(self): +- super().__init__() +- self.daemon = False +- self.exc_info = None +- +- def run(self): +- try: +- # Simulate use of six by +- # botocore.configloader.raw_config_parse() +- # Should raise AttributeError if six < 1.9.0 +- six.moves.configparser.RawConfigParser() +- except Exception: +- self.exc_info = sys.exc_info() +- +- +-def test_six_thread_safety(): +- _reload_six() +- with mock.patch( +- 'botocore.vendored.six.moves.__class__.__setattr__', +- wraps=_wrapped_setattr, +- ): +- threads = [] +- for i in range(2): +- t = _ExampleThread() +- threads.append(t) +- t.start() +- while threads: +- t = threads.pop() +- t.join() +- if t.exc_info: +- six.reraise(*t.exc_info) +--- a/tests/integration/test_client_http.py ++++ b/tests/integration/test_client_http.py +@@ -1,6 +1,8 @@ + import contextlib ++import http.server + import select + import socket ++import socketserver + import threading + from contextlib import contextmanager + +@@ -15,7 +17,6 @@ from botocore.exceptions import ( + ReadTimeoutError, + ) + from botocore.vendored.requests import exceptions as requests_exceptions +-from botocore.vendored.six.moves import BaseHTTPServer, socketserver + from tests import mock, unittest + + +@@ -182,7 +183,7 @@ class TestClientHTTPBehavior(unittest.Te + 'ec2', endpoint_url=self.localhost, config=config + ) + +- class BadStatusHandler(BaseHTTPServer.BaseHTTPRequestHandler): ++ class BadStatusHandler(http.server.BaseHTTPRequestHandler): + event = threading.Event() + + def do_POST(self): +@@ -200,7 +201,7 @@ def unused_port(): + return sock.getsockname()[1] + + +-class SimpleHandler(BaseHTTPServer.BaseHTTPRequestHandler): ++class SimpleHandler(http.server.BaseHTTPRequestHandler): + status = 200 + + def get_length(self): +@@ -219,7 +220,7 @@ class SimpleHandler(BaseHTTPServer.BaseH + do_POST = do_PUT = do_GET + + +-class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler): ++class ProxyHandler(http.server.BaseHTTPRequestHandler): + tunnel_chunk_size = 1024 + poll_limit = 10**4 + +--- a/tests/integration/test_glacier.py ++++ b/tests/integration/test_glacier.py +@@ -10,9 +10,9 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. ++import io + import botocore.session + from botocore.exceptions import ClientError +-from botocore.vendored import six + from tests import unittest + + +@@ -44,7 +44,7 @@ class TestGlacier(unittest.TestCase): + self.client.list_vaults(accountId='asdf') + + def test_can_upload_archive(self): +- body = six.BytesIO(b"bytes content") ++ body = io.BytesIO(b"bytes content") + response = self.client.upload_archive( + vaultName=self.VAULT_NAME, + archiveDescription='test upload', +--- a/tests/unit/auth/test_signers.py ++++ b/tests/unit/auth/test_signers.py +@@ -14,13 +14,14 @@ + # language governing permissions and limitations under the License. + import base64 + import datetime ++import io + import json + import time + + import botocore.auth + import botocore.credentials + from botocore.awsrequest import AWSRequest +-from botocore.compat import HTTPHeaders, parse_qs, six, urlsplit ++from botocore.compat import HTTPHeaders, parse_qs, urlsplit + from tests import mock, unittest + + +@@ -325,7 +326,7 @@ class TestS3SigV4Auth(BaseTestWithFixedD + access_key='foo', secret_key='bar', token='baz' + ) + self.auth = self.AuthClass(self.credentials, 'ec2', 'eu-central-1') +- self.request = AWSRequest(data=six.BytesIO(b"foo bar baz")) ++ self.request = AWSRequest(data=io.BytesIO(b"foo bar baz")) + self.request.method = 'PUT' + self.request.url = 'https://s3.eu-central-1.amazonaws.com/' + +@@ -551,7 +552,7 @@ class TestSigV4(unittest.TestCase): + + def test_payload_is_binary_file(self): + request = AWSRequest() +- request.data = six.BytesIO('\u2713'.encode()) ++ request.data = io.BytesIO('\u2713'.encode()) + request.url = 'https://amazonaws.com' + auth = self.create_signer() + payload = auth.payload(request) +@@ -582,7 +583,7 @@ class TestSigV4(unittest.TestCase): + + def test_content_sha256_set_if_payload_signing_disabled(self): + request = AWSRequest() +- request.data = six.BytesIO('\u2713'.encode()) ++ request.data = io.BytesIO('\u2713'.encode()) + request.url = 'https://amazonaws.com' + request.context['payload_signing_enabled'] = False + request.method = 'PUT' +--- a/tests/unit/auth/test_sigv4.py ++++ b/tests/unit/auth/test_sigv4.py +@@ -23,7 +23,9 @@ generate testcases based on these files. + + """ + import datetime ++import http.server + import logging ++import io + import os + import re + +@@ -31,7 +33,7 @@ import pytest + + import botocore.auth + from botocore.awsrequest import AWSRequest +-from botocore.compat import parse_qsl, six, urlsplit ++from botocore.compat import parse_qsl, urlsplit + from botocore.credentials import Credentials + from tests import FreezeTime + +@@ -55,21 +57,15 @@ TESTS_TO_IGNORE = [ + 'get-vanilla-query-order-key', + 'get-vanilla-query-order-value', + ] +-if not six.PY3: +- TESTS_TO_IGNORE += [ +- # NO support +- 'get-header-key-duplicate', +- 'get-header-value-order', +- ] + + log = logging.getLogger(__name__) + + +-class RawHTTPRequest(six.moves.BaseHTTPServer.BaseHTTPRequestHandler): ++class RawHTTPRequest(http.server.BaseHTTPRequestHandler): + def __init__(self, raw_request): + if isinstance(raw_request, str): + raw_request = raw_request.encode('utf-8') +- self.rfile = six.BytesIO(raw_request) ++ self.rfile = io.BytesIO(raw_request) + self.raw_requestline = self.rfile.readline() + self.error_code = None + self.error_message = None +--- a/tests/unit/docs/bcdoc/test_style.py ++++ b/tests/unit/docs/bcdoc/test_style.py +@@ -20,7 +20,6 @@ + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + # IN THE SOFTWARE. + # +-from botocore.compat import six + from botocore.docs.bcdoc.restdoc import ReSTDocument + from botocore.docs.bcdoc.style import ReSTStyle + from tests import unittest +@@ -151,10 +150,10 @@ class TestStyle(unittest.TestCase): + style.tocitem('bar') + self.assertEqual( + style.doc.getvalue(), +- six.b( ++ ( + '\n.. toctree::\n :maxdepth: 1' + '\n :titlesonly:\n\n foo\n bar\n' +- ), ++ ).encode('latin-1'), + ) + + def test_toctree_man(self): +@@ -173,10 +172,10 @@ class TestStyle(unittest.TestCase): + style.hidden_tocitem('bar') + self.assertEqual( + style.doc.getvalue(), +- six.b( ++ ( + '\n.. toctree::\n :maxdepth: 1' + '\n :hidden:\n\n foo\n bar\n' +- ), ++ ).encode('latin-1'), + ) + + def test_hidden_toctree_non_html(self): +@@ -294,7 +293,8 @@ class TestStyle(unittest.TestCase): + 'returns: None' + ) + style.write_py_doc_string(docstring) +- self.assertEqual(style.doc.getvalue(), six.b(docstring + '\n')) ++ self.assertEqual(style.doc.getvalue(), ++ (docstring + '\n').encode('latin-1')) + + def test_new_line(self): + style = ReSTStyle(ReSTDocument()) +--- a/tests/unit/test_awsrequest.py ++++ b/tests/unit/test_awsrequest.py +@@ -30,7 +30,7 @@ from botocore.awsrequest import ( + create_request_object, + prepare_request_dict, + ) +-from botocore.compat import file_type, six ++from botocore.compat import file_type + from botocore.exceptions import UnseekableStreamError + from tests import mock, unittest + +@@ -59,7 +59,7 @@ class FakeSocket: + pass + + +-class BytesIOWithLen(six.BytesIO): ++class BytesIOWithLen(io.BytesIO): + def __len__(self): + return len(self.getvalue()) + +@@ -400,7 +400,7 @@ class TestAWSHTTPConnection(unittest.Tes + conn.request( + 'GET', + '/bucket/foo', +- six.BytesIO(b'body'), ++ io.BytesIO(b'body'), + {'Expect': b'100-continue', 'Content-Length': b'4'}, + ) + response = conn.getresponse() +--- a/tests/unit/test_client.py ++++ b/tests/unit/test_client.py +@@ -10,6 +10,7 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. ++import io + import os + import warnings + from contextlib import closing +@@ -18,7 +19,6 @@ import botocore + import botocore.config + from botocore import client, exceptions, hooks + from botocore.client import ClientEndpointBridge +-from botocore.compat import six + from botocore.configprovider import ( + ChainProvider, + ConfigValueStore, +@@ -272,7 +272,7 @@ class TestAutoGeneratedClient(unittest.T + service_client = creator.create_client( + 'myservice', 'us-west-2', credentials=self.credentials + ) +- with mock.patch('sys.stdout', six.StringIO()) as mock_stdout: ++ with mock.patch('sys.stdout', io.StringIO()) as mock_stdout: + help(service_client.test_operation) + method_docstring = mock_stdout.getvalue() + ref_docstring_lines = [ +@@ -1154,7 +1154,7 @@ class TestAutoGeneratedClient(unittest.T + creator = self.create_client_creator() + service_client = creator.create_client('myservice', 'us-west-2') + paginator = service_client.get_paginator('test_operation') +- with mock.patch('sys.stdout', six.StringIO()) as mock_stdout: ++ with mock.patch('sys.stdout', io.StringIO()) as mock_stdout: + help(paginator.paginate) + contents = mock_stdout.getvalue() + lines = [ +--- a/tests/unit/test_configloader.py ++++ b/tests/unit/test_configloader.py +@@ -12,12 +12,12 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. ++import io + import os + import shutil + import tempfile + + import botocore.exceptions +-from botocore.compat import six + from botocore.configloader import ( + load_config, + multi_file_load_config, +@@ -29,7 +29,7 @@ from tests import mock, unittest + def path(filename): + directory = os.path.join(os.path.dirname(__file__), 'cfg') + if isinstance(filename, bytes): +- directory = six.b(directory) ++ directory = directory.encode('latin-1') + return os.path.join(directory, filename) + + +@@ -53,7 +53,7 @@ class TestConfigLoader(unittest.TestCase + + directory = self.tempdir + if isinstance(filename, bytes): +- directory = six.b(directory) ++ directory = directory.encode('latin-1') + full_path = os.path.join(directory, filename) + + with open(full_path, 'w') as f: +--- a/tests/unit/test_credentials.py ++++ b/tests/unit/test_credentials.py +@@ -24,7 +24,7 @@ from dateutil.tz import tzlocal, tzutc + import botocore.exceptions + import botocore.session + from botocore import credentials +-from botocore.compat import json, six ++from botocore.compat import json + from botocore.configprovider import ConfigValueStore + from botocore.credentials import ( + AssumeRoleProvider, +@@ -3425,7 +3425,7 @@ class TestProfileProviderBuilder(unittes + ConfigProvider, + ] + self.assertEqual(len(providers), len(expected_providers)) +- zipped_providers = six.moves.zip(providers, expected_providers) ++ zipped_providers = zip(providers, expected_providers) + for provider, expected_type in zipped_providers: + self.assertTrue(isinstance(provider, expected_type)) + +--- a/tests/unit/test_endpoint.py ++++ b/tests/unit/test_endpoint.py +@@ -11,12 +11,12 @@ + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. + import datetime ++import io + import socket + + import pytest + + import botocore.endpoint +-from botocore.compat import six + from botocore.config import Config + from botocore.endpoint import DEFAULT_TIMEOUT, Endpoint, EndpointCreator + from botocore.exceptions import HTTPClientError +@@ -44,14 +44,14 @@ def request_dict(**kwargs): + return base + + +-class RecordStreamResets(six.StringIO): ++class RecordStreamResets(io.StringIO): + def __init__(self, value): +- six.StringIO.__init__(self, value) ++ io.StringIO.__init__(self, value) + self.total_resets = 0 + + def seek(self, where, whence=0): + self.total_resets += 1 +- six.StringIO.seek(self, where, whence) ++ io.StringIO.seek(self, where, whence) + + + class TestEndpointBase(unittest.TestCase): +--- a/tests/unit/test_handlers.py ++++ b/tests/unit/test_handlers.py +@@ -13,6 +13,7 @@ + + import base64 + import copy ++import io + import json + import os + +@@ -22,7 +23,7 @@ import botocore + import botocore.session + from botocore import handlers + from botocore.awsrequest import AWSRequest +-from botocore.compat import OrderedDict, quote, six ++from botocore.compat import OrderedDict, quote + from botocore.config import Config + from botocore.credentials import Credentials + from botocore.docs.bcdoc.restdoc import DocumentStructure +@@ -584,7 +585,7 @@ class TestHandlers(BaseSessionTest): + + def test_run_instances_userdata(self): + user_data = 'This is a test' +- b64_user_data = base64.b64encode(six.b(user_data)).decode('utf-8') ++ b64_user_data = base64.b64encode(user_data.encode('latin-1')).decode('utf-8') + params = dict( + ImageId='img-12345678', MinCount=1, MaxCount=5, UserData=user_data + ) +@@ -705,7 +706,7 @@ class TestHandlers(BaseSessionTest): + def test_glacier_checksums_added(self): + request_dict = { + 'headers': {}, +- 'body': six.BytesIO(b'hello world'), ++ 'body': io.BytesIO(b'hello world'), + } + handlers.add_glacier_checksums(request_dict) + self.assertIn('x-amz-content-sha256', request_dict['headers']) +@@ -726,7 +727,7 @@ class TestHandlers(BaseSessionTest): + 'headers': { + 'x-amz-sha256-tree-hash': 'pre-exists', + }, +- 'body': six.BytesIO(b'hello world'), ++ 'body': io.BytesIO(b'hello world'), + } + handlers.add_glacier_checksums(request_dict) + self.assertEqual( +@@ -738,7 +739,7 @@ class TestHandlers(BaseSessionTest): + 'headers': { + 'x-amz-content-sha256': 'pre-exists', + }, +- 'body': six.BytesIO(b'hello world'), ++ 'body': io.BytesIO(b'hello world'), + } + handlers.add_glacier_checksums(request_dict) + self.assertEqual( +@@ -1094,7 +1095,7 @@ class TestConvertStringBodyToFileLikeObj + self.assert_converts_to_file_like_object_with_bytes(body, body_bytes) + + def test_file(self): +- body = six.StringIO() ++ body = io.StringIO() + params = {'Body': body} + handlers.convert_body_to_file_like_object(params) + self.assertEqual(params['Body'], body) +@@ -1339,7 +1340,7 @@ class TestAddMD5(BaseMD5Test): + self.assertTrue('Content-MD5' in request_dict['headers']) + + def test_add_md5_with_file_like_body(self): +- request_dict = {'body': six.BytesIO(b'foobar'), 'headers': {}} ++ request_dict = {'body': io.BytesIO(b'foobar'), 'headers': {}} + self.md5_digest.return_value = b'8X\xf6"0\xac<\x91_0\x0cfC\x12\xc6?' + conditionally_calculate_md5(request_dict) + self.assertEqual( +@@ -1372,7 +1373,7 @@ class TestAddMD5(BaseMD5Test): + + def test_skip_md5_when_flexible_checksum_context(self): + request_dict = { +- 'body': six.BytesIO(b'foobar'), ++ 'body': io.BytesIO(b'foobar'), + 'headers': {}, + 'context': { + 'checksum': { +@@ -1389,7 +1390,7 @@ class TestAddMD5(BaseMD5Test): + + def test_skip_md5_when_flexible_checksum_explicit_header(self): + request_dict = { +- 'body': six.BytesIO(b'foobar'), ++ 'body': io.BytesIO(b'foobar'), + 'headers': {'x-amz-checksum-crc32': 'foo'}, + } + conditionally_calculate_md5(request_dict) +--- a/tests/unit/test_response.py ++++ b/tests/unit/test_response.py +@@ -20,7 +20,6 @@ from urllib3.exceptions import ReadTimeo + import botocore + from botocore import response + from botocore.awsrequest import AWSResponse +-from botocore.compat import six + from botocore.exceptions import ( + IncompleteReadError, + ReadTimeoutError, +@@ -185,7 +184,7 @@ class TestStreamWrapper(unittest.TestCas + ) + + def test_streaming_line_iterator_keepends(self): +- body = six.BytesIO(b'1234567890\n1234567890\n12345') ++ body = BytesIO(b'1234567890\n1234567890\n12345') + stream = response.StreamingBody(body, content_length=27) + self.assert_lines( + stream.iter_lines(keepends=True), +--- a/tests/unit/test_serialize.py ++++ b/tests/unit/test_serialize.py +@@ -13,12 +13,12 @@ spec. This can happen for a number of r + """ + import base64 + import datetime ++import io + import json + + import dateutil.tz + + from botocore import serialize +-from botocore.compat import six + from botocore.exceptions import ParamValidationError + from botocore.model import ServiceModel + from tests import unittest +@@ -125,7 +125,7 @@ class TestBinaryTypesWithRestXML(BaseMod + } + + def test_blob_serialization_with_file_like_object(self): +- body = six.BytesIO(b'foobar') ++ body = io.BytesIO(b'foobar') + request = self.serialize_to_request(input_params={'Blob': body}) + self.assertEqual(request['body'], body) + +--- a/tests/unit/test_utils.py ++++ b/tests/unit/test_utils.py +@@ -21,7 +21,7 @@ from dateutil.tz import tzoffset, tzutc + import botocore + from botocore import xform_name + from botocore.awsrequest import AWSRequest, HeadersDict +-from botocore.compat import json, six ++from botocore.compat import json + from botocore.config import Config + from botocore.exceptions import ( + ClientError, +@@ -715,19 +715,19 @@ class TestArgumentGenerator(unittest.Tes + class TestChecksums(unittest.TestCase): + def test_empty_hash(self): + self.assertEqual( +- calculate_sha256(six.BytesIO(b''), as_hex=True), ++ calculate_sha256(io.BytesIO(b''), as_hex=True), + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + ) + + def test_as_hex(self): + self.assertEqual( +- calculate_sha256(six.BytesIO(b'hello world'), as_hex=True), ++ calculate_sha256(io.BytesIO(b'hello world'), as_hex=True), + 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9', + ) + + def test_as_binary(self): + self.assertEqual( +- calculate_sha256(six.BytesIO(b'hello world'), as_hex=False), ++ calculate_sha256(io.BytesIO(b'hello world'), as_hex=False), + ( + b"\xb9M'\xb9\x93M>\x08\xa5.R\xd7\xda}\xab\xfa\xc4\x84\xef" + b"\xe3zS\x80\xee\x90\x88\xf7\xac\xe2\xef\xcd\xe9" +@@ -742,12 +742,12 @@ class TestTreeHash(unittest.TestCase): + + def test_empty_tree_hash(self): + self.assertEqual( +- calculate_tree_hash(six.BytesIO(b'')), ++ calculate_tree_hash(io.BytesIO(b'')), + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + ) + + def test_tree_hash_less_than_one_mb(self): +- one_k = six.BytesIO(b'a' * 1024) ++ one_k = io.BytesIO(b'a' * 1024) + self.assertEqual( + calculate_tree_hash(one_k), + '2edc986847e209b4016e141a6dc8716d3207350f416969382d431539bf292e4a', +@@ -755,21 +755,21 @@ class TestTreeHash(unittest.TestCase): + + def test_tree_hash_exactly_one_mb(self): + one_meg_bytestring = b'a' * (1 * 1024 * 1024) +- one_meg = six.BytesIO(one_meg_bytestring) ++ one_meg = io.BytesIO(one_meg_bytestring) + self.assertEqual( + calculate_tree_hash(one_meg), + '9bc1b2a288b26af7257a36277ae3816a7d4f16e89c1e7e77d0a5c48bad62b360', + ) + + def test_tree_hash_multiple_of_one_mb(self): +- four_mb = six.BytesIO(b'a' * (4 * 1024 * 1024)) ++ four_mb = io.BytesIO(b'a' * (4 * 1024 * 1024)) + self.assertEqual( + calculate_tree_hash(four_mb), + '9491cb2ed1d4e7cd53215f4017c23ec4ad21d7050a1e6bb636c4f67e8cddb844', + ) + + def test_tree_hash_offset_of_one_mb_multiple(self): +- offset_four_mb = six.BytesIO(b'a' * (4 * 1024 * 1024) + b'a' * 20) ++ offset_four_mb = io.BytesIO(b'a' * (4 * 1024 * 1024) + b'a' * 20) + self.assertEqual( + calculate_tree_hash(offset_four_mb), + '12f3cbd6101b981cde074039f6f728071da8879d6f632de8afc7cdf00661b08f', +--- a/tests/unit/test_validate.py ++++ b/tests/unit/test_validate.py +@@ -1,7 +1,7 @@ ++import io + import decimal + from datetime import datetime + +-from botocore.compat import six + from botocore.model import ShapeResolver + from botocore.validate import ParamValidator + from tests import unittest +@@ -637,7 +637,7 @@ class TestValidateTypeBlob(BaseTestValid + self.assertEqual(error_msg, '') + + def test_validates_file_like_object(self): +- value = six.BytesIO(b'foo') ++ value = io.BytesIO(b'foo') + + errors = self.get_validation_error_message( + given_shapes=self.shapes, +--- a/tests/unit/test_waiters.py ++++ b/tests/unit/test_waiters.py +@@ -10,10 +10,10 @@ + # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF + # ANY KIND, either express or implied. See the License for the specific + # language governing permissions and limitations under the License. ++import io + import os + + import botocore +-from botocore.compat import six + from botocore.exceptions import ClientError, WaiterConfigError, WaiterError + from botocore.loaders import Loader + from botocore.model import ServiceModel +@@ -762,7 +762,7 @@ class TestCreateWaiter(unittest.TestCase + waiter = create_waiter_with_client( + waiter_name, self.waiter_model, self.client + ) +- with mock.patch('sys.stdout', six.StringIO()) as mock_stdout: ++ with mock.patch('sys.stdout', io.StringIO()) as mock_stdout: + help(waiter.wait) + content = mock_stdout.getvalue() + lines = [