summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/_pyio.py6
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/_io/_iomodule.c3
-rw-r--r--Modules/_io/_iomodule.h1
-rw-r--r--Modules/_io/bufferedio.c47
5 files changed, 48 insertions, 11 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index 74047bf..265edab 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -944,6 +944,12 @@ class BufferedReader(_BufferedIOMixin):
# Special case for when the number of bytes to read is unspecified.
if n is None or n == -1:
self._reset_read_buf()
+ if hasattr(self.raw, 'readall'):
+ chunk = self.raw.readall()
+ if chunk is None:
+ return buf[pos:] or None
+ else:
+ return buf[pos:] + chunk
chunks = [buf[pos:]] # Strip the consumed bytes.
current_size = 0
while True:
diff --git a/Misc/NEWS b/Misc/NEWS
index d1db0ab..b7f3907 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -161,6 +161,8 @@ Core and Builtins
Library
-------
+- Issue #12175: BufferedReader.read(-1) now calls raw.readall() if available.
+
- Issue #12175: FileIO.readall() now only reads the file position and size
once.
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index 44bdac6..6f5bd48 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -36,6 +36,7 @@ PyObject *_PyIO_str_nl;
PyObject *_PyIO_str_read;
PyObject *_PyIO_str_read1;
PyObject *_PyIO_str_readable;
+PyObject *_PyIO_str_readall;
PyObject *_PyIO_str_readinto;
PyObject *_PyIO_str_readline;
PyObject *_PyIO_str_reset;
@@ -767,6 +768,8 @@ PyInit__io(void)
goto fail;
if (!(_PyIO_str_readable = PyUnicode_InternFromString("readable")))
goto fail;
+ if (!(_PyIO_str_readall = PyUnicode_InternFromString("readall")))
+ goto fail;
if (!(_PyIO_str_readinto = PyUnicode_InternFromString("readinto")))
goto fail;
if (!(_PyIO_str_readline = PyUnicode_InternFromString("readline")))
diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h
index 925e4f2..9174bdd 100644
--- a/Modules/_io/_iomodule.h
+++ b/Modules/_io/_iomodule.h
@@ -155,6 +155,7 @@ extern PyObject *_PyIO_str_nl;
extern PyObject *_PyIO_str_read;
extern PyObject *_PyIO_str_read1;
extern PyObject *_PyIO_str_readable;
+extern PyObject *_PyIO_str_readall;
extern PyObject *_PyIO_str_readinto;
extern PyObject *_PyIO_str_readline;
extern PyObject *_PyIO_str_reset;
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 3b8b7e9..63ae1cb 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1407,32 +1407,57 @@ static PyObject *
_bufferedreader_read_all(buffered *self)
{
Py_ssize_t current_size;
- PyObject *res, *data = NULL;
- PyObject *chunks = PyList_New(0);
-
- if (chunks == NULL)
- return NULL;
+ PyObject *res, *data = NULL, *chunk, *chunks;
/* First copy what we have in the current buffer. */
current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
if (current_size) {
data = PyBytes_FromStringAndSize(
self->buffer + self->pos, current_size);
- if (data == NULL) {
- Py_DECREF(chunks);
+ if (data == NULL)
return NULL;
- }
}
_bufferedreader_reset_buf(self);
/* We're going past the buffer's bounds, flush it */
if (self->writable) {
res = _bufferedwriter_flush_unlocked(self, 1);
- if (res == NULL) {
- Py_DECREF(chunks);
+ if (res == NULL)
return NULL;
- }
Py_CLEAR(res);
}
+
+ if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) {
+ chunk = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL);
+ if (chunk == NULL)
+ return NULL;
+ if (chunk != Py_None && !PyBytes_Check(chunk)) {
+ Py_XDECREF(data);
+ Py_DECREF(chunk);
+ PyErr_SetString(PyExc_TypeError, "readall() should return bytes");
+ return NULL;
+ }
+ if (chunk == Py_None) {
+ if (current_size == 0)
+ return chunk;
+ else {
+ Py_DECREF(chunk);
+ return data;
+ }
+ }
+ else if (current_size) {
+ PyBytes_Concat(&data, chunk);
+ Py_DECREF(chunk);
+ if (data == NULL)
+ return NULL;
+ return data;
+ } else
+ return chunk;
+ }
+
+ chunks = PyList_New(0);
+ if (chunks == NULL)
+ return NULL;
+
while (1) {
if (data) {
if (PyList_Append(chunks, data) < 0) {