gh-155389: Return bytes from _pyio.BytesIO.peek() (GH-155390)

serhiy-storchaka <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/13aa41f4e253f23c8a2adb5565996cc9227d596e
commit: 13aa41f4e253f23c8a2adb5565996cc9227d596e
branch: main
author: Vyron Vasileiadis <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-16T10:51:56+03:00
summary:

gh-155389: Return bytes from _pyio.BytesIO.peek() (GH-155390)

peek() returned a slice of the internal bytearray, where read() converts with
take_bytes(). It also did not coerce its size through __index__ and did not
hold the lock while slicing, both of which read() and the C implementation do.

files:
M Lib/_pyio.py
M Lib/test/test_io/test_memoryio.py

diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index ac301180d284fa9..cf4ef04f37d26cc 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -1003,9 +1003,19 @@ def tell(self):
     def peek(self, size=0):
         if self.closed:
             raise ValueError("peek on closed file")
+        try:
+            size_index = size.__index__
+        except AttributeError:
+            raise TypeError(f"{size!r} is not an integer")
+        else:
+            size = size_index()
+
         if size < 1:
-            return self._buffer[self._pos:self._pos + io.DEFAULT_BUFFER_SIZE]
-        return self._buffer[self._pos:self._pos + size]
+            size = io.DEFAULT_BUFFER_SIZE
+
+        with self._lock:
+            b = self._buffer[self._pos:self._pos + size]
+            return b.take_bytes()
 
     def truncate(self, pos=None):
         if self.closed:
diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py
index 0037fdc2fd67c1a..e934e3fb2bdf124 100644
--- a/Lib/test/test_io/test_memoryio.py
+++ b/Lib/test/test_io/test_memoryio.py
@@ -596,6 +596,11 @@ def test_peek(self):
         buf = self.buftype("1234567890")
         with self.ioclass(buf) as memio:
             self.assertEqual(memio.tell(), 0)
+            # bytearray(b'1') == b'1', so the type has to be asserted separately.
+            self.assertIsInstance(memio.peek(), bytes)
+            self.assertIsInstance(memio.peek(1), bytes)
+            self.assertEqual(memio.peek(IntLike(3)), buf[:3])
+            self.assertRaises(TypeError, memio.peek, 1.5)
             self.assertEqual(memio.peek(1), buf[:1])
             self.assertEqual(memio.peek(1), buf[:1])
             self.assertEqual(memio.peek(), buf)

_______________________________________________
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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.