Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a flush() on the underlying binary stream.

Patch by akira.
This commit is contained in:
Antoine Pitrou 2014-05-09 00:31:32 +02:00
commit 38ca5a7b6d
4 changed files with 41 additions and 4 deletions

View File

@ -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

View File

@ -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()

View File

@ -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.

View File

@ -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;
}