From f7fa75c0ab9f1b5e745bc55df52f24fbd9f53299 Mon Sep 17 00:00:00 2001 From: hansu650 <2788086371@qq.com> Date: Tue, 25 Aug 2026 17:03:51 +0800 Subject: [PATCH] Fix socket close cancellation checkpoints Fixes #1288. --- docs/versionhistory.rst | 3 +++ src/anyio/_backends/_asyncio.py | 2 ++ src/anyio/_backends/_trio.py | 2 ++ tests/test_sockets.py | 15 +++++++++++++++ 4 files changed, 22 insertions(+) diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index 81f656aec..1a18928f7 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -68,6 +68,9 @@ This library adheres to `Semantic Versioning 2.0 `_. - Fixed ``UNIXSocketStream.aclose()`` raising ``asyncio.InvalidStateError`` when a concurrent receive or send operation had just been cancelled on the asyncio backend (`#1267 `_; PR by @alloutflo) +- Fixed socket ``aclose()`` implementations not checkpointing after closing on the + asyncio and Trio backends + (`#1288 `_; PR by @hansu650) - Fixed the pytest plugin importing the deprecated ``_pytest.python.CallSpec2`` alias, which triggers ``PytestRemovedIn10Warning`` on ``pytest>=9.2`` and crashes pytest at startup when ``filterwarnings = error`` is configured diff --git a/src/anyio/_backends/_asyncio.py b/src/anyio/_backends/_asyncio.py index 35b0cf371..9361c03a2 100644 --- a/src/anyio/_backends/_asyncio.py +++ b/src/anyio/_backends/_asyncio.py @@ -1453,6 +1453,8 @@ async def aclose(self) -> None: if self._send_future and not self._send_future.done(): self._send_future.set_result(None) + await AsyncIOBackend.checkpoint() + class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream): async def send_eof(self) -> None: diff --git a/src/anyio/_backends/_trio.py b/src/anyio/_backends/_trio.py index 2e67786e8..d6009a55a 100644 --- a/src/anyio/_backends/_trio.py +++ b/src/anyio/_backends/_trio.py @@ -467,6 +467,8 @@ async def aclose(self) -> None: self._closed = True self._trio_socket.close() + await trio.lowlevel.checkpoint() + def _convert_socket_error(self, exc: BaseException) -> NoReturn: if isinstance(exc, trio.ClosedResourceError): raise ClosedResourceError from exc diff --git a/tests/test_sockets.py b/tests/test_sockets.py index cc661b79a..e48d9d426 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -37,6 +37,7 @@ from anyio import ( BrokenResourceError, BusyResourceError, + CancelScope, ClosedResourceError, EndOfStream, Event, @@ -54,6 +55,7 @@ create_unix_datagram_socket, create_unix_listener, fail_after, + get_cancelled_exc_class, getaddrinfo, getnameinfo, move_on_after, @@ -1499,6 +1501,19 @@ async def operate() -> None: if client is not None: await client.aclose() + async def test_aclose_checkpoints_when_cancelled( + self, server_sock: socket.socket, socket_path: Path + ) -> None: + stream = await connect_unix(socket_path) + raw_socket = stream.extra(SocketAttribute.raw_socket) + + with CancelScope() as scope: + scope.cancel() + with pytest.raises(get_cancelled_exc_class()): + await stream.aclose() + + assert raw_socket.fileno() == -1 + async def test_receive_after_close( self, server_sock: socket.socket, socket_path: Path ) -> None: