diff options
-rw-r--r-- | Lib/test/test_io.py | 32 | ||||
-rw-r--r-- | Lib/test/test_subprocess.py | 1 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_io/textio.c | 9 |
4 files changed, 41 insertions, 4 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 8e702db..347832d 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2615,6 +2615,38 @@ class TextIOWrapperTest(unittest.TestCase): txt.write('5') self.assertEqual(b''.join(raw._write_stack), b'123\n45') + def test_bufio_write_through(self): + # Issue #21396: write_through=True doesn't force a flush() + # on the underlying binary buffered object. + flush_called, write_called = [], [] + class BufferedWriter(self.BufferedWriter): + def flush(self, *args, **kwargs): + flush_called.append(True) + return super().flush(*args, **kwargs) + def write(self, *args, **kwargs): + write_called.append(True) + return super().write(*args, **kwargs) + + rawio = self.BytesIO() + data = b"a" + bufio = BufferedWriter(rawio, len(data)*2) + textio = self.TextIOWrapper(bufio, encoding='ascii', + write_through=True) + # write to the buffered io but don't overflow the buffer + text = data.decode('ascii') + textio.write(text) + + # buffer.flush is not called with write_through=True + self.assertFalse(flush_called) + # buffer.write *is* called with write_through=True + self.assertTrue(write_called) + self.assertEqual(rawio.getvalue(), b"") # no flush + + write_called = [] # reset + textio.write(text * 10) # total content is larger than bufio buffer + self.assertTrue(write_called) + self.assertEqual(rawio.getvalue(), data * 11) # all flushed + def test_read_nonbytes(self): # Issue #17106 # Crash when underlying read() returns non-bytes diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 4c8d493..32ffb5f 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -786,6 +786,7 @@ class ProcessTestCase(BaseTestCase): stdout=subprocess.PIPE, universal_newlines=1) p.stdin.write("line1\n") + p.stdin.flush() self.assertEqual(p.stdout.readline(), "line1\n") p.stdin.write("line3\n") p.stdin.close() @@ -69,6 +69,9 @@ Core and Builtins Library ------- +- Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a + flush() on the underlying binary stream. Patch by akira. + - Issue #18314: Unlink now removes junctions on Windows. Patch by Kim Gräsman - Issue #21088: Bugfix for curses.window.addch() regression in 3.4.0. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index d5c7339..24c7b45 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1297,7 +1297,7 @@ textiowrapper_write(textio *self, PyObject *args) PyObject *b; Py_ssize_t textlen; int haslf = 0; - int needflush = 0; + int needflush = 0, text_needflush = 0; CHECK_INITIALIZED(self); @@ -1331,8 +1331,8 @@ textiowrapper_write(textio *self, PyObject *args) } if (self->write_through) - needflush = 1; - else if (self->line_buffering && + text_needflush = 1; + if (self->line_buffering && (haslf || PyUnicode_FindChar(text, '\r', 0, PyUnicode_GET_LENGTH(text), 1) != -1)) needflush = 1; @@ -1363,7 +1363,8 @@ textiowrapper_write(textio *self, PyObject *args) } self->pending_bytes_count += PyBytes_GET_SIZE(b); Py_DECREF(b); - if (self->pending_bytes_count > self->chunk_size || needflush) { + if (self->pending_bytes_count > self->chunk_size || needflush || + text_needflush) { if (_textiowrapper_writeflush(self) < 0) return NULL; } |