https://github.com/python/cpython/commit/601e69562e8c5b290922671ad8fc53c59e54ca47
commit: 601e69562e8c5b290922671ad8fc53c59e54ca47
branch: 3.14
author: Timofei Ivankov <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-08-17T10:30:35+05:30
summary:

[3.14] gh-155888: Fix asyncio writelines() hanging on an empty last chunk 
(#155913)

files:
A Misc/NEWS.d/next/Library/2026-08-16-11-38-17.gh-issue-155888.pO-nAp.rst
M Lib/asyncio/selector_events.py
M Lib/test/test_asyncio/test_events.py

diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 0c96e81cce0bd5a..3aac81215dc0aea 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -1183,7 +1183,11 @@ def writelines(self, list_of_data):
             self._conn_lost += 1
             return
 
-        self._buffer.extend([memoryview(data) for data in list_of_data])
+        # gh-155888: an empty chunk can never be drained, so never buffer it
+        self._buffer.extend(
+            [memoryview(data) for data in list_of_data if data])
+        if not self._buffer:
+            return
         self._write_ready()
         # If the entire buffer couldn't be written, register a write handler
         if self._buffer:
diff --git a/Lib/test/test_asyncio/test_events.py 
b/Lib/test/test_asyncio/test_events.py
index 888e8b4d11b978a..1ee39b0fac3ad62 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -560,6 +560,19 @@ def writer(data):
         r.close()
         self.assertEqual(read, data)
 
+    def test_writelines_empty_chunk(self):
+        # gh-155888: an empty chunk can never be drained, so never buffer it
+        rsock, wsock = socket.socketpair()
+        self.addCleanup(rsock.close)
+
+        async def main():
+            reader, writer = await asyncio.open_connection(sock=wsock)
+            writer.writelines([b'data', b''])
+            writer.close()
+            await asyncio.wait_for(writer.wait_closed(), support.SHORT_TIMEOUT)
+
+        self.loop.run_until_complete(main())
+
     @unittest.skipUnless(hasattr(signal, 'SIGKILL'), 'No SIGKILL')
     def test_add_signal_handler(self):
         caught = 0
diff --git 
a/Misc/NEWS.d/next/Library/2026-08-16-11-38-17.gh-issue-155888.pO-nAp.rst 
b/Misc/NEWS.d/next/Library/2026-08-16-11-38-17.gh-issue-155888.pO-nAp.rst
new file mode 100644
index 000000000000000..df3db71b912e1c2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-16-11-38-17.gh-issue-155888.pO-nAp.rst
@@ -0,0 +1,2 @@
+Fix :meth:`asyncio.WriteTransport.writelines` hanging the transport when the
+last data chunk is empty.

_______________________________________________
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]

Reply via email to