gh-70363: Implement io.IOBase interface for SpooledTemporaryFile (GH-29560)

Since the underlying file-like objects (either `io.BytesIO`,
or a true file object) all implement the `io.IOBase`
interface, the `SpooledTemporaryFile` should as well.

Additionally, since the underlying file object will either be an
instance of an `io.BufferedIOBase` (for binary mode) or an
`io.TextIOBase` (for text mode), methods for these classes were also
implemented.

In every case, the required methods and properties are simply delegated
to the underlying file object.

Co-authored-by: Gary Fernie <Gary.Fernie@skyscanner.net>
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
This commit is contained in:
Carey Metcalfe 2022-05-03 08:18:18 -04:00 committed by GitHub
parent 52dc9c3066
commit 78e70be331
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 3 deletions

View file

@ -639,7 +639,7 @@ else:
_os.close(fd)
raise
class SpooledTemporaryFile:
class SpooledTemporaryFile(_io.IOBase):
"""Temporary file wrapper, specialized to switch from BytesIO
or StringIO to a real file when it exceeds a certain size or
when a fileno is needed.
@ -704,6 +704,16 @@ class SpooledTemporaryFile:
def __iter__(self):
return self._file.__iter__()
def __del__(self):
if not self.closed:
_warnings.warn(
"Unclosed file {!r}".format(self),
ResourceWarning,
stacklevel=2,
source=self
)
self.close()
def close(self):
self._file.close()
@ -747,15 +757,30 @@ class SpooledTemporaryFile:
def newlines(self):
return self._file.newlines
def readable(self):
return self._file.readable()
def read(self, *args):
return self._file.read(*args)
def read1(self, *args):
return self._file.read1(*args)
def readinto(self, b):
return self._file.readinto(b)
def readinto1(self, b):
return self._file.readinto1(b)
def readline(self, *args):
return self._file.readline(*args)
def readlines(self, *args):
return self._file.readlines(*args)
def seekable(self):
return self._file.seekable()
def seek(self, *args):
return self._file.seek(*args)
@ -764,11 +789,14 @@ class SpooledTemporaryFile:
def truncate(self, size=None):
if size is None:
self._file.truncate()
return self._file.truncate()
else:
if size > self._max_size:
self.rollover()
self._file.truncate(size)
return self._file.truncate(size)
def writable(self):
return self._file.writable()
def write(self, s):
file = self._file
@ -782,6 +810,9 @@ class SpooledTemporaryFile:
self._check(file)
return rv
def detach(self):
return self._file.detach()
class TemporaryDirectory:
"""Create and return a temporary directory. This has the same