diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index fff7a7a03eb81d..c9822b96a14a2f 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -116,6 +116,7 @@ The module defines the following user-callable items: .. versionchanged:: 3.8 Added *errors* parameter. + Implemented :class:`io.IOBase` inteface. .. function:: TemporaryDirectory(suffix=None, prefix=None, dir=None) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 45709cb06cf4e6..eeda0d5609fc99 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -620,7 +620,7 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None, _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. @@ -679,6 +679,9 @@ def __exit__(self, exc, value, tb): def __iter__(self): return self._file.__iter__() + def __del__(self): + return self._file.__del__() + def close(self): self._file.close() @@ -725,6 +728,12 @@ def newlines(self): def read(self, *args): return self._file.read(*args) + def readable(self): + return self._file.readable() + + def readinto(self, b): + return self._file.readinto(b) + def readline(self, *args): return self._file.readline(*args) @@ -732,7 +741,10 @@ def readlines(self, *args): return self._file.readlines(*args) def seek(self, *args): - self._file.seek(*args) + return self._file.seek(*args) + + def seekable(self): + return self._file.seekable() @property def softspace(self): @@ -743,11 +755,11 @@ def tell(self): 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 write(self, s): file = self._file @@ -755,6 +767,9 @@ def write(self, s): self._check(file) return rv + def writable(self): + return self._file.writable() + def writelines(self, iterable): file = self._file rv = file.writelines(iterable) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index f995f6c9bfaf00..8baedabe896f40 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -985,6 +985,22 @@ def test_basic(self): f = self.do_create(max_size=100, pre="a", suf=".txt") self.assertFalse(f._rolled) + def test_is_iobase(self): + # SpooledTemporaryFile should implement io.IOBase + self.assertIsInstance(self.do_create(), io.IOBase) + + def test_iobase_interface(self): + # SpooledTemporaryFile should implement the io.IOBase interface. + # IOBase does not declare read(), readinto(), or write(), but + # they should be considered part of the interface. + iobase_abstract = {'read', 'readinto', 'write'} + spooledtempfile_abstract = set(dir(tempfile.SpooledTemporaryFile)) + missing_attributes = iobase_abstract - spooledtempfile_abstract + self.assertFalse( + missing_attributes, + 'io.IOBase attributes missing from SpooledTemporaryFile' + ) + def test_del_on_close(self): # A SpooledTemporaryFile is deleted when closed dir = tempfile.mkdtemp() @@ -1000,6 +1016,21 @@ def test_del_on_close(self): finally: os.rmdir(dir) + def test_del_rolled_file(self): + # The rolled file should be deleted when the + # SpooledTemporaryFile object is deleted. This should raise a + # ResourceWarning since the file was not explicitly closed. + f = self.do_create(max_size=2) + f.write(b'foo') + filename = f.name + self.assertTrue(os.path.exists(filename)) + with self.assertWarns(ResourceWarning): + f.__del__() + self.assertFalse( + os.path.exists(filename), + "Rolled SpooledTemporaryFile not deleted after __del__" + ) + def test_rewrite_small(self): # A SpooledTemporaryFile can be written to multiple within the max_size f = self.do_create(max_size=30) diff --git a/Misc/NEWS.d/next/Library/2017-08-30-23-14-17.bpo-26175.GOaj9y.rst b/Misc/NEWS.d/next/Library/2017-08-30-23-14-17.bpo-26175.GOaj9y.rst new file mode 100644 index 00000000000000..066ffac870da08 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-08-30-23-14-17.bpo-26175.GOaj9y.rst @@ -0,0 +1,2 @@ +Fully implement io.IOBase interface for tempfile.SpooledTemporaryFile. +Patch by Gary Fernie.