Kaydet (Commit) c644e7c3 authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a flush()…

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

Patch by akira.
üst a83ade1d
...@@ -2615,6 +2615,38 @@ class TextIOWrapperTest(unittest.TestCase): ...@@ -2615,6 +2615,38 @@ class TextIOWrapperTest(unittest.TestCase):
txt.write('5') txt.write('5')
self.assertEqual(b''.join(raw._write_stack), b'123\n45') 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): def test_read_nonbytes(self):
# Issue #17106 # Issue #17106
# Crash when underlying read() returns non-bytes # Crash when underlying read() returns non-bytes
......
...@@ -786,6 +786,7 @@ class ProcessTestCase(BaseTestCase): ...@@ -786,6 +786,7 @@ class ProcessTestCase(BaseTestCase):
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
universal_newlines=1) universal_newlines=1)
p.stdin.write("line1\n") p.stdin.write("line1\n")
p.stdin.flush()
self.assertEqual(p.stdout.readline(), "line1\n") self.assertEqual(p.stdout.readline(), "line1\n")
p.stdin.write("line3\n") p.stdin.write("line3\n")
p.stdin.close() p.stdin.close()
......
...@@ -24,6 +24,7 @@ Jim Ahlstrom ...@@ -24,6 +24,7 @@ Jim Ahlstrom
Farhan Ahmad Farhan Ahmad
Matthew Ahrens Matthew Ahrens
Nir Aides Nir Aides
Akira
Yaniv Aknin Yaniv Aknin
Jyrki Alakuijala Jyrki Alakuijala
Steve Alexander Steve Alexander
......
...@@ -7,6 +7,12 @@ What's New in Python 3.4.1? ...@@ -7,6 +7,12 @@ What's New in Python 3.4.1?
Release date: TBA 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 Tests
----- -----
......
...@@ -1297,7 +1297,7 @@ textiowrapper_write(textio *self, PyObject *args) ...@@ -1297,7 +1297,7 @@ textiowrapper_write(textio *self, PyObject *args)
PyObject *b; PyObject *b;
Py_ssize_t textlen; Py_ssize_t textlen;
int haslf = 0; int haslf = 0;
int needflush = 0; int needflush = 0, text_needflush = 0;
CHECK_INITIALIZED(self); CHECK_INITIALIZED(self);
...@@ -1331,8 +1331,8 @@ textiowrapper_write(textio *self, PyObject *args) ...@@ -1331,8 +1331,8 @@ textiowrapper_write(textio *self, PyObject *args)
} }
if (self->write_through) if (self->write_through)
needflush = 1; text_needflush = 1;
else if (self->line_buffering && if (self->line_buffering &&
(haslf || (haslf ||
PyUnicode_FindChar(text, '\r', 0, PyUnicode_GET_LENGTH(text), 1) != -1)) PyUnicode_FindChar(text, '\r', 0, PyUnicode_GET_LENGTH(text), 1) != -1))
needflush = 1; needflush = 1;
...@@ -1363,7 +1363,8 @@ textiowrapper_write(textio *self, PyObject *args) ...@@ -1363,7 +1363,8 @@ textiowrapper_write(textio *self, PyObject *args)
} }
self->pending_bytes_count += PyBytes_GET_SIZE(b); self->pending_bytes_count += PyBytes_GET_SIZE(b);
Py_DECREF(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) if (_textiowrapper_writeflush(self) < 0)
return NULL; return NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment