https://github.com/python/cpython/commit/b2c299373d86b670f50d930564da22550af55308
commit: b2c299373d86b670f50d930564da22550af55308
branch: main
author: Timofei Ivankov <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-08-16T15:12:55+05:30
summary:

gh-155888: Fix asyncio writelines() hanging on an empty chunk (#155889)

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 19ffd8cc98b0e9d..83916160b9fbde9 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -1198,8 +1198,13 @@ def writelines(self, list_of_data):
             return
 
         for data in list_of_data:
+            # gh-155888: an empty chunk can never be drained, so never buffer 
it
+            if not data:
+                continue
             self._buffer.append(memoryview(data))
             self._buffer_size += len(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 f7cd59a54199710..db316fae090280a 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