https://github.com/python/cpython/commit/7a1d2c462bb544eb3de7f04d1fc5d09a327f301c
commit: 7a1d2c462bb544eb3de7f04d1fc5d09a327f301c
branch: main
author: lpyuu <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-09-07T16:40:24+05:30
summary:
gh-157025: Fix transport cleanup when cancelling asyncio native sendfile
(#157027)
files:
A Misc/NEWS.d/next/Library/2026-09-06-15-12-18.gh-issue-157025.ZvFpFT.rst
M Lib/asyncio/proactor_events.py
M Lib/asyncio/selector_events.py
M Lib/test/test_asyncio/test_sendfile.py
diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py
index 7adb09f3fce5de7..6717f067caa08bb 100644
--- a/Lib/asyncio/proactor_events.py
+++ b/Lib/asyncio/proactor_events.py
@@ -766,8 +766,8 @@ async def _sock_sendfile_native(self, sock, file, offset,
count):
async def _sendfile_native(self, transp, file, offset, count):
resume_reading = transp.is_reading()
transp.pause_reading()
- await transp._make_empty_waiter()
try:
+ await transp._make_empty_waiter()
return await self.sock_sendfile(transp._sock, file, offset, count,
fallback=False)
finally:
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index a682063d9d3d6e3..bf20f053ded4353 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -739,8 +739,8 @@ async def _sendfile_native(self, transp, file, offset,
count):
del self._transports[transp._sock_fd]
resume_reading = transp.is_reading()
transp.pause_reading()
- await transp._make_empty_waiter()
try:
+ await transp._make_empty_waiter()
return await self.sock_sendfile(transp._sock, file, offset, count,
fallback=False)
finally:
diff --git a/Lib/test/test_asyncio/test_sendfile.py
b/Lib/test/test_asyncio/test_sendfile.py
index c8d429c3d1651f0..91bbbc2e6993dae 100644
--- a/Lib/test/test_asyncio/test_sendfile.py
+++ b/Lib/test/test_asyncio/test_sendfile.py
@@ -376,6 +376,47 @@ def test_sendfile(self):
self.assertEqual(srv_proto.data, self.DATA)
self.assertEqual(self.file.tell(), len(self.DATA))
+ def test_sendfile_cancel_empty_waiter(self):
+ for reading in (True, False):
+ with self.subTest(reading=reading):
+ srv_proto, cli_proto = self.prepare_sendfile()
+ transport = cli_proto.transport
+ if not reading:
+ transport.pause_reading()
+ waiter = self.loop.create_future()
+
+ def make_empty_waiter():
+ transport._empty_waiter = waiter
+ return waiter
+
+ with mock.patch.object(transport, '_make_empty_waiter',
+ side_effect=make_empty_waiter):
+ task = self.loop.create_task(
+ self.loop.sendfile(transport, self.file))
+ test_utils.run_briefly(self.loop)
+ self.assertIs(transport._empty_waiter, waiter)
+ self.assertFalse(waiter.done())
+ self.assertFalse(transport.is_reading())
+ task.cancel()
+ with self.assertRaises(asyncio.CancelledError):
+ self.run_loop(task)
+
+ try:
+ self.assertIsNone(transport._empty_waiter)
+ self.assertEqual(transport.is_reading(), reading)
+ if isinstance(self.loop, asyncio.SelectorEventLoop):
+ self.assertIs(
+ self.loop._transports[transport._sock_fd],
+ transport)
+ finally:
+ transport._reset_empty_waiter()
+
+ ret = self.run_loop(self.loop.sendfile(transport, self.file))
+ transport.close()
+ self.run_loop(srv_proto.done)
+ self.assertEqual(ret, len(self.DATA))
+ self.assertEqual(srv_proto.data, self.DATA)
+
def test_sendfile_force_fallback(self):
srv_proto, cli_proto = self.prepare_sendfile()
diff --git
a/Misc/NEWS.d/next/Library/2026-09-06-15-12-18.gh-issue-157025.ZvFpFT.rst
b/Misc/NEWS.d/next/Library/2026-09-06-15-12-18.gh-issue-157025.ZvFpFT.rst
new file mode 100644
index 000000000000000..fd1a6d7c5f47527
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-06-15-12-18.gh-issue-157025.ZvFpFT.rst
@@ -0,0 +1,2 @@
+Fix transport cleanup when cancelling :meth:`asyncio.loop.sendfile` while
+waiting for the write buffer to drain in the native implementation.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]