Skip to content

bpo-32475: Add argument to peek() into I/O buffer without reading #7947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Doc/library/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,15 @@ than raw I/O does.
:class:`BufferedReader` provides or overrides these methods in addition to
those from :class:`BufferedIOBase` and :class:`IOBase`:

.. method:: peek([size])
.. method:: peek([size][, allow_read])

Return bytes from the stream without advancing the position. At most one
single read on the raw stream is done to satisfy the call. The number of
bytes returned may be less or more than requested.

If *allow_read* is supplied and False, only bytes already buffered are
returned, and no reads are done on the raw stream.

.. method:: read([size])

Read and return *size* bytes, or if *size* is not given or negative, until
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
New optional argument to `BufferedReader.peek`: `allow_read` prevents reads of
the underlying file when set to False.
13 changes: 7 additions & 6 deletions Modules/_io/bufferedio.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ _bufferedreader_reset_buf(buffered *self);
static void
_bufferedwriter_reset_buf(buffered *self);
static PyObject *
_bufferedreader_peek_unlocked(buffered *self);
_bufferedreader_peek_unlocked(buffered *self, int);
static PyObject *
_bufferedreader_read_all(buffered *self);
static PyObject *
Expand Down Expand Up @@ -843,13 +843,14 @@ buffered_flush(buffered *self, PyObject *args)
/*[clinic input]
_io._Buffered.peek
size: Py_ssize_t = 0
allow_read: bool = True
/

[clinic start generated code]*/

static PyObject *
_io__Buffered_peek_impl(buffered *self, Py_ssize_t size)
/*[clinic end generated code: output=ba7a097ca230102b input=37ffb97d06ff4adb]*/
_io__Buffered_peek_impl(buffered *self, Py_ssize_t size, int allow_read)
/*[clinic end generated code: output=14a0ef8e7da9806a input=97d65e49c07606d3]*/
{
PyObject *res = NULL;

Expand All @@ -865,7 +866,7 @@ _io__Buffered_peek_impl(buffered *self, Py_ssize_t size)
goto end;
Py_CLEAR(res);
}
res = _bufferedreader_peek_unlocked(self);
res = _bufferedreader_peek_unlocked(self, allow_read);

end:
LEAVE_BUFFERED(self)
Expand Down Expand Up @@ -1725,7 +1726,7 @@ _bufferedreader_read_generic(buffered *self, Py_ssize_t n)
}

static PyObject *
_bufferedreader_peek_unlocked(buffered *self)
_bufferedreader_peek_unlocked(buffered *self, int allow_read)
{
Py_ssize_t have, r;

Expand All @@ -1736,7 +1737,7 @@ _bufferedreader_peek_unlocked(buffered *self)
to make some place.
Therefore, we either return `have` bytes (if > 0), or a full buffer.
*/
if (have > 0) {
if (have > 0 || !allow_read) {
return PyBytes_FromStringAndSize(self->buffer + self->pos, have);
}

Expand Down
13 changes: 7 additions & 6 deletions Modules/_io/clinic/bufferedio.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,27 +86,28 @@ _io__BufferedIOBase_detach(PyObject *self, PyObject *Py_UNUSED(ignored))
}

PyDoc_STRVAR(_io__Buffered_peek__doc__,
"peek($self, size=0, /)\n"
"peek($self, size=0, allow_read=True, /)\n"
"--\n"
"\n");

#define _IO__BUFFERED_PEEK_METHODDEF \
{"peek", (PyCFunction)_io__Buffered_peek, METH_FASTCALL, _io__Buffered_peek__doc__},

static PyObject *
_io__Buffered_peek_impl(buffered *self, Py_ssize_t size);
_io__Buffered_peek_impl(buffered *self, Py_ssize_t size, int allow_read);

static PyObject *
_io__Buffered_peek(buffered *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
Py_ssize_t size = 0;
int allow_read = 1;

if (!_PyArg_ParseStack(args, nargs, "|n:peek",
&size)) {
if (!_PyArg_ParseStack(args, nargs, "|np:peek",
&size, &allow_read)) {
goto exit;
}
return_value = _io__Buffered_peek_impl(self, size);
return_value = _io__Buffered_peek_impl(self, size, allow_read);

exit:
return return_value;
Expand Down Expand Up @@ -476,4 +477,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
exit:
return return_value;
}
/*[clinic end generated code: output=9a20dd4eaabb5d58 input=a9049054013a1b77]*/
/*[clinic end generated code: output=b0f91041c4b36d20 input=a9049054013a1b77]*/