Skip to content

Commit b786a5e

Browse files
committed
gh-155389: Return bytes from _pyio.BytesIO.peek()
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 8ed1479 commit b786a5e

2 files changed

Lines changed: 16 additions & 3 deletions

File tree

Lib/_pyio.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,9 +1003,18 @@ def tell(self):
10031003
def peek(self, size=0):
10041004
if self.closed:
10051005
raise ValueError("peek on closed file")
1006-
if size < 1:
1007-
return self._buffer[self._pos:self._pos + io.DEFAULT_BUFFER_SIZE]
1008-
return self._buffer[self._pos:self._pos + size]
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+
1013+
with self._lock:
1014+
if size < 1:
1015+
size = io.DEFAULT_BUFFER_SIZE
1016+
b = self._buffer[self._pos:self._pos + size]
1017+
return b.take_bytes()
10091018

10101019
def truncate(self, pos=None):
10111020
if self.closed:

Lib/test/test_io/test_memoryio.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,10 @@ def test_peek(self):
570570
buf = self.buftype("1234567890")
571571
with self.ioclass(buf) as memio:
572572
self.assertEqual(memio.tell(), 0)
573+
# bytearray(b'1') == b'1', so the type has to be asserted separately.
574+
self.assertIsInstance(memio.peek(), bytes)
575+
self.assertIsInstance(memio.peek(1), bytes)
576+
self.assertEqual(memio.peek(IntLike(3)), buf[:3])
573577
self.assertEqual(memio.peek(1), buf[:1])
574578
self.assertEqual(memio.peek(1), buf[:1])
575579
self.assertEqual(memio.peek(), buf)

0 commit comments

Comments
 (0)