https://github.com/python/cpython/commit/105c6419fec67478d6400583932a042e4cda1426
commit: 105c6419fec67478d6400583932a042e4cda1426
branch: 3.14
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-10-24T13:42:51-07:00
summary:
[3.14] gh-159739: Respect readline limits after a short read (GH-159974)
(#160483)
(cherry picked from commit 87eaef117191037cebce2becea5350ff4f45dee3)
files:
A Misc/NEWS.d/next/Library/2026-10-20-00-00-00.gh-issue-159739.4c9783.rst
M Lib/_pyio.py
M Lib/test/test_io.py
M Modules/_io/iobase.c
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index cc336d2939443c..01fd821fb0049c 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -528,7 +528,7 @@ def nreadahead():
return 1
n = (readahead.find(b"\n") + 1) or len(readahead)
if size >= 0:
- n = min(n, size)
+ n = min(n, size - len(res))
return n
else:
def nreadahead():
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index d11e66e94b4970..cbec18fb403632 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -624,6 +624,22 @@ def test_readline(self):
with self.open(os_helper.TESTFN, "r", encoding="utf-8") as f:
self.assertRaises(TypeError, f.readline, 5.3)
+ def test_readline_limit_with_short_read(self):
+ class Reader(self.IOBase):
+ data = b"abcdef"
+
+ def peek(self, size):
+ return self.data
+
+ def read(self, size):
+ data = self.data[:min(size, 2)]
+ self.data = self.data[len(data):]
+ return data
+
+ reader = Reader()
+ self.assertEqual(reader.readline(3), b"abc")
+ self.assertEqual(reader.data, b"def")
+
def test_readline_nonsizeable(self):
# Issue #30061
# Crash when readline() returns an object without __len__
diff --git
a/Misc/NEWS.d/next/Library/2026-10-20-00-00-00.gh-issue-159739.4c9783.rst
b/Misc/NEWS.d/next/Library/2026-10-20-00-00-00.gh-issue-159739.4c9783.rst
new file mode 100644
index 00000000000000..b65ac4cede106b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-20-00-00-00.gh-issue-159739.4c9783.rst
@@ -0,0 +1,2 @@
+Fix :meth:`io.IOBase.readline` returning more bytes than requested when a
+stream supports :meth:`!peek` and returns short reads.
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
index e291d7cfc4710f..5cbd28ca136b4b 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -609,8 +609,9 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
Py_ssize_t n = 0;
const char *buf = PyBytes_AS_STRING(readahead);
if (limit >= 0) {
+ Py_ssize_t remaining = limit -
PyByteArray_GET_SIZE(buffer);
do {
- if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
+ if (n >= PyBytes_GET_SIZE(readahead) || n >= remaining)
break;
if (buf[n++] == '\n')
break;
_______________________________________________
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]