https://github.com/python/cpython/commit/5cd6cfe4cf6770b9424bb23f8c7c661f7a3db7b0
commit: 5cd6cfe4cf6770b9424bb23f8c7c661f7a3db7b0
branch: 3.14
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-10-07T23:06:04+05:30
summary:
[3.14] gh-136234: Fix `SelectorSocketTransport.writelines` to be robust to
connection loss (GH-136743) (#138702)
files:
A Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst
M Lib/asyncio/selector_events.py
M Lib/test/test_asyncio/test_selector_events.py
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index f8744cbb223003..6a949f35a16a67 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -1174,6 +1174,13 @@ def writelines(self, list_of_data):
raise RuntimeError('unable to writelines; sendfile is in progress')
if not list_of_data:
return
+
+ if self._conn_lost:
+ if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
+ logger.warning('socket.send() raised exception.')
+ self._conn_lost += 1
+ return
+
self._buffer.extend([memoryview(data) for data in list_of_data])
self._write_ready()
# If the entire buffer couldn't be written, register a write handler
diff --git a/Lib/test/test_asyncio/test_selector_events.py
b/Lib/test/test_asyncio/test_selector_events.py
index 7b6d1bce5e460f..5a7df774e60858 100644
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -854,6 +854,22 @@ def test_writelines_pauses_protocol(self):
self.assertTrue(self.sock.send.called)
self.assertTrue(self.loop.writers)
+ def test_writelines_after_connection_lost(self):
+ # GH-136234
+ transport = self.socket_transport()
+ self.sock.send = mock.Mock()
+ self.sock.send.side_effect = ConnectionResetError
+ transport.write(b'data1') # Will fail immediately, causing connection
lost
+
+ transport.writelines([b'data2'])
+ self.assertFalse(transport._buffer)
+ self.assertFalse(self.loop.writers)
+
+ test_utils.run_briefly(self.loop) # Allow _call_connection_lost to run
+ transport.writelines([b'data2'])
+ self.assertFalse(transport._buffer)
+ self.assertFalse(self.loop.writers)
+
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
def test_write_sendmsg_full(self):
data = memoryview(b'data')
diff --git
a/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst
b/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst
new file mode 100644
index 00000000000000..044a601c9170a1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-17-16-12-23.gh-issue-136234.VmTxtj.rst
@@ -0,0 +1,2 @@
+Fix :meth:`asyncio.WriteTransport.writelines` to be robust to connection
+failure, by using the same behavior as :meth:`~asyncio.WriteTransport.write`.
_______________________________________________
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]