aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2014-05-09 00:24:50 +0200
committerAntoine Pitrou <solipsis@pitrou.net>2014-05-09 00:24:50 +0200
commitc644e7c39f7adf0ed783e128b0278665133bf523 (patch)
tree85a2c3c546b5b9f3c189ef45d4c6b5b932af7d60
parent#21300: fix typo (diff)
downloadcpython-c644e7c39f7adf0ed783e128b0278665133bf523.tar.gz
cpython-c644e7c39f7adf0ed783e128b0278665133bf523.tar.bz2
cpython-c644e7c39f7adf0ed783e128b0278665133bf523.zip
Issue #21396: Fix TextIOWrapper(..., write_through=True) to not force a flush() on the underlying binary stream.
Patch by akira.
-rw-r--r--Lib/test/test_io.py32
-rw-r--r--Lib/test/test_subprocess.py1
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS6
-rw-r--r--Modules/_io/textio.c9
5 files changed, 45 insertions, 4 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 267537fdeb7..ef1e05622bb 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 4c8d4937321..32ffb5fa4ba 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()
diff --git a/Misc/ACKS b/Misc/ACKS
index 4068836cf1c..75fb70657bb 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -24,6 +24,7 @@ Jim Ahlstrom
Farhan Ahmad
Matthew Ahrens
Nir Aides
+Akira
Yaniv Aknin
Jyrki Alakuijala
Steve Alexander
diff --git a/Misc/NEWS b/Misc/NEWS
index 96f3cb78775..29634fcf407 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -7,6 +7,12 @@ What's New in Python 3.4.1?
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 --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 5739bc4d01d..ba5789d3c73 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;
}