From bb0cb39de43964599f944c51a35edc4df5cbd6fb Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Wed, 26 Oct 2022 14:34:12 -0500 Subject: [PATCH] Drop Python 3.6 support (#940) --- .github/workflows/tests.yml | 5 +---- README.rst | 2 +- asyncpg/compat.py | 10 ---------- asyncpg/connect_utils.py | 10 +--------- asyncpg/connection.py | 3 +-- asyncpg/pool.py | 4 ---- asyncpg/protocol/scram.pyx | 11 ++--------- docs/index.rst | 2 +- setup.py | 9 ++++----- tests/test_connect.py | 5 ----- tests/test_pool.py | 4 ---- 11 files changed, 11 insertions(+), 54 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3a95aaf3..f451cff8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,13 +17,10 @@ jobs: # job. strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11.0-rc.2"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-rc.2"] os: [ubuntu-latest, macos-latest, windows-latest] loop: [asyncio, uvloop] exclude: - # uvloop does not support Python 3.6 - - loop: uvloop - python-version: "3.6" # uvloop does not support windows - loop: uvloop os: windows-latest diff --git a/README.rst b/README.rst index 2ed14726..01a28c00 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ of PostgreSQL server binary protocol for use with Python's ``asyncio`` framework. You can read more about asyncpg in an introductory `blog post `_. -asyncpg requires Python 3.6 or later and is supported for PostgreSQL +asyncpg requires Python 3.7 or later and is supported for PostgreSQL versions 9.5 to 14. Older PostgreSQL versions or other databases implementing the PostgreSQL protocol *may* work, but are not being actively tested. diff --git a/asyncpg/compat.py b/asyncpg/compat.py index 348b8caa..29b8e16e 100644 --- a/asyncpg/compat.py +++ b/asyncpg/compat.py @@ -8,10 +8,8 @@ import asyncio import pathlib import platform -import sys -PY_37 = sys.version_info >= (3, 7) SYSTEM = platform.uname().system @@ -36,14 +34,6 @@ def get_pg_home_directory() -> pathlib.Path: return pathlib.Path.home() -if PY_37: - def current_asyncio_task(loop): - return asyncio.current_task(loop) -else: - def current_asyncio_task(loop): - return asyncio.Task.current_task(loop) - - async def wait_closed(stream): # Not all asyncio versions have StreamWriter.wait_closed(). if hasattr(stream, 'wait_closed'): diff --git a/asyncpg/connect_utils.py b/asyncpg/connect_utils.py index 90a61503..40905edf 100644 --- a/asyncpg/connect_utils.py +++ b/asyncpg/connect_utils.py @@ -237,10 +237,6 @@ def _parse_hostlist(hostlist, port, *, unquote=False): def _parse_tls_version(tls_version): - if not hasattr(ssl_module, 'TLSVersion'): - raise ValueError( - "TLSVersion is not supported in this version of Python" - ) if tls_version.startswith('SSL'): raise ValueError( f"Unsupported TLS version: {tls_version}" @@ -573,11 +569,7 @@ def _parse_connect_dsn_and_args(*, dsn, host, port, user, ssl_min_protocol_version ) else: - try: - ssl.minimum_version = _parse_tls_version('TLSv1.2') - except ValueError: - # Python 3.6 does not have ssl.TLSVersion - pass + ssl.minimum_version = _parse_tls_version('TLSv1.2') if ssl_max_protocol_version is None: ssl_max_protocol_version = os.getenv('PGSSLMAXPROTOCOLVERSION') diff --git a/asyncpg/connection.py b/asyncpg/connection.py index ea128aab..365ab416 100644 --- a/asyncpg/connection.py +++ b/asyncpg/connection.py @@ -20,7 +20,6 @@ import warnings import weakref -from . import compat from . import connect_utils from . import cursor from . import exceptions @@ -1468,7 +1467,7 @@ async def _cancel(self, waiter): waiter.set_exception(ex) finally: self._cancellations.discard( - compat.current_asyncio_task(self._loop)) + asyncio.current_task(self._loop)) if not waiter.done(): waiter.set_result(None) diff --git a/asyncpg/pool.py b/asyncpg/pool.py index 14e4be7e..9bd2a3e3 100644 --- a/asyncpg/pool.py +++ b/asyncpg/pool.py @@ -43,10 +43,6 @@ def __new__(mcls, name, bases, dct, *, wrap=False): return super().__new__(mcls, name, bases, dct) - def __init__(cls, name, bases, dct, *, wrap=False): - # Needed for Python 3.5 to handle `wrap` class keyword argument. - super().__init__(name, bases, dct) - @staticmethod def _wrap_connection_method(meth_name): def call_con_method(self, *args, **kwargs): diff --git a/asyncpg/protocol/scram.pyx b/asyncpg/protocol/scram.pyx index bfb82f73..765ddd46 100644 --- a/asyncpg/protocol/scram.pyx +++ b/asyncpg/protocol/scram.pyx @@ -9,18 +9,11 @@ import base64 import hashlib import hmac import re +import secrets import stringprep import unicodedata -# try to import the secrets library from Python 3.6+ for the -# cryptographic token generator for generating nonces as part of SCRAM -# Otherwise fall back on os.urandom -try: - from secrets import token_bytes as generate_token_bytes -except ImportError: - from os import urandom as generate_token_bytes - @cython.final cdef class SCRAMAuthentication: """Contains the protocol for generating and a SCRAM hashed password. @@ -198,7 +191,7 @@ cdef class SCRAMAuthentication: cdef: bytes token - token = generate_token_bytes(num_bytes) + token = secrets.token_bytes(num_bytes) return base64.b64encode(token) diff --git a/docs/index.rst b/docs/index.rst index 87c43aa8..ee9f85d4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,7 +14,7 @@ PostgreSQL and Python/asyncio. asyncpg is an efficient, clean implementation of PostgreSQL server binary protocol for use with Python's ``asyncio`` framework. -**asyncpg** requires Python 3.6 or later and is supported for PostgreSQL +**asyncpg** requires Python 3.7 or later and is supported for PostgreSQL versions 9.5 to 14. Older PostgreSQL versions or other databases implementing the PostgreSQL protocol *may* work, but are not being actively tested. diff --git a/setup.py b/setup.py index 78cc0fd3..af0bcdc3 100644 --- a/setup.py +++ b/setup.py @@ -7,8 +7,8 @@ import sys -if sys.version_info < (3, 6): - raise RuntimeError('asyncpg requires Python 3.6 or greater') +if sys.version_info < (3, 7): + raise RuntimeError('asyncpg requires Python 3.7 or greater') import os import os.path @@ -30,7 +30,7 @@ # Minimal dependencies required to test asyncpg. TEST_DEPENDENCIES = [ 'flake8~=5.0.4', - 'uvloop>=0.15.3; platform_system != "Windows" and python_version >= "3.7"', + 'uvloop>=0.15.3; platform_system != "Windows"', ] # Dependencies required to build documentation. @@ -255,7 +255,6 @@ def finalize_options(self): 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', @@ -264,7 +263,7 @@ def finalize_options(self): 'Topic :: Database :: Front-Ends', ], platforms=['macOS', 'POSIX', 'Windows'], - python_requires='>=3.6.0', + python_requires='>=3.7.0', zip_safe=False, author='MagicStack Inc', author_email='hello@magic.io', diff --git a/tests/test_connect.py b/tests/test_connect.py index db7817f6..c8da7e29 100644 --- a/tests/test_connect.py +++ b/tests/test_connect.py @@ -14,7 +14,6 @@ import shutil import ssl import stat -import sys import tempfile import textwrap import unittest @@ -1466,10 +1465,6 @@ async def test_executemany_uvloop_ssl_issue_700(self): finally: await con.close() - @unittest.skipIf( - sys.version_info < (3, 7), - "Python < 3.7 doesn't have ssl.TLSVersion" - ) async def test_tls_version(self): if self.cluster.get_pg_version() < (12, 0): self.skipTest("PostgreSQL < 12 cannot set ssl protocol version") diff --git a/tests/test_pool.py b/tests/test_pool.py index e2c99efc..b77783e9 100644 --- a/tests/test_pool.py +++ b/tests/test_pool.py @@ -10,7 +10,6 @@ import os import platform import random -import sys import textwrap import time import unittest @@ -741,7 +740,6 @@ async def test_pool_size_and_capacity(self): self.assertEqual(pool.get_size(), 3) self.assertEqual(pool.get_idle_size(), 0) - @unittest.skipIf(sys.version_info[:2] < (3, 6), 'no asyncgen support') async def test_pool_handles_transaction_exit_in_asyncgen_1(self): pool = await self.create_pool(database='postgres', min_size=1, max_size=1) @@ -763,7 +761,6 @@ class MyException(Exception): async for _ in iterate(con): # noqa raise MyException() - @unittest.skipIf(sys.version_info[:2] < (3, 6), 'no asyncgen support') async def test_pool_handles_transaction_exit_in_asyncgen_2(self): pool = await self.create_pool(database='postgres', min_size=1, max_size=1) @@ -788,7 +785,6 @@ class MyException(Exception): del iterator - @unittest.skipIf(sys.version_info[:2] < (3, 6), 'no asyncgen support') async def test_pool_handles_asyncgen_finalization(self): pool = await self.create_pool(database='postgres', min_size=1, max_size=1)