# HG changeset patch # Parent b8acf98beca9c9c155c8581b9acafa774bca514f Issue #23214: Implement optional BufferedReader, BytesIO read1() argument diff -r b8acf98beca9 Doc/library/io.rst --- a/Doc/library/io.rst Sat Mar 19 02:51:45 2016 +0100 +++ b/Doc/library/io.rst Sat Mar 19 06:12:45 2016 +0000 @@ -466,7 +466,7 @@ 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 @@ -474,6 +474,9 @@ 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 up to ``len(b)`` bytes into bytearray *b* and return the number of @@ -612,13 +615,16 @@ 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.6 + 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 @@ -648,12 +654,15 @@ 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.6 + The *size* argument is now optional. + .. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE) diff -r b8acf98beca9 Lib/_pyio.py --- a/Lib/_pyio.py Sat Mar 19 02:51:45 2016 +0100 +++ b/Lib/_pyio.py Sat Mar 19 06:12:45 2016 +0000 @@ -632,7 +632,7 @@ 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 @@ -652,7 +652,7 @@ """ 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. """ @@ -866,7 +866,7 @@ 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: @@ -880,7 +880,7 @@ 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) @@ -1072,12 +1072,12 @@ 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: @@ -1267,7 +1267,7 @@ 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) @@ -1281,7 +1281,7 @@ 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): @@ -1367,7 +1367,7 @@ self.flush() return BufferedReader.peek(self, size) - def read1(self, size): + def read1(self, size=-1): self.flush() return BufferedReader.read1(self, size) diff -r b8acf98beca9 Lib/test/test_io.py --- a/Lib/test/test_io.py Sat Mar 19 02:51:45 2016 +0100 +++ b/Lib/test/test_io.py Sat Mar 19 06:12:45 2016 +0000 @@ -960,6 +960,7 @@ 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)) @@ -968,8 +969,17 @@ 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")) @@ -1615,6 +1625,7 @@ 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): pair = self.tp(self.BytesIO(b"abcdef"), self.MockRawIO()) @@ -3271,6 +3282,7 @@ 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"): diff -r b8acf98beca9 Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py Sat Mar 19 02:51:45 2016 +0100 +++ b/Lib/test/test_memoryio.py Sat Mar 19 06:12:45 2016 +0000 @@ -440,10 +440,8 @@ 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") diff -r b8acf98beca9 Misc/NEWS --- a/Misc/NEWS Sat Mar 19 02:51:45 2016 +0100 +++ b/Misc/NEWS Sat Mar 19 06:12:45 2016 +0000 @@ -226,6 +226,10 @@ 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 #26567: Add a new function :c:func:`PyErr_ResourceWarning` function to pass the destroyed object. Add a *source* attribute to :class:`warnings.WarningMessage`. Add warnings._showwarnmsg() which uses diff -r b8acf98beca9 Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Sat Mar 19 02:51:45 2016 +0100 +++ b/Modules/_io/bufferedio.c Sat Mar 19 06:12:45 2016 +0000 @@ -904,7 +904,7 @@ 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 @@ /*[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") diff -r b8acf98beca9 Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c Sat Mar 19 02:51:45 2016 +0100 +++ b/Modules/_io/bytesio.c Sat Mar 19 06:12:45 2016 +0000 @@ -420,7 +420,7 @@ /*[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 @@ [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); } diff -r b8acf98beca9 Modules/_io/clinic/bufferedio.c.h --- a/Modules/_io/clinic/bufferedio.c.h Sat Mar 19 02:51:45 2016 +0100 +++ b/Modules/_io/clinic/bufferedio.c.h Sat Mar 19 06:12:45 2016 +0000 @@ -134,23 +134,24 @@ } 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); @@ -451,4 +452,4 @@ exit: return return_value; } -/*[clinic end generated code: output=2bbb5e239b4ffe6f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dc673580cf2fca9f input=a9049054013a1b77]*/ diff -r b8acf98beca9 Modules/_io/clinic/bytesio.c.h --- a/Modules/_io/clinic/bytesio.c.h Sat Mar 19 02:51:45 2016 +0100 +++ b/Modules/_io/clinic/bytesio.c.h Sat Mar 19 06:12:45 2016 +0000 @@ -180,7 +180,7 @@ } 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" @@ -189,7 +189,26 @@ "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" @@ -419,4 +438,4 @@ exit: return return_value; } -/*[clinic end generated code: output=500ccc149587fac4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=afb26d28f19fdeae input=a9049054013a1b77]*/