GeezerVison is showing github.com — bpo-26175: Implement `io.IOBase` interface for `SpooledTemporaryFile` by pR0Ps · Pull Request #29560 · python/cpython
bpo-26175: Implement io.IOBase interface for SpooledTemporaryFile
#29560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement . We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Uh oh!
There was an error while loading. Please reload this page.
Show file tree
Hide file tree
Changes from all commits
Commits
File filter
Filter by extension
.py
(2)
.rst
(2)
No extension
(1)
All 3 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Hide whitespace
Diff view
Hide whitespace
There are no files selected for viewing
Original file line number
Diff line number
Diff line change
Expand Up
@@ -123,6 +123,11 @@ The module defines the following user-callable items:
.. versionchanged:: 3.8
Added *errors* parameter.
.. versionchanged:: 3.11
Fully implements the :class:`io.BufferedIOBase` and
:class:`io.TextIOBase` abstract base classes (depending on whether binary
or text *mode* was specified).
.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False)
Expand Down
Original file line number
Diff line number
Diff line change
Expand Up
@@ -639,7 +639,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.
Expand Down
Expand Up
@@ -704,6 +704,16 @@ def __exit__(self, exc, value, tb):
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()
Expand Down
Expand Up
@@ -747,15 +757,30 @@ def name(self):
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)
Expand All
@@ -764,11 +789,14 @@ 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 writable(self):
return self._file.writable()
def write(self, s):
file = self._file
Expand All
@@ -782,6 +810,9 @@ def writelines(self, iterable):
self._check(file)
return rv
def detach(self):
return self._file.detach()
class TemporaryDirectory:
"""Create and return a temporary directory. This has the same
Expand Down
Original file line number
Diff line number
Diff line change
Expand Up
@@ -1061,6 +1061,30 @@ 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.
# Ensure it has all the required methods and properties.
iobase_attrs = {
# From IOBase
'fileno', 'seek', 'truncate', 'close', 'closed', '__enter__',
'__exit__', 'flush', 'isatty', '__iter__', '__next__', 'readable',
'readline', 'readlines', 'seekable', 'tell', 'writable',
'writelines',
# From BufferedIOBase (binary mode) and TextIOBase (text mode)
'detach', 'read', 'read1', 'write', 'readinto', 'readinto1',
'encoding', 'errors', 'newlines',
}
spooledtempfile_attrs = set(dir(tempfile.SpooledTemporaryFile))
missing_attrs = iobase_attrs - spooledtempfile_attrs
self.assertFalse(
missing_attrs,
'SpooledTemporaryFile missing attributes from IOBase/BufferedIOBase/TextIOBase'
)
def test_del_on_close(self):
# A SpooledTemporaryFile is deleted when closed
dir = tempfile.mkdtemp()
Expand All
@@ -1076,6 +1100,30 @@ def test_del_on_close(self):
finally:
os.rmdir(dir)
def test_del_unrolled_file(self):
# The unrolled SpooledTemporaryFile should raise a ResourceWarning
# when deleted since the file was not explicitly closed.
f = self.do_create(max_size=10)
f.write(b'foo')
self.assertEqual(f.name, None) # Unrolled so no filename/fd
with self.assertWarns(ResourceWarning):
f.__del__()
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')
name = f.name # This is a fd on posix+cygwin, a filename everywhere else
self.assertTrue(os.path.exists(name))
with self.assertWarns(ResourceWarning):
f.__del__()
self.assertFalse(
os.path.exists(name),
"Rolled SpooledTemporaryFile (name=%s) exists after delete" % name
)
def test_rewrite_small(self):
# A SpooledTemporaryFile can be written to multiple within the max_size
f = self.do_create(max_size=30)
Expand Down
1 change: 1 addition & 0 deletions
1
Misc/ACKS
Original file line number
Diff line number
Diff line change
Expand Up
@@ -1172,6 +1172,7 @@ Dimitri Merejkowsky
Brian Merrell
Bruce Merry
Alexis Métaireau
Carey Metcalfe
Luke Mewburn
Carl Meyer
Kyle Meyer
Expand Down
Original file line number
Diff line number
Diff line change
@@ -0,0 +1,4 @@
Fully implement the :class:`io.BufferedIOBase` or :class:`io.TextIOBase`
interface for :class:`tempfile.SpooledTemporaryFile` objects. This lets them
work correctly with higher-level layers (like compression modules). Patch by
Carey Metcalfe.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.