GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

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.

Sign up for GitHub

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

Merged
methane merged 6 commits into python:main from pR0Ps:bpo-26175_fix-SpooledTemporaryFile-IOBase
May 3, 2022

Uh oh!

There was an error while loading. Please reload this page.

Merged

bpo-26175: Implement io.IOBase interface for SpooledTemporaryFile #29560

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
6 commits
Select commit Hold shift + click to select a range
b229469
Implement io.IOBase interface for SpooledTemporaryFile
pR0Ps Nov 14, 2021
753aeb0
Fix calling 'del' in tests
pR0Ps Jan 3, 2022
d93781b
Apply suggestion from @merwok
pR0Ps Feb 23, 2022
145668a
Revert improvement to truncate control flow
pR0Ps Feb 24, 2022
9ebd545
Added name to ACKs and patch notes
pR0Ps Feb 25, 2022
3e3c8f1
Merge branch 'main' into bpo-26175_fix-SpooledTemporaryFile-IOBase
methane May 3, 2022
File filter
Filter by extension

Clear filters
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
Diff view

There are no files selected for viewing

5 changes: 5 additions & 0 deletions 5 Doc/library/tempfile.rst
Show comments
View file
Open in desktop
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
37 changes: 34 additions & 3 deletions 37 Lib/tempfile.py
Show comments
View file
Open in desktop
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
48 changes: 48 additions & 0 deletions 48 Lib/test/test_tempfile.py
Show comments
View file
Open in desktop
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
Show comments
View file
Open in desktop
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
4 changes: 4 additions & 0 deletions 4 Misc/NEWS.d/next/Library/2021-11-14-01-35-04.bpo-26175.LNlOfI.rst
Show comments
View file
Open in desktop
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.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.