changeset: 90593:39f2a78f4357 branch: 3.4 parent: 90589:9e55089aa505 user: Antoine Pitrou date: Fri May 09 00:24:50 2014 +0200 files: Lib/test/test_io.py Lib/test/test_subprocess.py Misc/ACKS Misc/NEWS Modules/_io/textio.c description: Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a flush() on the underlying binary stream. Patch by akira. diff -r 9e55089aa505 -r 39f2a78f4357 Lib/test/test_io.py --- a/Lib/test/test_io.py Thu May 08 10:05:47 2014 -0400 +++ b/Lib/test/test_io.py Fri May 09 00:24:50 2014 +0200 @@ -2615,6 +2615,38 @@ 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 -r 9e55089aa505 -r 39f2a78f4357 Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py Thu May 08 10:05:47 2014 -0400 +++ b/Lib/test/test_subprocess.py Fri May 09 00:24:50 2014 +0200 @@ -786,6 +786,7 @@ 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() diff -r 9e55089aa505 -r 39f2a78f4357 Misc/ACKS --- a/Misc/ACKS Thu May 08 10:05:47 2014 -0400 +++ b/Misc/ACKS Fri May 09 00:24:50 2014 +0200 @@ -24,6 +24,7 @@ Farhan Ahmad Matthew Ahrens Nir Aides +Akira Yaniv Aknin Jyrki Alakuijala Steve Alexander diff -r 9e55089aa505 -r 39f2a78f4357 Misc/NEWS --- a/Misc/NEWS Thu May 08 10:05:47 2014 -0400 +++ b/Misc/NEWS Fri May 09 00:24:50 2014 +0200 @@ -7,6 +7,12 @@ Release date: TBA +Library +------- + +- Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a + flush() on the underlying binary stream. Patch by akira. + Tests ----- diff -r 9e55089aa505 -r 39f2a78f4357 Modules/_io/textio.c --- a/Modules/_io/textio.c Thu May 08 10:05:47 2014 -0400 +++ b/Modules/_io/textio.c Fri May 09 00:24:50 2014 +0200 @@ -1297,7 +1297,7 @@ 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 @@ } 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 @@ } 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; }