diff --git a/Lib/_pyio.py b/Lib/_pyio.py index df2c29bfa9caee..379de83ae5482f 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -2512,8 +2512,11 @@ def read(self, size=None): decoder = self._decoder or self._get_decoder() if size < 0: # Read everything. + if (input_chunk := self.buffer.read()) is None and isinstance(self.buffer, BufferedReader): + raise BlockingIOError( + "BufferedReader.read() return None, stream opened in non-blocking mode and not data is available") result = (self._get_decoded_chars() + - decoder.decode(self.buffer.read(), final=True)) + decoder.decode(input_chunk, final=True)) if self._snapshot is not None: self._set_decoded_chars('') self._snapshot = None diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 9e28b936e00bd5..a0088c2a52ebc9 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3995,6 +3995,14 @@ class PyTextIOWrapperTest(TextIOWrapperTest): io = pyio shutdown_error = "LookupError: unknown encoding: ascii" + def test_read_non_blocking_stream(self): + # Issue #57531 + # io module doesn't support non-blocking files + r = self.MockRawIO((None,)) + b = self.BufferedReader(r, 1000) + t = self.TextIOWrapper(b, encoding="utf-8") + self.assertRaises(BlockingIOError, t.read) + class IncrementalNewlineDecoderTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-08-40-32.gh-issue-57531.425aq5.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-08-40-32.gh-issue-57531.425aq5.rst new file mode 100644 index 00000000000000..bb336317272396 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-08-40-32.gh-issue-57531.425aq5.rst @@ -0,0 +1 @@ +Add BufferedReader.read() return value check for non-blocking stream mode, raise BlockingIOError instead of TypeError with more context for the caller.