Issue #23214: Implement optional BufferedReader, BytesIO read1() argument
This commit is contained in:
parent
ea8762cae6
commit
ccb2c0e310
|
@ -477,7 +477,7 @@ I/O Base Classes
|
|||
A :exc:`BlockingIOError` is raised if the underlying raw stream is in
|
||||
non blocking-mode, and has no data available at the moment.
|
||||
|
||||
.. method:: read1(size=-1)
|
||||
.. method:: read1([size])
|
||||
|
||||
Read and return up to *size* bytes, with at most one call to the
|
||||
underlying raw stream's :meth:`~RawIOBase.read` (or
|
||||
|
@ -485,6 +485,9 @@ I/O Base Classes
|
|||
implementing your own buffering on top of a :class:`BufferedIOBase`
|
||||
object.
|
||||
|
||||
If *size* is −1 (the default), an arbitrary number of bytes are
|
||||
returned (more than zero unless EOF is reached).
|
||||
|
||||
.. method:: readinto(b)
|
||||
|
||||
Read bytes into a pre-allocated, writable
|
||||
|
@ -628,13 +631,16 @@ than raw I/O does.
|
|||
Return :class:`bytes` containing the entire contents of the buffer.
|
||||
|
||||
|
||||
.. method:: read1()
|
||||
.. method:: read1([size])
|
||||
|
||||
In :class:`BytesIO`, this is the same as :meth:`read`.
|
||||
In :class:`BytesIO`, this is the same as :meth:`~BufferedIOBase.read`.
|
||||
|
||||
.. method:: readinto1()
|
||||
.. versionchanged:: 3.7
|
||||
The *size* argument is now optional.
|
||||
|
||||
In :class:`BytesIO`, this is the same as :meth:`readinto`.
|
||||
.. method:: readinto1(b)
|
||||
|
||||
In :class:`BytesIO`, this is the same as :meth:`~BufferedIOBase.readinto`.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
@ -664,12 +670,15 @@ than raw I/O does.
|
|||
Read and return *size* bytes, or if *size* is not given or negative, until
|
||||
EOF or if the read call would block in non-blocking mode.
|
||||
|
||||
.. method:: read1(size)
|
||||
.. method:: read1([size])
|
||||
|
||||
Read and return up to *size* bytes with only one call on the raw stream.
|
||||
If at least one byte is buffered, only buffered bytes are returned.
|
||||
Otherwise, one raw stream read call is made.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
The *size* argument is now optional.
|
||||
|
||||
|
||||
.. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
|
||||
|
||||
|
|
18
Lib/_pyio.py
18
Lib/_pyio.py
|
@ -635,7 +635,7 @@ class BufferedIOBase(IOBase):
|
|||
implementation, but wrap one.
|
||||
"""
|
||||
|
||||
def read(self, size=None):
|
||||
def read(self, size=-1):
|
||||
"""Read and return up to size bytes, where size is an int.
|
||||
|
||||
If the argument is omitted, None, or negative, reads and
|
||||
|
@ -655,7 +655,7 @@ class BufferedIOBase(IOBase):
|
|||
"""
|
||||
self._unsupported("read")
|
||||
|
||||
def read1(self, size=None):
|
||||
def read1(self, size=-1):
|
||||
"""Read up to size bytes with at most one read() system call,
|
||||
where size is an int.
|
||||
"""
|
||||
|
@ -863,7 +863,7 @@ class BytesIO(BufferedIOBase):
|
|||
self._buffer.clear()
|
||||
super().close()
|
||||
|
||||
def read(self, size=None):
|
||||
def read(self, size=-1):
|
||||
if self.closed:
|
||||
raise ValueError("read from closed file")
|
||||
if size is None:
|
||||
|
@ -877,7 +877,7 @@ class BytesIO(BufferedIOBase):
|
|||
self._pos = newpos
|
||||
return bytes(b)
|
||||
|
||||
def read1(self, size):
|
||||
def read1(self, size=-1):
|
||||
"""This is the same as read.
|
||||
"""
|
||||
return self.read(size)
|
||||
|
@ -1073,12 +1073,12 @@ class BufferedReader(_BufferedIOMixin):
|
|||
self._read_pos = 0
|
||||
return self._read_buf[self._read_pos:]
|
||||
|
||||
def read1(self, size):
|
||||
def read1(self, size=-1):
|
||||
"""Reads up to size bytes, with at most one read() system call."""
|
||||
# Returns up to size bytes. If at least one byte is buffered, we
|
||||
# only return buffered bytes. Otherwise, we do one raw read.
|
||||
if size < 0:
|
||||
raise ValueError("number of bytes to read must be positive")
|
||||
size = self.buffer_size
|
||||
if size == 0:
|
||||
return b""
|
||||
with self._read_lock:
|
||||
|
@ -1270,7 +1270,7 @@ class BufferedRWPair(BufferedIOBase):
|
|||
self.reader = BufferedReader(reader, buffer_size)
|
||||
self.writer = BufferedWriter(writer, buffer_size)
|
||||
|
||||
def read(self, size=None):
|
||||
def read(self, size=-1):
|
||||
if size is None:
|
||||
size = -1
|
||||
return self.reader.read(size)
|
||||
|
@ -1284,7 +1284,7 @@ class BufferedRWPair(BufferedIOBase):
|
|||
def peek(self, size=0):
|
||||
return self.reader.peek(size)
|
||||
|
||||
def read1(self, size):
|
||||
def read1(self, size=-1):
|
||||
return self.reader.read1(size)
|
||||
|
||||
def readinto1(self, b):
|
||||
|
@ -1370,7 +1370,7 @@ class BufferedRandom(BufferedWriter, BufferedReader):
|
|||
self.flush()
|
||||
return BufferedReader.peek(self, size)
|
||||
|
||||
def read1(self, size):
|
||||
def read1(self, size=-1):
|
||||
self.flush()
|
||||
return BufferedReader.read1(self, size)
|
||||
|
||||
|
|
|
@ -1146,6 +1146,7 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
|||
self.assertEqual(b"a", bufio.read(1))
|
||||
self.assertEqual(b"b", bufio.read1(1))
|
||||
self.assertEqual(rawio._reads, 1)
|
||||
self.assertEqual(b"", bufio.read1(0))
|
||||
self.assertEqual(b"c", bufio.read1(100))
|
||||
self.assertEqual(rawio._reads, 1)
|
||||
self.assertEqual(b"d", bufio.read1(100))
|
||||
|
@ -1154,8 +1155,17 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
|
|||
self.assertEqual(rawio._reads, 3)
|
||||
self.assertEqual(b"", bufio.read1(100))
|
||||
self.assertEqual(rawio._reads, 4)
|
||||
# Invalid args
|
||||
self.assertRaises(ValueError, bufio.read1, -1)
|
||||
|
||||
def test_read1_arbitrary(self):
|
||||
rawio = self.MockRawIO((b"abc", b"d", b"efg"))
|
||||
bufio = self.tp(rawio)
|
||||
self.assertEqual(b"a", bufio.read(1))
|
||||
self.assertEqual(b"bc", bufio.read1())
|
||||
self.assertEqual(b"d", bufio.read1())
|
||||
self.assertEqual(b"efg", bufio.read1(-1))
|
||||
self.assertEqual(rawio._reads, 3)
|
||||
self.assertEqual(b"", bufio.read1())
|
||||
self.assertEqual(rawio._reads, 4)
|
||||
|
||||
def test_readinto(self):
|
||||
rawio = self.MockRawIO((b"abc", b"d", b"efg"))
|
||||
|
@ -1806,6 +1816,7 @@ class BufferedRWPairTest(unittest.TestCase):
|
|||
pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO())
|
||||
|
||||
self.assertEqual(pair.read1(3), b"abc")
|
||||
self.assertEqual(pair.read1(), b"def")
|
||||
|
||||
def test_readinto(self):
|
||||
for method in ("readinto", "readinto1"):
|
||||
|
@ -3467,6 +3478,7 @@ class MiscIOTest(unittest.TestCase):
|
|||
self.assertRaises(ValueError, f.read)
|
||||
if hasattr(f, "read1"):
|
||||
self.assertRaises(ValueError, f.read1, 1024)
|
||||
self.assertRaises(ValueError, f.read1)
|
||||
if hasattr(f, "readall"):
|
||||
self.assertRaises(ValueError, f.readall)
|
||||
if hasattr(f, "readinto"):
|
||||
|
|
|
@ -437,10 +437,8 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
|
|||
|
||||
def test_read1(self):
|
||||
buf = self.buftype("1234567890")
|
||||
memio = self.ioclass(buf)
|
||||
|
||||
self.assertRaises(TypeError, memio.read1)
|
||||
self.assertEqual(memio.read(), buf)
|
||||
self.assertEqual(self.ioclass(buf).read1(), buf)
|
||||
self.assertEqual(self.ioclass(buf).read1(-1), buf)
|
||||
|
||||
def test_readinto(self):
|
||||
buf = self.buftype("1234567890")
|
||||
|
|
|
@ -88,6 +88,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #23214: In the "io" module, the argument to BufferedReader and
|
||||
BytesIO's read1() methods is now optional and can be -1, matching the
|
||||
BufferedIOBase specification.
|
||||
|
||||
- Issue #28480: Fix error building socket module when multithreading is
|
||||
disabled.
|
||||
|
||||
|
|
|
@ -904,7 +904,7 @@ _io__Buffered_read_impl(buffered *self, Py_ssize_t n)
|
|||
CHECK_INITIALIZED(self)
|
||||
if (n < -1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"read length must be positive or -1");
|
||||
"read length must be non-negative or -1");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -932,22 +932,20 @@ _io__Buffered_read_impl(buffered *self, Py_ssize_t n)
|
|||
|
||||
/*[clinic input]
|
||||
_io._Buffered.read1
|
||||
size as n: Py_ssize_t
|
||||
size as n: Py_ssize_t = -1
|
||||
/
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_io__Buffered_read1_impl(buffered *self, Py_ssize_t n)
|
||||
/*[clinic end generated code: output=bcc4fb4e54d103a3 input=8d2869c18b983184]*/
|
||||
/*[clinic end generated code: output=bcc4fb4e54d103a3 input=7d22de9630b61774]*/
|
||||
{
|
||||
Py_ssize_t have, r;
|
||||
PyObject *res = NULL;
|
||||
|
||||
CHECK_INITIALIZED(self)
|
||||
if (n < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"read length must be positive");
|
||||
return NULL;
|
||||
n = self->buffer_size;
|
||||
}
|
||||
|
||||
CHECK_CLOSED(self, "read of closed file")
|
||||
|
|
|
@ -420,7 +420,7 @@ _io_BytesIO_read_impl(bytesio *self, PyObject *arg)
|
|||
|
||||
/*[clinic input]
|
||||
_io.BytesIO.read1
|
||||
size: object
|
||||
size: object(c_default="Py_None") = -1
|
||||
/
|
||||
|
||||
Read at most size bytes, returned as a bytes object.
|
||||
|
@ -430,8 +430,8 @@ Return an empty bytes object at EOF.
|
|||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_io_BytesIO_read1(bytesio *self, PyObject *size)
|
||||
/*[clinic end generated code: output=16021f5d0ac3d4e2 input=d4f40bb8f2f99418]*/
|
||||
_io_BytesIO_read1_impl(bytesio *self, PyObject *size)
|
||||
/*[clinic end generated code: output=a60d80c84c81a6b8 input=0951874bafee8e80]*/
|
||||
{
|
||||
return _io_BytesIO_read_impl(self, size);
|
||||
}
|
||||
|
|
|
@ -140,23 +140,24 @@ exit:
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(_io__Buffered_read1__doc__,
|
||||
"read1($self, size, /)\n"
|
||||
"read1($self, size=-1, /)\n"
|
||||
"--\n"
|
||||
"\n");
|
||||
|
||||
#define _IO__BUFFERED_READ1_METHODDEF \
|
||||
{"read1", (PyCFunction)_io__Buffered_read1, METH_O, _io__Buffered_read1__doc__},
|
||||
{"read1", (PyCFunction)_io__Buffered_read1, METH_VARARGS, _io__Buffered_read1__doc__},
|
||||
|
||||
static PyObject *
|
||||
_io__Buffered_read1_impl(buffered *self, Py_ssize_t n);
|
||||
|
||||
static PyObject *
|
||||
_io__Buffered_read1(buffered *self, PyObject *arg)
|
||||
_io__Buffered_read1(buffered *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_ssize_t n;
|
||||
Py_ssize_t n = -1;
|
||||
|
||||
if (!PyArg_Parse(arg, "n:read1", &n)) {
|
||||
if (!PyArg_ParseTuple(args, "|n:read1",
|
||||
&n)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _io__Buffered_read1_impl(self, n);
|
||||
|
@ -475,4 +476,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=a956f394ecde4cf9 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=490c97bfcfd92c51 input=a9049054013a1b77]*/
|
||||
|
|
|
@ -181,7 +181,7 @@ exit:
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(_io_BytesIO_read1__doc__,
|
||||
"read1($self, size, /)\n"
|
||||
"read1($self, size=-1, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Read at most size bytes, returned as a bytes object.\n"
|
||||
|
@ -190,7 +190,27 @@ PyDoc_STRVAR(_io_BytesIO_read1__doc__,
|
|||
"Return an empty bytes object at EOF.");
|
||||
|
||||
#define _IO_BYTESIO_READ1_METHODDEF \
|
||||
{"read1", (PyCFunction)_io_BytesIO_read1, METH_O, _io_BytesIO_read1__doc__},
|
||||
{"read1", (PyCFunction)_io_BytesIO_read1, METH_VARARGS, _io_BytesIO_read1__doc__},
|
||||
|
||||
static PyObject *
|
||||
_io_BytesIO_read1_impl(bytesio *self, PyObject *size);
|
||||
|
||||
static PyObject *
|
||||
_io_BytesIO_read1(bytesio *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *size = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "read1",
|
||||
0, 1,
|
||||
&size)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _io_BytesIO_read1_impl(self, size);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_io_BytesIO_readline__doc__,
|
||||
"readline($self, size=None, /)\n"
|
||||
|
@ -428,4 +448,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=6382e8eb578eea64 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=8f469431da1b3857 input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue