Skip to content

Commit b493914

Browse files
committed
Update docs, factor out peek_bytes, semantics
Semantic change: The default argument for peek is now size=1.
1 parent 79ab9a4 commit b493914

5 files changed

Lines changed: 44 additions & 28 deletions

File tree

Doc/library/io.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,12 +739,15 @@ than raw I/O does.
739739

740740
Return :class:`bytes` containing the entire contents of the buffer.
741741

742-
.. method:: peek(size=0, /)
743-
744-
.. versionadded:: 3.13
742+
.. method:: peek(size=1, /)
745743

746744
Return bytes from the current position onwards but without advancing the
747-
position. The number of bytes returned may be less or more than requested.
745+
position. If the size argument is less than one or larger than the number
746+
of available bytes, a copy of the buffer from the current position until
747+
the end is returned.
748+
Return an empty bytes object at EOF.
749+
750+
.. versionadded:: 3.15
748751

749752
.. method:: read1(size=-1, /)
750753

Lib/_pyio.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -996,13 +996,12 @@ def tell(self):
996996
raise ValueError("tell on closed file")
997997
return self._pos
998998

999-
def peek(self, size=-1):
1000-
pos = self.tell()
1001-
if size == 0:
1002-
size = -1
1003-
b = self.read(size)
1004-
self.seek(pos)
1005-
return b
999+
def peek(self, size=1):
1000+
if self.closed:
1001+
raise ValueError("peek on closed file")
1002+
if size < 1:
1003+
size = len(self._buffer) - self._pos
1004+
return self._buffer[self._pos : self._pos + size]
10061005

10071006
def truncate(self, pos=None):
10081007
if self.closed:

Lib/test/test_io/test_memoryio.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,12 +572,13 @@ def test_peek(self):
572572
pos = memio.tell()
573573
self.assertEqual(memio.peek(1), buf[:1])
574574
self.assertEqual(memio.peek(1), buf[:1])
575-
self.assertEqual(memio.peek(), buf)
575+
self.assertEqual(memio.peek(), buf[:1])
576576
self.assertEqual(memio.peek(0), buf)
577577
self.assertEqual(memio.tell(), pos)
578578
memio.read(1)
579579
self.assertEqual(memio.peek(1), buf[1:2])
580-
self.assertEqual(memio.peek(), buf[1:])
580+
self.assertEqual(memio.peek(), buf[1:2])
581+
self.assertEqual(memio.peek(0), buf[1:])
581582
self.assertEqual(memio.peek(42), buf[1:])
582583
memio.read()
583584
self.assertEqual(memio.peek(1), self.EOF)

Modules/_io/bytesio.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,9 @@ _io_BytesIO_tell_impl(bytesio *self)
420420
return PyLong_FromSsize_t(self->pos);
421421
}
422422

423+
// Read without advancing position
423424
static PyObject *
424-
read_bytes_lock_held(bytesio *self, Py_ssize_t size)
425+
peek_bytes_lock_held(bytesio *self, Py_ssize_t size)
425426
{
426427
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
427428

@@ -432,7 +433,6 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size)
432433
if (size > 1 &&
433434
self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
434435
FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) {
435-
self->pos += size;
436436
return Py_NewRef(self->buf);
437437
}
438438

@@ -444,10 +444,16 @@ read_bytes_lock_held(bytesio *self, Py_ssize_t size)
444444
}
445445

446446
output = PyBytes_AS_STRING(self->buf) + self->pos;
447-
self->pos += size;
448447
return PyBytes_FromStringAndSize(output, size);
449448
}
450449

450+
static PyObject *
451+
read_bytes_lock_held(bytesio *self, Py_ssize_t size) {
452+
PyObject *bytes = peek_bytes_lock_held(self, size);
453+
self->pos += size;
454+
return bytes;
455+
}
456+
451457
/*[clinic input]
452458
@critical_section
453459
_io.BytesIO.read
@@ -502,17 +508,18 @@ _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size)
502508

503509
/*[clinic input]
504510
_io.BytesIO.peek
505-
size: Py_ssize_t(accept={int, NoneType}) = -1
511+
size: Py_ssize_t = 1
506512
/
507513
508514
Return bytes from the stream without advancing the position.
509515
516+
If the size argument is zero or negative, read until EOF is reached.
510517
Return an empty bytes object at EOF.
511518
[clinic start generated code]*/
512519

513520
static PyObject *
514521
_io_BytesIO_peek_impl(bytesio *self, Py_ssize_t size)
515-
/*[clinic end generated code: output=fa4d8ce28b35db9b input=afc80e71b37e7c59]*/
522+
/*[clinic end generated code: output=fa4d8ce28b35db9b input=cb06614a3ed0496e]*/
516523
{
517524
Py_ssize_t n;
518525

@@ -525,11 +532,7 @@ _io_BytesIO_peek_impl(bytesio *self, Py_ssize_t size)
525532
if (size < 0)
526533
size = 0;
527534
}
528-
Py_ssize_t prev_pos = self->pos;
529-
PyObject* result = read_bytes_lock_held(self, size);
530-
self->pos = prev_pos;
531-
532-
return result;
535+
return peek_bytes_lock_held(self, size);
533536
}
534537

535538

Modules/_io/clinic/bytesio.c.h

Lines changed: 15 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)