Index: Lib/io.py =================================================================== --- Lib/io.py (revision 59809) +++ Lib/io.py (working copy) @@ -394,6 +394,7 @@ def readline(self, limit: int = -1) -> bytes: """For backwards compatibility, a (slowish) readline().""" + self._checkClosed() if hasattr(self, "peek"): def nreadahead(): readahead = self.peek(1, unsafe=True) @@ -429,7 +430,7 @@ return line def readlines(self, hint=None): - if hint is None: + if hint is None or hint <= 0: return list(self) n = 0 lines = [] @@ -626,6 +627,8 @@ if pos is None: pos = self.tell() + # XXX: Should seek() be used, instead of passing the position + # XXX directly to truncate? return self.raw.truncate(pos) ### Flush and close ### @@ -665,7 +668,7 @@ return self.raw.isatty() -class BytesIO(BufferedIOBase): +class _BytesIO(BufferedIOBase): """Buffered I/O implementation using an in-memory bytes buffer.""" @@ -679,13 +682,19 @@ self._pos = 0 def getvalue(self): + if self.closed: + raise ValueError("getvalue of closed file") return bytes(self._buffer) def read(self, n=None): + if self.closed: + raise ValueError("read from closed file") if n is None: n = -1 if n < 0: n = len(self._buffer) + if len(self._buffer) <= self._pos: + return self._buffer[:0] newpos = min(len(self._buffer), self._pos + n) b = self._buffer[self._pos : newpos] self._pos = newpos @@ -700,6 +709,8 @@ if isinstance(b, str): raise TypeError("can't write str to binary stream") n = len(b) + if n == 0: + return 0 newpos = self._pos + n if newpos> len(self._buffer): # Inserts null bytes between the current end of the file @@ -711,28 +722,38 @@ return n def seek(self, pos, whence=0): + if self.closed: + raise ValueError("seek on closed file") try: pos = pos.__index__() except AttributeError as err: raise TypeError("an integer is required") from err if whence == 0: self._pos = max(0, pos) + if pos < 0: + raise ValueError("Negative seek position %r" % (pos,)) elif whence == 1: self._pos = max(0, self._pos + pos) elif whence == 2: self._pos = max(0, len(self._buffer) + pos) else: - raise IOError("invalid whence value") + raise ValueError("invalid whence value") return self._pos def tell(self): + if self.closed: + raise ValueError("tell on closed file") return self._pos def truncate(self, pos=None): + if self.closed: + raise ValueError("truncate on closed file") if pos is None: pos = self._pos + elif pos < 0: + raise ValueError("Negative truncate position %r" % (pos,)) del self._buffer[pos:] - return pos + return self.seek(pos) def readable(self): return True @@ -743,7 +764,17 @@ def seekable(self): return True +# Use the faster implementation of BytesIO if available +try: + from _bytesio import _BytesIO + + class BytesIO(_BytesIO, BufferedIOBase): + __doc__ = _BytesIO.__doc__ +except ImportError: + BytesIO = _BytesIO + + class BufferedReader(_BufferedIOMixin): """Buffer for a readable sequential RawIO object.""" @@ -871,6 +902,12 @@ raise BlockingIOError(e.errno, e.strerror, overage) return written + def truncate(self, pos=None): + self.flush() + if pos is None: + pos = self.raw.tell() + return self.raw.truncate(pos) + def flush(self): if self.closed: raise ValueError("flush of closed file") @@ -980,6 +1017,13 @@ else: return self.raw.tell() - len(self._read_buf) + def truncate(self, pos=None): + if pos is None: + pos = self.tell() + # Use seek to flush the read buffer. + self.seek(pos) + BufferedWriter.truncate(self) + def read(self, n=None): if n is None: n = -1 @@ -1026,14 +1070,6 @@ """write(s: str) -> int. Write string s to stream.""" self._unsupported("write") - def truncate(self, pos: int = None) -> int: - """truncate(pos: int = None) -> int. Truncate size to pos.""" - self.flush() - if pos is None: - pos = self.tell() - self.seek(pos) - return self.buffer.truncate() - def readline(self) -> str: """readline() -> str. Read until newline or EOF. @@ -1206,9 +1242,15 @@ # were rendered by the decoder after feeding it those bytes. We # use this to reconstruct intermediate decoder states in tell(). - def _seekable(self): + def seekable(self): return self._seekable + def readable(self): + return self.buffer.readable() + + def writable(self): + return self.buffer.writable() + def flush(self): self.buffer.flush() self._telling = self._seekable @@ -1323,7 +1365,17 @@ finally: decoder.setstate(saved_state) + def truncate(self, pos: int = None) -> int: + """truncate(pos: int = None) -> int. Truncate size to pos.""" + self.flush() + if pos is None: + pos = self.tell() + self.seek(pos) + return self.buffer.truncate() + def seek(self, pos, whence=0): + if self.closed: + raise ValueError("tell on closed file") if not self._seekable: raise IOError("Underlying stream is not seekable") if whence == 1: @@ -1393,6 +1445,8 @@ return line def readline(self, limit=None): + if self.closed: + raise ValueError("read from closed file") if limit is None: limit = -1 if limit>= 0:

AltStyle によって変換されたページ (->オリジナル) /