Skip to content

Commit 13aa41f

Browse files
authored
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.
1 parent f101660 commit 13aa41f

2 files changed

Lines changed: 17 additions & 2 deletions

File tree

Lib/_pyio.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,9 +1003,19 @@ def tell(self):
10031003
def peek(self, size=0):
10041004
if self.closed:
10051005
raise ValueError("peek on closed file")
1006+
try:
1007+
size_index = size.__index__
1008+
except AttributeError:
1009+
raise TypeError(f"{size!r} is not an integer")
1010+
else:
1011+
size = size_index()
1012+
10061013
if size < 1:
1007-
return self._buffer[self._pos:self._pos + io.DEFAULT_BUFFER_SIZE]
1008-
return self._buffer[self._pos:self._pos + size]
1014+
size = io.DEFAULT_BUFFER_SIZE
1015+
1016+
with self._lock:
1017+
b = self._buffer[self._pos:self._pos + size]
1018+
return b.take_bytes()
10091019

10101020
def truncate(self, pos=None):
10111021
if self.closed:

Lib/test/test_io/test_memoryio.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@ def test_peek(self):
596596
buf = self.buftype("1234567890")
597597
with self.ioclass(buf) as memio:
598598
self.assertEqual(memio.tell(), 0)
599+
# bytearray(b'1') == b'1', so the type has to be asserted separately.
600+
self.assertIsInstance(memio.peek(), bytes)
601+
self.assertIsInstance(memio.peek(1), bytes)
602+
self.assertEqual(memio.peek(IntLike(3)), buf[:3])
603+
self.assertRaises(TypeError, memio.peek, 1.5)
599604
self.assertEqual(memio.peek(1), buf[:1])
600605
self.assertEqual(memio.peek(1), buf[:1])
601606
self.assertEqual(memio.peek(), buf)

0 commit comments

Comments
 (0)