[issue4428] make io.BufferedWriter observe max_buffer_size limits - Code Review (original) (raw)
OLD
NEW
1 """The io module provides the Python interfaces to stream handling. The
1 """The io module provides the Python interfaces to stream handling. The
2 builtin open function is defined in this module.
2 builtin open function is defined in this module.
3
3
4 At the top of the I/O hierarchy is the abstract base class IOBase. It
4 At the top of the I/O hierarchy is the abstract base class IOBase. It
5 defines the basic interface to a stream. Note, however, that there is no
5 defines the basic interface to a stream. Note, however, that there is no
6 seperation between reading and writing to streams; implementations are
6 seperation between reading and writing to streams; implementations are
7 allowed to throw an IOError if they do not support a given operation.
7 allowed to throw an IOError if they do not support a given operation.
8
8
9 Extending IOBase is RawIOBase which deals simply with the reading and
9 Extending IOBase is RawIOBase which deals simply with the reading and
10 writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide
10 writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide
(...skipping 1029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...
1040 raise TypeError("can't write str to binary stream")
1040 raise TypeError("can't write str to binary stream")
1041 with self._write_lock:
1041 with self._write_lock:
1042 # XXX we can implement some more tricks to try and avoid
1042 # XXX we can implement some more tricks to try and avoid
1043 # partial writes
1043 # partial writes
1044 if len(self._write_buf) > self.buffer_size:
1044 if len(self._write_buf) > self.buffer_size:
1045 # We're full, so let's pre-flush the buffer
1045 # We're full, so let's pre-flush the buffer
1046 try:
1046 try:
1047 self._flush_unlocked()
1047 self._flush_unlocked()
1048 except BlockingIOError as e:
1048 except BlockingIOError as e:
1049 # We can't accept anything else.
1049 # We can't accept anything else.
1050 # XXX Why not just let the exception pass through?
1050 # Reraise this with 0 in the written field as none of the
1051 # data passed to this call has been written.
1051 raise BlockingIOError(e.errno, e.strerror, 0)
1052 raise BlockingIOError(e.errno, e.strerror, 0)
1052 before = len(self._write_buf)
1053 before = len(self._write_buf)
1053 self._write_buf.extend(b)
1054 bytes_to_consume = self.max_buffer_size - before
1054 written = len(self._write_buf) - before
1055 # b is an iterable of ints, it won't always support len().
1056 if hasattr(b, '__len__') and len(b) > bytes_to_consume:
1057 try:
1058 chunk = memoryview(b)[:bytes_to_consume]
1059 except TypeError:
1060 # No buffer API? Make intermediate slice copies instead.
1061 chunk = b[:bytes_to_consume]
1062 # Loop over the data, flushing it to the underlying raw IO
1063 # stream in self.max_buffer_size chunks.
1064 written = 0
1065 self._write_buf.extend(chunk)
1066 while chunk and len(self._write_buf) > self.buffer_size:
1067 try:
1068 self._flush_unlocked()
1069 except BlockingIOError as e:
1070 written += e.characters_written
1071 raise BlockingIOError(e.errno, e.strerror, written)
1072 written += len(chunk)
1073 assert not self._write_buf, "_write_buf should be empty"
1074 if isinstance(chunk, memoryview):
1075 chunk = memoryview(b)[written:
1076 written + self.max_buffer_size]
1077 else:
1078 chunk = b[written:written + self.max_buffer_size]
1079 self._write_buf.extend(chunk)
1080 else:
1081 # This could go beyond self.max_buffer_size as we don't know
1082 # the length of b. The alternative of iterating over it one
1083 # byte at a time in python would be slow.
1084 self._write_buf.extend(b)
1085 written = len(self._write_buf) - before
1055 if len(self._write_buf) > self.buffer_size:
1086 if len(self._write_buf) > self.buffer_size:
1056 try:
1087 try:
1057 self._flush_unlocked()
1088 self._flush_unlocked()
1058 except BlockingIOError as e:
1089 except BlockingIOError as e:
1059 if len(self._write_buf) > self.max_buffer_size:
1090 if len(self._write_buf) > self.max_buffer_size:
1060 # We've hit max_buffer_size. We have to accept a
1091 # We've hit max_buffer_size. We have to accept a
1061 # partial write and cut back our buffer.
1092 # partial write and cut back our buffer.
1062 overage = len(self._write_buf) - self.max_buffer_size
1093 overage = len(self._write_buf) - self.max_buffer_size
1063 self._write_buf = self._write_buf[:self.max_buffer_size]
1094 self._write_buf = self._write_buf[:self.max_buffer_size]
1064 raise BlockingIOError(e.errno, e.strerror, overage)
1095 raise BlockingIOError(e.errno, e.strerror, overage)
(...skipping 1066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...
2131 ("\r", "\n"),
2162 ("\r", "\n"),
2132 "\r\n",
2163 "\r\n",
2133 ("\n", "\r\n"),
2164 ("\n", "\r\n"),
2134 ("\r", "\r\n"),
2165 ("\r", "\r\n"),
2135 ("\r", "\n", "\r\n")
2166 ("\r", "\n", "\r\n")
2136 )[self._seennl]
2167 )[self._seennl]
2137
2168
2138
2169
2139 except ImportError:
2170 except ImportError:
2140 StringIO = _StringIO
2171 StringIO = _StringIO
OLD
NEW