mirror of https://github.com/python/cpython.git
gh-109523: Raise a BlockingIOError if reading text from a non-blocking stream cannot immediately return bytes. (GH-122933)
This commit is contained in:
parent
930ba0ce60
commit
31f16e427b
|
@ -64,6 +64,12 @@ In-memory text streams are also available as :class:`StringIO` objects::
|
||||||
|
|
||||||
f = io.StringIO("some initial text data")
|
f = io.StringIO("some initial text data")
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When working with a non-blocking stream, be aware that read operations on text I/O objects
|
||||||
|
might raise a :exc:`BlockingIOError` if the stream cannot perform the operation
|
||||||
|
immediately.
|
||||||
|
|
||||||
The text stream API is described in detail in the documentation of
|
The text stream API is described in detail in the documentation of
|
||||||
:class:`TextIOBase`.
|
:class:`TextIOBase`.
|
||||||
|
|
||||||
|
@ -770,6 +776,11 @@ than raw I/O does.
|
||||||
Read and return *size* bytes, or if *size* is not given or negative, until
|
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.
|
EOF or if the read call would block in non-blocking mode.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
|
||||||
|
may be raised if a read operation cannot be completed immediately.
|
||||||
|
|
||||||
.. method:: read1(size=-1, /)
|
.. method:: read1(size=-1, /)
|
||||||
|
|
||||||
Read and return up to *size* bytes with only one call on the raw stream.
|
Read and return up to *size* bytes with only one call on the raw stream.
|
||||||
|
@ -779,6 +790,10 @@ than raw I/O does.
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
The *size* argument is now optional.
|
The *size* argument is now optional.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
|
||||||
|
may be raised if a read operation cannot be completed immediately.
|
||||||
|
|
||||||
.. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
|
.. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
|
||||||
|
|
||||||
|
@ -1007,6 +1022,11 @@ Text I/O
|
||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.10
|
||||||
The *encoding* argument now supports the ``"locale"`` dummy encoding name.
|
The *encoding* argument now supports the ``"locale"`` dummy encoding name.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
|
||||||
|
may be raised if a read operation cannot be completed immediately.
|
||||||
|
|
||||||
:class:`TextIOWrapper` provides these data attributes and methods in
|
:class:`TextIOWrapper` provides these data attributes and methods in
|
||||||
addition to those from :class:`TextIOBase` and :class:`IOBase`:
|
addition to those from :class:`TextIOBase` and :class:`IOBase`:
|
||||||
|
|
||||||
|
|
|
@ -404,6 +404,15 @@ inspect
|
||||||
(Contributed by Zhikang Yan in :gh:`125634`.)
|
(Contributed by Zhikang Yan in :gh:`125634`.)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
io
|
||||||
|
--
|
||||||
|
|
||||||
|
* Reading text from a non-blocking stream with ``read`` may now raise a
|
||||||
|
:exc:`BlockingIOError` if the operation cannot immediately return bytes.
|
||||||
|
(Contributed by Giovanni Siragusa in :gh:`109523`.)
|
||||||
|
|
||||||
|
|
||||||
json
|
json
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
@ -2545,9 +2545,12 @@ def read(self, size=None):
|
||||||
size = size_index()
|
size = size_index()
|
||||||
decoder = self._decoder or self._get_decoder()
|
decoder = self._decoder or self._get_decoder()
|
||||||
if size < 0:
|
if size < 0:
|
||||||
|
chunk = self.buffer.read()
|
||||||
|
if chunk is None:
|
||||||
|
raise BlockingIOError("Read returned None.")
|
||||||
# Read everything.
|
# Read everything.
|
||||||
result = (self._get_decoded_chars() +
|
result = (self._get_decoded_chars() +
|
||||||
decoder.decode(self.buffer.read(), final=True))
|
decoder.decode(chunk, final=True))
|
||||||
if self._snapshot is not None:
|
if self._snapshot is not None:
|
||||||
self._set_decoded_chars('')
|
self._set_decoded_chars('')
|
||||||
self._snapshot = None
|
self._snapshot = None
|
||||||
|
|
|
@ -3932,6 +3932,22 @@ def test_issue35928(self):
|
||||||
f.write(res)
|
f.write(res)
|
||||||
self.assertEqual(res + f.readline(), 'foo\nbar\n')
|
self.assertEqual(res + f.readline(), 'foo\nbar\n')
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
|
||||||
|
def test_read_non_blocking(self):
|
||||||
|
import os
|
||||||
|
r, w = os.pipe()
|
||||||
|
try:
|
||||||
|
os.set_blocking(r, False)
|
||||||
|
with self.io.open(r, 'rt') as textfile:
|
||||||
|
r = None
|
||||||
|
# Nothing has been written so a non-blocking read raises a BlockingIOError exception.
|
||||||
|
with self.assertRaises(BlockingIOError):
|
||||||
|
textfile.read()
|
||||||
|
finally:
|
||||||
|
if r is not None:
|
||||||
|
os.close(r)
|
||||||
|
os.close(w)
|
||||||
|
|
||||||
|
|
||||||
class MemviewBytesIO(io.BytesIO):
|
class MemviewBytesIO(io.BytesIO):
|
||||||
'''A BytesIO object whose read method returns memoryviews
|
'''A BytesIO object whose read method returns memoryviews
|
||||||
|
|
|
@ -1736,6 +1736,7 @@ Ng Pheng Siong
|
||||||
Yann Sionneau
|
Yann Sionneau
|
||||||
George Sipe
|
George Sipe
|
||||||
J. Sipprell
|
J. Sipprell
|
||||||
|
Giovanni Siragusa
|
||||||
Ngalim Siregar
|
Ngalim Siregar
|
||||||
Kragen Sitaker
|
Kragen Sitaker
|
||||||
Kaartic Sivaraam
|
Kaartic Sivaraam
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Reading text from a non-blocking stream with ``read`` may now raise a :exc:`BlockingIOError` if the operation cannot immediately return bytes.
|
|
@ -1992,6 +1992,12 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
|
||||||
if (bytes == NULL)
|
if (bytes == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (bytes == Py_None){
|
||||||
|
Py_DECREF(bytes);
|
||||||
|
PyErr_SetString(PyExc_BlockingIOError, "Read returned None.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
_PyIO_State *state = self->state;
|
_PyIO_State *state = self->state;
|
||||||
if (Py_IS_TYPE(self->decoder, state->PyIncrementalNewlineDecoder_Type))
|
if (Py_IS_TYPE(self->decoder, state->PyIncrementalNewlineDecoder_Type))
|
||||||
decoded = _PyIncrementalNewlineDecoder_decode(self->decoder,
|
decoded = _PyIncrementalNewlineDecoder_decode(self->decoder,
|
||||||
|
|
Loading…
Reference in New Issue