Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

bpo-26175: Fix SpooledTemporaryFile IOBase abstract#3249

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
GFernie wants to merge13 commits intopython:mainfromGFernie:bpo-26175_fix-SpooledTemporaryFile-IOBase
Closed
Show file tree
Hide file tree
Changes from8 commits
Commits
Show all changes
13 commits
Select commitHold shift + click to select a range
83d6152
Fix SpooledTemporaryFile IOBase abstract
GFernieAug 30, 2017
3b69baa
Add news entry for bpo-26175 patch
GFernieAug 30, 2017
753b4fb
Update 2017-08-30-23-14-17.bpo-26175.GOaj9y.rst
merwokSep 20, 2017
a70113e
Make SpooledTemporaryFile subclass IOBase
GFernieSep 30, 2017
fb28362
Refactor tests to more reliably test abstract
GFernieSep 30, 2017
bc9d0a9
Return new absolute position from underlying file on seek
GFernieSep 9, 2018
b588dec
Do nothing on __del__
GFernieSep 9, 2018
ab49dd1
Return new file size from underlying file on truncate
GFernieSep 9, 2018
4251b21
Merge remote-tracking branch 'origin/master' into bpo-26175_fix-Spool…
GFernieOct 30, 2019
19f4c08
Add versionchanged tag
GFernieOct 30, 2019
4519b9c
Use :class: instead of :py:data:
GFernieOct 30, 2019
554aad6
Revert "Do nothing on __del__"
GFernieNov 23, 2019
be094b3
Add test for rolled file finalisation
GFernieNov 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletionsLib/tempfile.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -626,7 +626,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 DownExpand Up@@ -685,6 +685,12 @@ def __exit__(self, exc, value, tb):
def __iter__(self):
return self._file.__iter__()

def __del__(self):
Copy link

@ppperyppperyJun 6, 2018
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This shouldn't be added: deleting the SpooledTemporaryFile will null out the reference to the underline file, and therefor call its __del__

Copy link
Member

@vadmiumvadmiumJun 9, 2018
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think if you inherit the defaultIOBase.__del__ implementation, it will callclose and defeat any ResourceWarning that might otherwise be emitted. Perhaps it is better to make__del__ do nothing,or set it toobject.__del__. [Seems that last option doesn’t exist.]

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I agree: the underlying file should not be explicitly deleted as this is not expected behaviour. I can imagine a situation where someone is deliberately holding a reference to the underlying file and they would not expect/want it to be closed until their own reference has fallen out of scope. I've changed the method to do nothing and added a docstring to reflect this.

Thanks for your feedback

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I agree: the underlying file should not be explicitly deleted as this is not expected behaviour

The doc says: """This function operates exactly as TemporaryFile() does, except [irrelevant differences]."""

And then, about TemporaryFile: """On completion of the context or destruction of the file object the temporary file will be removed from the filesystem."""

So it seems the underlying fileshould be deleted when the file object disappears.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The point is thatIOBase implements a__del__ which has some side-effects. Those side effects are not desirable here. Any underlying buffers being wrapped, e.g. theTemporaryFile or theBytesIO, will be gc'd and handled as they should.

I think this implementation is correct.

"""Do nothing. Underlying file will be deleted as a consequence
of falling out of scope, anyway, if nothing else is otherwise
deliberately referencing it."""
pass

def close(self):
self._file.close()

Expand DownExpand Up@@ -737,14 +743,23 @@ 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)

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):
Expand All@@ -755,18 +770,21 @@ def tell(self):

def truncate(self, size=None):
if size is None:
self._file.truncate()
returnself._file.truncate()
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

this else is not needed, PEP warning, might as well fix

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It's not necessary to remove the else. It does no harm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I never said it was necessary, just bad style as it unnecessarily increased the code depth, take my comment as an FYI

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Just wanted to confirm@merwok - nothing needs to be changed here for approval?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Right, I advise to not change theelse line.

if size > self._max_size:
self.rollover()
self._file.truncate(size)
returnself._file.truncate(size)

def write(self, s):
file = self._file
rv = file.write(s)
self._check(file)
return rv

def writable(self):
return self._file.writable()

def writelines(self, iterable):
file = self._file
rv = file.writelines(iterable)
Expand Down
16 changes: 16 additions & 0 deletionsLib/test/test_tempfile.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -982,6 +982,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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Those tests are not very interesting. It would be better to test the methods operate properly.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Itliterally delegates everything to the underlying file.

The existing tests should cover the behaviors. The new behaviors are intended to flesh out the API so thatSpooledTemporaryFile, and these tests seem to cover that.

# 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()
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Fully implement io.IOBase interface for tempfile.SpooledTemporaryFile.
Patch by Gary Fernie.

[8]ページ先頭

©2009-2025 Movatter.jp