From a42ec20880d44150022b8cd9c852fff6cca2dcaa Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 4 Oct 2021 16:22:33 +0800 Subject: py27 going, going, gone (#1047) * py27 going, going, gone * black * more black * ok then * forgot to remove pypy2 --- .github/workflows/ci.yml | 5 ----- CHANGELOG.rst | 3 +++ setup.py | 7 +------ src/OpenSSL/SSL.py | 36 ++++++++++++++++------------------ src/OpenSSL/_util.py | 32 ++++++++----------------------- src/OpenSSL/crypto.py | 44 +++++++++++++++++------------------------- tests/test_ssl.py | 50 ++++++++++-------------------------------------- tests/util.py | 7 +------ 8 files changed, 58 insertions(+), 126 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08d8ae1..e5e2e6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,12 +10,10 @@ jobs: matrix: PYTHON: # Base builds - - {VERSION: "2.7", TOXENV: "py27"} - {VERSION: "3.6", TOXENV: "py36"} - {VERSION: "3.7", TOXENV: "py37"} - {VERSION: "3.8", TOXENV: "py38"} - {VERSION: "3.9", TOXENV: "py39"} - - {VERSION: "pypy2", TOXENV: "pypy"} - {VERSION: "pypy3", TOXENV: "pypy3"} # -cryptographyMain - {VERSION: "3.6", TOXENV: "py36-cryptographyMain"} @@ -24,15 +22,12 @@ jobs: - {VERSION: "3.9", TOXENV: "py39-cryptographyMain"} - {VERSION: "pypy3", TOXENV: "pypy3-cryptographyMain"} # -cryptographyMinimum - - {VERSION: "2.7", TOXENV: "py27-cryptographyMinimum"} - {VERSION: "3.6", TOXENV: "py36-cryptographyMinimum"} - {VERSION: "3.7", TOXENV: "py37-cryptographyMinimum"} - {VERSION: "3.8", TOXENV: "py38-cryptographyMinimum"} - {VERSION: "3.9", TOXENV: "py39-cryptographyMinimum"} - - {VERSION: "pypy2", TOXENV: "pypy-cryptographyMinimum"} - {VERSION: "pypy3", TOXENV: "pypy3-cryptographyMinimum"} # Random order - - {VERSION: "2.7", TOXENV: "py27-randomorder"} - {VERSION: "3.9", TOXENV: "py39-randomorder"} # Downstreams - {VERSION: "3.7", TOXENV: "py37-twistedTrunk"} diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ffeeb7..853e576 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,9 @@ The third digit is only for regressions. Backward-incompatible changes: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Drop support for Python 2.7. + `#1047 `_ + Deprecations: ^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 1ca7b11..b9cd5bf 100755 --- a/setup.py +++ b/setup.py @@ -76,8 +76,6 @@ if __name__ == "__main__": "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", @@ -89,15 +87,12 @@ if __name__ == "__main__": "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Networking", ], - python_requires=( - ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" - ), + python_requires=(">=3.6"), packages=find_packages(where="src"), package_dir={"": "src"}, install_requires=[ # Fix cryptographyMinimum in tox.ini when changing this! "cryptography>=3.3", - "six>=1.5.2", ], extras_require={ "test": ["flaky", "pretend", "pytest>=3.0.1"], diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index e71b044..59f21ce 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -6,8 +6,6 @@ from itertools import count, chain from weakref import WeakValueDictionary from errno import errorcode -from six import integer_types, int2byte, indexbytes - from OpenSSL._util import ( UNSPECIFIED as _UNSPECIFIED, exception_from_error_queue as _exception_from_error_queue, @@ -381,7 +379,7 @@ class _ALPNSelectHelper(_CallbackExceptionHelper): instr = _ffi.buffer(in_, inlen)[:] protolist = [] while instr: - encoded_len = indexbytes(instr, 0) + encoded_len = instr[0] proto = instr[1 : encoded_len + 1] protolist.append(proto) instr = instr[encoded_len + 1 :] @@ -551,15 +549,15 @@ class _OCSPClientCallbackHelper(_CallbackExceptionHelper): def _asFileDescriptor(obj): fd = None - if not isinstance(obj, integer_types): + if not isinstance(obj, int): meth = getattr(obj, "fileno", None) if meth is not None: obj = meth() - if isinstance(obj, integer_types): + if isinstance(obj, int): fd = obj - if not isinstance(fd, integer_types): + if not isinstance(fd, int): raise TypeError("argument must be an int, or have a fileno() method.") elif fd < 0: raise ValueError( @@ -653,7 +651,7 @@ class Context(object): ) def __init__(self, method): - if not isinstance(method, integer_types): + if not isinstance(method, int): raise TypeError("method must be an integer") try: @@ -897,7 +895,7 @@ class Context(object): :return: None """ certfile = _path_string(certfile) - if not isinstance(filetype, integer_types): + if not isinstance(filetype, int): raise TypeError("filetype must be an integer") use_result = _lib.SSL_CTX_use_certificate_file( @@ -958,7 +956,7 @@ class Context(object): if filetype is _UNSPECIFIED: filetype = FILETYPE_PEM - elif not isinstance(filetype, integer_types): + elif not isinstance(filetype, int): raise TypeError("filetype must be an integer") use_result = _lib.SSL_CTX_use_PrivateKey_file( @@ -1035,7 +1033,7 @@ class Context(object): .. versionadded:: 0.14 """ - if not isinstance(mode, integer_types): + if not isinstance(mode, int): raise TypeError("mode must be an integer") return _lib.SSL_CTX_set_session_cache_mode(self._context, mode) @@ -1070,7 +1068,7 @@ class Context(object): See SSL_CTX_set_verify(3SSL) for further details. """ - if not isinstance(mode, integer_types): + if not isinstance(mode, int): raise TypeError("mode must be an integer") if callback is None: @@ -1093,7 +1091,7 @@ class Context(object): :param depth: An integer specifying the verify depth :return: None """ - if not isinstance(depth, integer_types): + if not isinstance(depth, int): raise TypeError("depth must be an integer") _lib.SSL_CTX_set_verify_depth(self._context, depth) @@ -1253,7 +1251,7 @@ class Context(object): :param timeout: The timeout in (whole) seconds :return: The previous session timeout """ - if not isinstance(timeout, integer_types): + if not isinstance(timeout, int): raise TypeError("timeout must be an integer") return _lib.SSL_CTX_set_timeout(self._context, timeout) @@ -1356,7 +1354,7 @@ class Context(object): :param options: The options to add. :return: The new option bitmask. """ - if not isinstance(options, integer_types): + if not isinstance(options, int): raise TypeError("options must be an integer") return _lib.SSL_CTX_set_options(self._context, options) @@ -1369,7 +1367,7 @@ class Context(object): :param mode: The mode to add. :return: The new mode bitmask. """ - if not isinstance(mode, integer_types): + if not isinstance(mode, int): raise TypeError("mode must be an integer") return _lib.SSL_CTX_set_mode(self._context, mode) @@ -1426,7 +1424,7 @@ class Context(object): # Take the list of protocols and join them together, prefixing them # with their lengths. protostr = b"".join( - chain.from_iterable((int2byte(len(p)), p) for p in protos) + chain.from_iterable((bytes((len(p),)), p) for p in protos) ) # Build a C string from the list. We don't need to save this off @@ -1839,7 +1837,7 @@ class Connection(object): if self._from_ssl is None: raise TypeError("Connection sock was not None") - if not isinstance(bufsiz, integer_types): + if not isinstance(bufsiz, int): raise TypeError("bufsiz must be an integer") buf = _no_zero_allocator("char[]", bufsiz) @@ -2070,7 +2068,7 @@ class Connection(object): :param state: bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN. :return: None """ - if not isinstance(state, integer_types): + if not isinstance(state, int): raise TypeError("state must be an integer") _lib.SSL_set_shutdown(self._ssl, state) @@ -2454,7 +2452,7 @@ class Connection(object): # Take the list of protocols and join them together, prefixing them # with their lengths. protostr = b"".join( - chain.from_iterable((int2byte(len(p)), p) for p in protos) + chain.from_iterable((bytes((len(p),)), p) for p in protos) ) # Build a C string from the list. We don't need to save this off diff --git a/src/OpenSSL/_util.py b/src/OpenSSL/_util.py index 53c0b9e..8235f5b 100644 --- a/src/OpenSSL/_util.py +++ b/src/OpenSSL/_util.py @@ -1,8 +1,6 @@ import sys import warnings -from six import PY2, text_type - from cryptography.hazmat.bindings.openssl.binding import Binding @@ -83,14 +81,10 @@ def native(s): :raise TypeError: The input is neither :py:class:`bytes` nor :py:class:`unicode`. """ - if not isinstance(s, (bytes, text_type)): + if not isinstance(s, (bytes, str)): raise TypeError("%r is neither bytes nor unicode" % s) - if PY2: - if isinstance(s, text_type): - return s.encode("utf-8") - else: - if isinstance(s, bytes): - return s.decode("utf-8") + if isinstance(s, bytes): + return s.decode("utf-8") return s @@ -105,31 +99,21 @@ def path_string(s): """ if isinstance(s, bytes): return s - elif isinstance(s, text_type): + elif isinstance(s, str): return s.encode(sys.getfilesystemencoding()) else: raise TypeError("Path must be represented as bytes or unicode string") -if PY2: - - def byte_string(s): - return s - - -else: - - def byte_string(s): - return s.encode("charmap") +def byte_string(s): + return s.encode("charmap") # A marker object to observe whether some optional arguments are passed any # value or not. UNSPECIFIED = object() -_TEXT_WARNING = ( - text_type.__name__ + " for {0} is no longer accepted, use bytes" -) +_TEXT_WARNING = "str for {0} is no longer accepted, use bytes" def text_to_bytes_and_warn(label, obj): @@ -145,7 +129,7 @@ def text_to_bytes_and_warn(label, obj): UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is returned. """ - if isinstance(obj, text_type): + if isinstance(obj, str): warnings.warn( _TEXT_WARNING.format(label), category=DeprecationWarning, diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py index eda4af6..151d7d1 100644 --- a/src/OpenSSL/crypto.py +++ b/src/OpenSSL/crypto.py @@ -5,12 +5,6 @@ from base64 import b16encode from functools import partial from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__ -from six import ( - integer_types as _integer_types, - text_type as _text_type, - PY2 as _PY2, -) - from cryptography import utils, x509 from cryptography.hazmat.primitives.asymmetric import dsa, rsa @@ -411,18 +405,16 @@ class _EllipticCurve(object): _curves = None - if not _PY2: - # This only necessary on Python 3. Moreover, it is broken on Python 2. - def __ne__(self, other): - """ - Implement cooperation with the right-hand side argument of ``!=``. + def __ne__(self, other): + """ + Implement cooperation with the right-hand side argument of ``!=``. - Python 3 seems to have dropped this cooperation in this very narrow - circumstance. - """ - if isinstance(other, _EllipticCurve): - return super(_EllipticCurve, self).__ne__(other) - return NotImplemented + Python 3 seems to have dropped this cooperation in this very narrow + circumstance. + """ + if isinstance(other, _EllipticCurve): + return super(_EllipticCurve, self).__ne__(other) + return NotImplemented @classmethod def _load_elliptic_curves(cls, lib): @@ -602,7 +594,7 @@ class X509Name(object): _lib.X509_NAME_ENTRY_free(ent) break - if isinstance(value, _text_type): + if isinstance(value, str): value = value.encode("utf-8") add_result = _lib.X509_NAME_add_entry_by_NID( @@ -1304,7 +1296,7 @@ class X509(object): :return: :py:data`None` """ - if not isinstance(serial, _integer_types): + if not isinstance(serial, int): raise TypeError("serial must be an integer") hex_serial = hex(serial)[2:] @@ -1957,7 +1949,7 @@ def load_certificate(type, buffer): :return: The X509 object """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -2883,7 +2875,7 @@ def load_publickey(type, buffer): :return: The PKey object. :rtype: :class:`PKey` """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -2919,7 +2911,7 @@ def load_privatekey(type, buffer, passphrase=None): :return: The PKey object """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -2980,7 +2972,7 @@ def load_certificate_request(type, buffer): :param buffer: The buffer the certificate request is stored in :return: The X509Req object """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -3109,7 +3101,7 @@ def load_crl(type, buffer): :return: The PKey object """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -3138,7 +3130,7 @@ def load_pkcs7_data(type, buffer): :param buffer: The buffer with the pkcs7 data. :return: The PKCS7 object """ - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) @@ -3183,7 +3175,7 @@ def load_pkcs12(buffer, passphrase=None): """ passphrase = _text_to_bytes_and_warn("passphrase", passphrase) - if isinstance(buffer, _text_type): + if isinstance(buffer, str): buffer = buffer.encode("ascii") bio = _new_mem_buf(buffer) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index e604164..ffc505d 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -32,8 +32,6 @@ import pytest from pretend import raiser -from six import PY2, text_type - from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes @@ -166,9 +164,6 @@ i5s5yYK7a/0eWxxRr2qraYaUj8RwDpH9CwIBAg== """ -skip_if_py3 = pytest.mark.skipif(not PY2, reason="Python 2 only") - - def socket_any_family(): try: return socket(AF_INET) @@ -197,7 +192,7 @@ def join_bytes_or_unicode(prefix, suffix): return join(prefix, suffix) # Otherwise, coerce suffix to the type of prefix. - if isinstance(prefix, text_type): + if isinstance(prefix, str): return join(prefix, suffix.decode(getfilesystemencoding())) else: return join(prefix, suffix.encode(getfilesystemencoding())) @@ -1751,7 +1746,7 @@ class TestContext(object): """ context = Context(SSLv23_METHOD) with pytest.raises(TypeError): - context.set_tlsext_use_srtp(text_type("SRTP_AES128_CM_SHA1_80")) + context.set_tlsext_use_srtp(str("SRTP_AES128_CM_SHA1_80")) def test_set_tlsext_use_srtp_invalid_profile(self): """ @@ -2285,10 +2280,8 @@ class TestConnection(object): with pytest.raises(TypeError): conn.set_tlsext_host_name(b"with\0null") - if not PY2: - # On Python 3.x, don't accidentally implicitly convert from text. - with pytest.raises(TypeError): - conn.set_tlsext_host_name(b"example.com".decode("ascii")) + with pytest.raises(TypeError): + conn.set_tlsext_host_name(b"example.com".decode("ascii")) def test_pending(self): """ @@ -2858,8 +2851,8 @@ class TestConnection(object): client.get_cipher_name(), ) - assert isinstance(server_cipher_name, text_type) - assert isinstance(client_cipher_name, text_type) + assert isinstance(server_cipher_name, str) + assert isinstance(client_cipher_name, str) assert server_cipher_name == client_cipher_name @@ -2883,8 +2876,8 @@ class TestConnection(object): client.get_cipher_version(), ) - assert isinstance(server_cipher_version, text_type) - assert isinstance(client_cipher_version, text_type) + assert isinstance(server_cipher_version, str) + assert isinstance(client_cipher_version, str) assert server_cipher_version == client_cipher_version @@ -2922,8 +2915,8 @@ class TestConnection(object): client_protocol_version_name = client.get_protocol_version_name() server_protocol_version_name = server.get_protocol_version_name() - assert isinstance(server_protocol_version_name, text_type) - assert isinstance(client_protocol_version_name, text_type) + assert isinstance(server_protocol_version_name, str) + assert isinstance(client_protocol_version_name, str) assert server_protocol_version_name == client_protocol_version_name @@ -3066,18 +3059,6 @@ class TestConnectionSend(object): assert count == 2 assert client.recv(2) == b"xy" - @skip_if_py3 - def test_short_buffer(self): - """ - When passed a buffer containing a small number of bytes, - `Connection.send` transmits all of them and returns the number - of bytes sent. - """ - server, client = loopback() - count = server.send(buffer(b"xy")) # noqa: F821 - assert count == 2 - assert client.recv(2) == b"xy" - @pytest.mark.skipif( sys.maxsize < 2 ** 31, reason="sys.maxsize < 2**31 - test requires 64 bit", @@ -3273,17 +3254,6 @@ class TestConnectionSendall(object): server.sendall(memoryview(b"x")) assert client.recv(1) == b"x" - @skip_if_py3 - def test_short_buffers(self): - """ - When passed a buffer containing a small number of bytes, - `Connection.sendall` transmits all of them. - """ - server, client = loopback() - count = server.sendall(buffer(b"xy")) # noqa: F821 - assert count == 2 - assert client.recv(2) == b"xy" - def test_long(self): """ `Connection.sendall` transmits all the bytes in the string passed to it diff --git a/tests/util.py b/tests/util.py index 75d2c8d..566146c 100644 --- a/tests/util.py +++ b/tests/util.py @@ -6,8 +6,6 @@ Helpers for the OpenSSL test suite, largely copied from U{Twisted}. """ -from six import PY2 - # This is the UTF-8 encoding of the SNOWMAN unicode code point. NON_ASCII = b"\xe2\x98\x83".decode("utf-8") @@ -154,7 +152,4 @@ class EqualityTestsMixin(object): # The type name expected in warnings about using the wrong string type. -if PY2: - WARNING_TYPE_EXPECTED = "unicode" -else: - WARNING_TYPE_EXPECTED = "str" +WARNING_TYPE_EXPECTED = "str" -- cgit v1.2.1