From e51959bbfcebca0629d278eedaf0637b825adb38 Mon Sep 17 00:00:00 2001 From: honglei Date: Mon, 24 Aug 2026 16:41:46 +0800 Subject: [PATCH 1/4] Fix epoll test cleanup on Python 3.15 --- tests/test_sockets.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_sockets.py b/tests/test_sockets.py index e7c335e11..63cc8a6d8 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -1,4 +1,5 @@ import asyncio +import os import pickle import select import socket @@ -272,7 +273,9 @@ def test_socket_sync_remove(self): # See https://github.com/MagicStack/uvloop/issues/61 for details sock = socket.socket() - epoll = select.epoll.fromfd(self.loop._get_backend_id()) + # Keep a separate descriptor for the backend epoll instance. The loop + # owns its descriptor and closes it when the loop is closed. + epoll = select.epoll.fromfd(os.dup(self.loop._get_backend_id())) try: cb = lambda: None @@ -288,8 +291,8 @@ def test_socket_sync_remove(self): finally: sock.close() - self.loop.close() epoll.close() + self.loop.close() def test_add_reader_or_writer_transport_fd(self): def assert_raises(): From bd69a06deec15a0899213c1d5a1a7a42e0dea883 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Tue, 29 Sep 2026 12:15:58 -0400 Subject: [PATCH 2/4] Add Python 3.15 and free-threaded builds to test matrix --- .github/workflows/tests.yml | 5 ++++- pyproject.toml | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ec325e5ff..2fd086db6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,6 +24,8 @@ jobs: - "3.13" - "3.14" - "3.14t" + - "3.15" + - "3.15t" os: [ubuntu-latest, macos-latest] env: @@ -55,7 +57,8 @@ jobs: - name: Install macOS deps if: matrix.os == 'macos-latest' && steps.release.outputs.version == 0 run: | - brew install gnu-sed libtool autoconf automake + brew install gnu-sed libtool autoconf automake openssl@3 + echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> "$GITHUB_ENV" - name: Install Python Deps if: steps.release.outputs.version == 0 diff --git a/pyproject.toml b/pyproject.toml index 1802b4066..d547ccae8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,9 @@ test = [ 'flake8~=6.1', 'psutil', 'pycodestyle~=2.11.0', - 'pyOpenSSL~=25.3.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"', 'mypy>=0.800', ] dev = [ From b9cddedfcee16fe1a213f34294f37c6cfc0e0004 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Tue, 29 Sep 2026 14:56:59 -0400 Subject: [PATCH 3/4] Fix races in thread checks and subprocess tests Serialize foreign-thread scheduling calls with the running loop in test_check_thread to avoid corrupting libuv state on free-threaded Python. Wait for the subprocess protocol connection_lost callback before asserting pipe shutdown stages. --- tests/test_base.py | 9 ++++++++- tests/test_process.py | 9 ++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 5506748d8..1eaa1b936 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -290,9 +290,16 @@ def check_in_thread(loop, event, debug, create_loop, fut): def test_thread(loop, debug, create_loop=False): event = threading.Event() fut = asyncio.Future(loop=loop) - loop.call_soon(event.set) args = (loop, event, debug, create_loop, fut) thread = threading.Thread(target=check_in_thread, args=args) + + def run_thread(): + # Keep the loop running for the thread checks, but prevent + # concurrent access to its non-thread-safe scheduling APIs. + event.set() + thread.join() + + loop.call_soon(run_thread) thread.start() loop.run_until_complete(fut) thread.join() diff --git a/tests/test_process.py b/tests/test_process.py index 45036256e..7b06e76d8 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -884,9 +884,10 @@ class TestAsyncio_AIO_Process(_AsyncioTests, tb.AIOTestCase): class Test_UV_Process_Delayed(tb.UVTestCase): class TestProto: - def __init__(self): + def __init__(self, closed): self.lost = 0 self.stages = [] + self.closed = closed def connection_made(self, transport): self.stages.append(('CM', transport)) @@ -905,10 +906,11 @@ def process_exited(self): def connection_lost(self, exc): self.stages.append(('CL', self.lost, exc)) self.lost += 1 + self.closed.set_result(None) async def run_sub(self, **kwargs): return await self.loop.subprocess_shell( - lambda: self.TestProto(), + lambda: self.TestProto(self.loop.create_future()), 'echo 1', **kwargs) @@ -962,7 +964,8 @@ def test_process_delayed_stdio__not_paused__no_stdin(self): stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)) - self.loop.run_until_complete(transport._wait()) + # Process exit alone does not guarantee that pipe callbacks have run. + self.loop.run_until_complete(asyncio.wait_for(proto.closed, 10)) self.assertEqual(transport.get_returncode(), 0) self.assertIsNot(transport, None) self.assertEqual( From a7b2ba75a9677f63e966cb3e6ce1b52f6d16a94d Mon Sep 17 00:00:00 2001 From: Fantix King Date: Wed, 30 Sep 2026 10:58:28 -0400 Subject: [PATCH 4/4] Add Python 3.15 and 3.15t release wheel builds Use cibuildwheel 4.2 for Python 3.9+ while retaining 3.2 for Python 3.8. Pair runners with architectures explicitly, testing macOS x86_64 wheels on Intel and universal2 wheels on arm64. Install native OpenSSL and Linux container dependencies for wheel tests, use native build flags for universal2 test dependencies, and pass the GitHub CI marker into Linux containers. --- .github/workflows/install-linux-test-deps.sh | 14 ++++++ .github/workflows/release.yml | 48 ++++++++++++++------ 2 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/install-linux-test-deps.sh diff --git a/.github/workflows/install-linux-test-deps.sh b/.github/workflows/install-linux-test-deps.sh new file mode 100644 index 000000000..8a2ebef63 --- /dev/null +++ b/.github/workflows/install-linux-test-deps.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +# cryptography has no CPython 3.15t wheels yet. These dependencies are only +# needed to build test dependencies inside the cibuildwheel container. +if command -v apk >/dev/null 2>&1; then + apk add --no-cache openssl-dev libffi-dev pkgconf +else + # manylinux_2_28 ships OpenSSL 1.1.1; cryptography needs OpenSSL 3. + yum install -y openssl3-devel libffi-devel pkgconfig + # EPEL names its pkg-config file openssl3.pc; the build looks for openssl. + mkdir -p /usr/local/lib/pkgconfig + ln -s /usr/lib64/pkgconfig/openssl3.pc /usr/local/lib/pkgconfig/openssl.pc +fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b194aa423..f0e52471d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, ubuntu-22.04-arm] + os: + - ubuntu-latest + - ubuntu-22.04-arm + - macos-15-intel + - macos-latest python: - "cp38" - "cp39" @@ -85,17 +89,17 @@ jobs: - "cp313" - "cp314" - "cp314t" - cibw_arch: ["x86_64", "aarch64", "universal2"] - exclude: + - "cp315" + - "cp315t" + include: - os: ubuntu-latest - cibw_arch: universal2 - - os: ubuntu-latest - cibw_arch: aarch64 - - os: macos-latest - cibw_arch: aarch64 - - os: ubuntu-22.04-arm cibw_arch: x86_64 - os: ubuntu-22.04-arm + cibw_arch: aarch64 + # Use native OpenSSL when compiling x86_64 test dependencies. + - os: macos-15-intel + cibw_arch: x86_64 + - os: macos-latest cibw_arch: universal2 defaults: @@ -104,6 +108,13 @@ jobs: env: PIP_DISABLE_PIP_VERSION_CHECK: 1 + CIBW_BUILD_VERBOSITY: 1 + CIBW_BUILD: ${{ matrix.python }}-* + CIBW_ARCHS: ${{ matrix.cibw_arch }} + # Let tests inside Linux containers recognize GitHub CI. + CIBW_ENVIRONMENT_PASS_LINUX: GITHUB_WORKFLOW + # Exercise arm64 here; x86_64 wheels have their own test jobs. + CIBW_TEST_SKIP: "*universal2:x86_64" steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 @@ -114,14 +125,23 @@ jobs: - name: Install macOS deps if: startsWith(matrix.os, 'macos') run: | - brew install gnu-sed libtool autoconf automake + 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_BUILD_VERBOSITY: 1 - CIBW_BUILD: ${{ matrix.python }}-* - CIBW_ARCHS: ${{ matrix.cibw_arch }} - CIBW_TEST_SKIP: "*universal2:arm64" + CIBW_BEFORE_ALL_LINUX: >- + ${{ matrix.python == 'cp315t' && 'bash {project}/.github/workflows/install-linux-test-deps.sh' || '' }} + # Build universal2 wheels, but compile their test dependencies for arm64. + CIBW_TEST_ENVIRONMENT_MACOS: >- + ${{ matrix.cibw_arch == 'universal2' + && 'ARCHFLAGS="-arch arm64" _PYTHON_HOST_PLATFORM="macosx-11.0-arm64"' + || '' }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: