8000 gh-109523: Raise a BlockingIOError if reading text from a non-blockin… · python/cpython@31f16e4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 31f16e4

Browse files
authored
gh-109523: Raise a BlockingIOError if reading text from a non-blocking stream cannot immediately return bytes. (GH-122933)
1 parent 930ba0c commit 31f16e4

File tree

7 files changed

+57
-1
lines changed

7 files changed

+57
-1
lines changed

Doc/library/io.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ In-memory text streams are also available as :class:`StringIO` objects::
6464

6565
f = io.StringIO("some initial text data")
6666

67+
.. note::
68+
69+
When working with a non-blocking stream, be aware that read operations on text I/O objects
70+
might raise a :exc:`BlockingIOError` if the stream cannot perform the operation
71+
immediately.
72+
6773
The text stream API is described in detail in the documentation of
6874
:class:`TextIOBase`.
6975

@@ -770,6 +776,11 @@ than raw I/O does.
770776
Read and return *size* bytes, or if *size* is not given or negative, until
771777
EOF or if the read call would block in non-blocking mode.
772778

779+
.. note::
780+
781+
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
782+
may be raised if a read operation cannot be completed immediately.
783+
773784
.. method:: read1(size=-1, /)
774785

775 8000 786
Read and return up to *size* bytes with only one call on the raw stream.
@@ -779,6 +790,10 @@ than raw I/O does.
779790
.. versionchanged:: 3.7
780791
The *size* argument is now optional.
781792

793+
.. note::
794+
795+
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
796+
may be raised if a read operation cannot be completed immediately.
782797

783798
.. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
784799

@@ -1007,6 +1022,11 @@ Text I/O
10071022
.. versionchanged:: 3.10
10081023
The *encoding* argument now supports the ``"locale"`` dummy encoding name.
10091024

1025+
.. note::
1026+
1027+
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
1028+
may be raised if a read operation cannot be completed immediately.
1029+
10101030
:class:`TextIOWrapper` provides these data attributes and methods in
10111031
addition to those from :class:`TextIOBase` and :class:`IOBase`:
< 8000 /td>
10121032

Doc/whatsnew/3.14.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,15 @@ inspect
404404
(Contributed by Zhikang Yan in :gh:`125634`.)
405405

406406

407+
408+
io
409+
--
410+
411+
* Reading text from a non-blocking stream with ``read`` may now raise a
412+
:exc:`BlockingIOError` if the operation cannot immediately return bytes.
413+
(Contributed by Giovanni Siragusa in :gh:`109523`.)
414+
415+
407416
json
408417
----
409418

Lib/_pyio.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2545,9 +2545,12 @@ def read(self, size=None):
25452545
size = size_index()
25462546
decoder = self._decoder or self._get_decoder()
25472547
if size < 0:
2548+
chunk = self.buffer.read()
2549+
if chunk is None:
2550+
raise BlockingIOError("Read returned None.")
25482551
# Read everything.
25492552
result = (self._get_decoded_chars() +
2550-
decoder.decode(self.buffer.read(), final=True))
2553+
decoder.decode(chunk, final=True))
25512554
if self._snapshot is not None:
25522555
self._set_decoded_chars('')
25532556
self._snapshot = None

Lib/test/test_io.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3932,6 +3932,22 @@ def test_issue35928(self):
39323932
f.write(res)
39333933
self.assertEqual(res + f.readline(), 'foo\nbar\n')
39343934

3935+
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
3936+
def test_read_non_blocking(self):
3937+
import os
3938+
r, w = os.pipe()
3939+
try:
3940+
os.set_blocking(r, False)
3941+
with self.io.open(r, 'rt') as textfile:
3942+
r = None
3943+
# Nothing has been written so a non-blocking read raises a BlockingIOError exception.
3944+
with self.assertRaises(BlockingIOError):
3945+
textfile.read()
3946+
finally:
3947+
if r is not None:
3948+
os.close(r)
3949+
os.close(w)
3950+
39353951

39363952
class MemviewBytesIO(io.BytesIO):
39373953
'''A BytesIO object whose read method returns memoryviews

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,7 @@ Ng Pheng Siong
17361736
Yann Sionneau
17371737
George Sipe
17381738
J. Sipprell
1739+
Giovanni Siragusa
17391740
Ngalim Siregar
17401741
Kragen Sitaker
17411742
Kaartic Sivaraam
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reading text from a non-blocking stream with ``read`` may now raise a :exc:`BlockingIOError` if the operation cannot immediately return bytes.

Modules/_io/textio.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,12 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
19921992
if (bytes == NULL)
19931993
goto fail;
19941994

1995+
if (bytes == Py_None){
1996+
Py_DECREF(bytes);
1997+
PyErr_SetString(PyExc_BlockingIOError, "Read returned None.");
1998+
return NULL;
1999+
}
2000+
19952001
_PyIO_State *state = self->state;
19962002
if (Py_IS_TYPE(self->decoder, state->PyIncrementalNewlineDecoder_Type))
19972003
decoded = _PyIncrementalNewlineDecoder_decode(self->decoder,

0 commit comments

Comments
 (0)
0