https://github.com/python/cpython/commit/880696af1aff6f4170fbacdfb8aa73a84be73da5
commit: 880696af1aff6f4170fbacdfb8aa73a84be73da5
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-03T22:15:45Z
summary:

gh-158585: Use PyBytesWriter in io.BufferedReader.readline() (#158615)

Replace a list of bytes object with PyBytesWriter.

files:
M Modules/_io/bufferedio.c

diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 2cc3774e75c9dad..d6318af1263d9c6 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1205,109 +1205,115 @@ _io__Buffered_readinto1_impl(buffered *self, 
Py_buffer *buffer)
 static PyObject *
 _buffered_readline(buffered *self, Py_ssize_t limit)
 {
-    PyObject *res = NULL;
-    PyObject *chunks = NULL;
-    Py_ssize_t n;
-    const char *start, *s, *end;
+    _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
 
     CHECK_CLOSED(self, "readline of closed file")
 
     /* First, try to find a line in the buffer. This can run unlocked because
        the calls to the C API are simple enough that they can't trigger
        any thread switch. */
-    n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (limit >= 0 && n > limit)
+    Py_ssize_t n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
+    if (limit >= 0 && n > limit) {
         n = limit;
-    start = self->buffer + self->pos;
-    s = memchr(start, '\n', n);
+    }
+    const char *start = self->buffer + self->pos;
+    const char *s = memchr(start, '\n', n);
     if (s != NULL) {
-        res = PyBytes_FromStringAndSize(start, s - start + 1);
-        if (res != NULL)
-            self->pos += s - start + 1;
-        goto end_unlocked;
+        n = s - start + 1;
+        PyObject *res = PyBytes_FromStringAndSize(start, n);
+        if (res == NULL) {
+            return NULL;
+        }
+        self->pos += n;
+        return res;
     }
+
     if (n == limit) {
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res != NULL)
-            self->pos += n;
-        goto end_unlocked;
+        PyObject *res = PyBytes_FromStringAndSize(start, n);
+        if (res == NULL) {
+            return NULL;
+        }
+        self->pos += n;
+        return res;
     }
 
-    if (!ENTER_BUFFERED(self))
-        goto end_unlocked;
+    PyBytesWriter *writer = NULL;
+    int locked = 0;
+    if (!ENTER_BUFFERED(self)) {
+        goto error;
+    }
+    locked = 1;
 
     /* Now we try to get some more from the raw stream */
-    chunks = PyList_New(0);
-    if (chunks == NULL)
-        goto end;
+    writer = PyBytesWriter_Create(0);
+    if (writer == NULL) {
+        goto error;
+    }
+
     if (n > 0) {
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res == NULL)
-            goto end;
-        if (PyList_Append(chunks, res) < 0) {
-            Py_CLEAR(res);
-            goto end;
+        if (PyBytesWriter_WriteBytes(writer, start, n) < 0) {
+            goto error;
         }
-        Py_CLEAR(res);
         self->pos += n;
-        if (limit >= 0)
+        if (limit >= 0) {
             limit -= n;
+        }
     }
     if (self->writable) {
-        PyObject *r = buffered_flush_and_rewind_unlocked(self);
-        if (r == NULL)
-            goto end;
-        Py_DECREF(r);
+        PyObject *res = buffered_flush_and_rewind_unlocked(self);
+        if (res == NULL) {
+            goto error;
+        }
+        Py_DECREF(res);
     }
 
     for (;;) {
         _bufferedreader_reset_buf(self);
         n = _bufferedreader_fill_buffer(self);
-        if (n == -1)
-            goto end;
-        if (n <= 0)
+        if (n == -1) {
+            goto error;
+        }
+        if (n <= 0) {
             break;
-        if (limit >= 0 && n > limit)
+        }
+        if (limit >= 0 && n > limit) {
             n = limit;
+        }
         start = self->buffer;
-        end = start + n;
+        const char *end = start + n;
         s = start;
         while (s < end) {
             if (*s++ == '\n') {
-                res = PyBytes_FromStringAndSize(start, s - start);
-                if (res == NULL)
-                    goto end;
+                if (PyBytesWriter_WriteBytes(writer, start, s - start) < 0) {
+                    goto error;
+                }
                 self->pos = s - start;
                 goto found;
             }
         }
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res == NULL)
-            goto end;
+
+        if (PyBytesWriter_WriteBytes(writer, start, n) < 0) {
+            goto error;
+        }
         if (n == limit) {
             self->pos = n;
             break;
         }
-        if (PyList_Append(chunks, res) < 0) {
-            Py_CLEAR(res);
-            goto end;
-        }
-        Py_CLEAR(res);
-        if (limit >= 0)
+        if (limit >= 0) {
             limit -= n;
+        }
     }
-found:
-    if (res != NULL && PyList_Append(chunks, res) < 0) {
-        Py_CLEAR(res);
-        goto end;
-    }
-    Py_XSETREF(res, PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), 
chunks));
 
-end:
+found:
     LEAVE_BUFFERED(self)
-end_unlocked:
-    Py_XDECREF(chunks);
-    return res;
+    return PyBytesWriter_Finish(writer);
+
+error:
+    PyBytesWriter_Discard(writer);
+    if (locked) {
+        LEAVE_BUFFERED(self)
+    }
+    return NULL;
 }
 
 /*[clinic input]

_______________________________________________
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