# HG changeset patch # User Antoine Pitrou # Date 1230657284 -3600 diff -r 2d3038da3cb8 -r a6ffec431855 Lib/io.py --- a/Lib/io.py +++ b/Lib/io.py @@ -1055,8 +1055,9 @@ class BufferedWriter(_BufferedIOMixin): # We've hit max_buffer_size. We have to accept a # partial write and cut back our buffer. overage = len(self._write_buf) - self.max_buffer_size + written -= overage self._write_buf = self._write_buf[:self.max_buffer_size] - raise BlockingIOError(e.errno, e.strerror, overage) + raise BlockingIOError(e.errno, e.strerror, written) return written def truncate(self, pos=None): diff -r 2d3038da3cb8 -r a6ffec431855 Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -63,20 +63,36 @@ class MockFileIO(io.BytesIO): class MockNonBlockWriterIO(io.RawIOBase): - def __init__(self, blocking_script): - self._blocking_script = list(blocking_script) + def __init__(self): self._write_stack = [] + self._blocker_char = None + + def pop_written(self): + s = b"".join(self._write_stack) + self._write_stack[:] = [] + return s + + def block_on(self, char): + """Block when a given char is encountered.""" + self._blocker_char = char + + def writable(self): + return True def write(self, b): - self._write_stack.append(b[:]) - n = self._blocking_script.pop(0) - if (n < 0): - raise io.BlockingIOError(0, "test blocking", -n) - else: - return n - - def writable(self): - return True + b = bytes(b) + n = -1 + if self._blocker_char: + try: + n = b.index(self._blocker_char) + except ValueError: + pass + else: + self._blocker_char = None + self._write_stack.append(b[:n]) + raise io.BlockingIOError(0, "test blocking", n) + self._write_stack.append(b) + return len(b) class IOTest(unittest.TestCase): @@ -480,24 +496,31 @@ class BufferedWriterTest(unittest.TestCa self.assertEquals(b"abcdefghijkl", writer._write_stack[0]) def testWriteNonBlocking(self): - raw = MockNonBlockWriterIO((9, 2, 22, -6, 10, 12, 12)) - bufio = io.BufferedWriter(raw, 8, 16) + raw = MockNonBlockWriterIO() + bufio = io.BufferedWriter(raw, 8, 8) - bufio.write(b"asdf") - bufio.write(b"asdfa") - self.assertEquals(b"asdfasdfa", raw._write_stack[0]) - - bufio.write(b"asdfasdfasdf") - self.assertEquals(b"asdfasdfasdf", raw._write_stack[1]) - bufio.write(b"asdfasdfasdf") - self.assertEquals(b"dfasdfasdf", raw._write_stack[2]) - self.assertEquals(b"asdfasdfasdf", raw._write_stack[3]) - - bufio.write(b"asdfasdfasdf") - - # XXX I don't like this test. It relies too heavily on how the - # algorithm actually works, which we might change. Refactor - # later. + self.assertEquals(bufio.write(b"abcd"), 4) + self.assertEquals(bufio.write(b"efghi"), 5) + # 1 byte will be written, the rest will be buffered + raw.block_on(b"k") + self.assertEquals(bufio.write(b"jklmn"), 5) + + # 8 bytes will be written, 8 will be buffered and the rest will be lost + raw.block_on(b"0") + try: + bufio.write(b"opqrwxyz0123456789") + except io.BlockingIOError as e: + written = e.characters_written + else: + self.fail("BlockingIOError should have been raised") + self.assertEquals(written, 16) + self.assertEquals(raw.pop_written(), + b"abcdefghijklmnopqrwxyz") + + self.assertEquals(bufio.write(b"ABCDEFGHI"), 9) + s = raw.pop_written() + # Previously buffered bytes were flushed + self.assertTrue(s.startswith(b"01234567A"), s) def testFileno(self): rawio = MockRawIO((b"abc", b"d", b"efg"))