From f4c6084bdcbf260054790dd25e9395817a79258c Mon Sep 17 00:00:00 2001 From: Fantix King Date: Thu, 1 Oct 2026 09:43:34 -0400 Subject: [PATCH] Drop Python 3.8 support --- .github/workflows/release.yml | 6 ------ .github/workflows/tests.yml | 1 - README.rst | 4 ++-- docs/dev/index.rst | 2 +- docs/user/index.rst | 2 +- pyproject.toml | 7 ++----- setup.py | 4 ++-- tests/test_base.py | 5 ----- tests/test_sockets.py | 11 ----------- tests/test_tcp.py | 6 +----- tests/test_udp.py | 2 -- uvloop/__init__.py | 5 +---- uvloop/loop.pyx | 25 ++++++------------------- 13 files changed, 16 insertions(+), 64 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0e52471d..2ee9f8f92 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,7 +81,6 @@ jobs: - macos-15-intel - macos-latest python: - - "cp38" - "cp39" - "cp310" - "cp311" @@ -128,12 +127,7 @@ jobs: brew install gnu-sed libtool autoconf automake openssl@3 echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> "$GITHUB_ENV" - # cibuildwheel 4 added Python 3.15 but removed Python 3.8. - - uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0 - if: matrix.python == 'cp38' - - uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 - if: matrix.python != 'cp38' env: CIBW_BEFORE_ALL_LINUX: >- ${{ matrix.python == 'cp315t' && 'bash {project}/.github/workflows/install-linux-test-deps.sh' || '' }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2fd086db6..ee59ab67e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.8" - "3.9" - "3.10" - "3.11" diff --git a/README.rst b/README.rst index c279822e2..24b1fc201 100644 --- a/README.rst +++ b/README.rst @@ -39,7 +39,7 @@ about it. Installation ------------ -uvloop requires Python 3.8 or greater and is available on PyPI. +uvloop requires Python 3.9 or greater and is available on PyPI. Use pip to install it:: $ pip install uvloop @@ -96,7 +96,7 @@ snippet can be used: Building From Source -------------------- -To build uvloop, you'll need Python 3.8 or greater: +To build uvloop, you'll need Python 3.9 or greater: 1. Clone the repository: diff --git a/docs/dev/index.rst b/docs/dev/index.rst index 6f612397a..378839d35 100644 --- a/docs/dev/index.rst +++ b/docs/dev/index.rst @@ -28,7 +28,7 @@ from the `libuv` Github repository. Build ----- -To build `uvloop`, you'll need ``Cython`` and Python 3.8. +To build `uvloop`, you'll need ``Cython`` and Python 3.9 or greater. .. note:: diff --git a/docs/user/index.rst b/docs/user/index.rst index b1c26f38e..e4dbc6604 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -8,7 +8,7 @@ uvloop. Installation ------------ -`uvloop` is available from PyPI. It requires Python 3.8. +`uvloop` is available from PyPI. It requires Python 3.9 or greater. Use pip to install it. diff --git a/pyproject.toml b/pyproject.toml index d547ccae8..70a57e0b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "uvloop" description = "Fast implementation of asyncio event loop on top of libuv" authors = [{name = "Yury Selivanov", email = "yury@magic.io"}] -requires-python = '>=3.8.1' +requires-python = '>=3.9' readme = "README.rst" license = {text = "MIT License"} dynamic = ["version"] @@ -19,7 +19,6 @@ classifiers = [ "Operating System :: POSIX", "Operating System :: MacOS :: MacOS X", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -41,9 +40,7 @@ test = [ 'flake8~=6.1', 'psutil', 'pycodestyle~=2.11.0', - # pyOpenSSL 26.4 requires Python 3.9 or later. - 'pyOpenSSL~=25.3.0; python_version < "3.9"', - 'pyOpenSSL~=26.4.0; python_version >= "3.9"', + 'pyOpenSSL~=26.4.0', 'mypy>=0.800', ] dev = [ diff --git a/setup.py b/setup.py index 7d4e55b22..0d10beba6 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ import sys vi = sys.version_info -if vi < (3, 8): - raise RuntimeError('uvloop requires Python 3.8 or greater') +if vi < (3, 9): + raise RuntimeError('uvloop requires Python 3.9 or greater') if sys.platform in ('win32', 'cygwin', 'cli'): raise RuntimeError('uvloop does not support Windows at the moment') diff --git a/tests/test_base.py b/tests/test_base.py index 1eaa1b936..b226a84fd 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -837,11 +837,6 @@ async def main(): self.fail(result.stdout.strip()) def test_thread_name_prefix_in_default_executor(self): - if self.implementation == "asyncio" and sys.version_info < (3, 9): - raise unittest.SkipTest( - "thread_name_prefix was added in CPython 3.9" - ) - called = [] def cb(): diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 63cc8a6d8..809ec5d5f 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -3,7 +3,6 @@ import pickle import select import socket -import sys import time import unittest @@ -161,11 +160,6 @@ def test_socket_sync_remove_and_immediately_close(self): self.loop.run_until_complete(asyncio.sleep(0.01)) def test_sock_cancel_add_reader_race(self): - if self.is_asyncio_loop() and sys.version_info[:2] == (3, 8): - # asyncio 3.8.x has a regression; fixed in 3.9.0 - # tracked in https://bugs.python.org/issue30064 - raise unittest.SkipTest() - srv_sock_conn = None async def server(): @@ -217,11 +211,6 @@ async def send_server_data(): self.loop.run_until_complete(server()) def test_sock_send_before_cancel(self): - if self.is_asyncio_loop() and sys.version_info[:2] == (3, 8): - # asyncio 3.8.x has a regression; fixed in 3.9.0 - # tracked in https://bugs.python.org/issue30064 - raise unittest.SkipTest() - srv_sock_conn = None async def server(): diff --git a/tests/test_tcp.py b/tests/test_tcp.py index 47f18ba96..b933166b7 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -2525,7 +2525,7 @@ def prog(sock): async def start_server(): extras = {'ssl_handshake_timeout': SSL_HANDSHAKE_TIMEOUT} - if self.implementation != 'asyncio': # or self.PY38 + if self.implementation != 'asyncio': extras['ssl_shutdown_timeout'] = 0.5 srv = await asyncio.start_server( @@ -2647,10 +2647,6 @@ def unwrap_server(sock): except ssl.SSLError as ex: # Since OpenSSL 1.1.1, it raises "application data after # close notify" - # Python < 3.8: - if ex.reason == 'KRB5_S_INIT': - break - # Python >= 3.8: if ex.reason == 'APPLICATION_DATA_AFTER_CLOSE_NOTIFY': break raise ex diff --git a/tests/test_udp.py b/tests/test_udp.py index 1b7953f20..e529b9e33 100644 --- a/tests/test_udp.py +++ b/tests/test_udp.py @@ -317,8 +317,6 @@ def _skip_create_datagram_endpoint_reuse_addr(self): if self.implementation == 'asyncio': if sys.version_info[:2] >= (3, 11): raise unittest.SkipTest() - if (3, 8, 0) <= sys.version_info < (3, 8, 1): - raise unittest.SkipTest() def test_create_datagram_endpoint_reuse_address_error(self): # bpo-37228: Ensure that explicit passing of `reuse_address=True` diff --git a/uvloop/__init__.py b/uvloop/__init__.py index 638b874c0..5e9060b1c 100644 --- a/uvloop/__init__.py +++ b/uvloop/__init__.py @@ -71,10 +71,7 @@ async def wrapper(): try: _cancel_all_tasks(loop) loop.run_until_complete(loop.shutdown_asyncgens()) - if hasattr(loop, 'shutdown_default_executor'): - loop.run_until_complete( - loop.shutdown_default_executor() - ) + loop.run_until_complete(loop.shutdown_default_executor()) finally: __asyncio.set_event_loop(None) loop.close() diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index e20d956de..802cdb69c 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -48,7 +48,6 @@ include "includes/stdlib.pxi" include "errors.pyx" cdef: - int PY39 = PY_VERSION_HEX >= 0x03090000 int PY311 = PY_VERSION_HEX >= 0x030b0000 int PY313 = PY_VERSION_HEX >= 0x030d0000 uint64_t MAX_SLEEP = 3600 * 24 * 365 * 100 @@ -3315,15 +3314,9 @@ class _SyncSocketReaderFuture(aio_Future): self.__loop.remove_reader(self.__sock) self.__sock = None - if PY39: - def cancel(self, msg=None): - self.__remove_reader() - aio_Future.cancel(self, msg=msg) - - else: - def cancel(self): - self.__remove_reader() - aio_Future.cancel(self) + def cancel(self, msg=None): + self.__remove_reader() + aio_Future.cancel(self, msg=msg) class _SyncSocketWriterFuture(aio_Future): @@ -3338,15 +3331,9 @@ class _SyncSocketWriterFuture(aio_Future): self.__loop.remove_writer(self.__sock) self.__sock = None - if PY39: - def cancel(self, msg=None): - self.__remove_writer() - aio_Future.cancel(self, msg=msg) - - else: - def cancel(self): - self.__remove_writer() - aio_Future.cancel(self) + def cancel(self, msg=None): + self.__remove_writer() + aio_Future.cancel(self, msg=msg) include "cbhandles.pyx"