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

Commit78e70be

Browse files
pR0PsGFerniemethane
authored
gh-70363: Implementio.IOBase interface forSpooledTemporaryFile (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 aninstance of an `io.BufferedIOBase` (for binary mode) or an`io.TextIOBase` (for text mode), methods for these classes were alsoimplemented.In every case, the required methods and properties are simply delegatedto the underlying file object.Co-authored-by: Gary Fernie <Gary.Fernie@skyscanner.net>Co-authored-by: Inada Naoki <songofacandy@gmail.com>
1 parent52dc9c3 commit78e70be

File tree

5 files changed

+92
-3
lines changed

5 files changed

+92
-3
lines changed

‎Doc/library/tempfile.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ The module defines the following user-callable items:
123123
..versionchanged::3.8
124124
Added *errors* parameter.
125125

126+
..versionchanged::3.11
127+
Fully implements the:class:`io.BufferedIOBase` and
128+
:class:`io.TextIOBase` abstract base classes (depending on whether binary
129+
or text *mode* was specified).
130+
126131

127132
..class::TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False)
128133

‎Lib/tempfile.py‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
639639
_os.close(fd)
640640
raise
641641

642-
classSpooledTemporaryFile:
642+
classSpooledTemporaryFile(_io.IOBase):
643643
"""Temporary file wrapper, specialized to switch from BytesIO
644644
or StringIO to a real file when it exceeds a certain size or
645645
when a fileno is needed.
@@ -704,6 +704,16 @@ def __exit__(self, exc, value, tb):
704704
def__iter__(self):
705705
returnself._file.__iter__()
706706

707+
def__del__(self):
708+
ifnotself.closed:
709+
_warnings.warn(
710+
"Unclosed file {!r}".format(self),
711+
ResourceWarning,
712+
stacklevel=2,
713+
source=self
714+
)
715+
self.close()
716+
707717
defclose(self):
708718
self._file.close()
709719

@@ -747,15 +757,30 @@ def name(self):
747757
defnewlines(self):
748758
returnself._file.newlines
749759

760+
defreadable(self):
761+
returnself._file.readable()
762+
750763
defread(self,*args):
751764
returnself._file.read(*args)
752765

766+
defread1(self,*args):
767+
returnself._file.read1(*args)
768+
769+
defreadinto(self,b):
770+
returnself._file.readinto(b)
771+
772+
defreadinto1(self,b):
773+
returnself._file.readinto1(b)
774+
753775
defreadline(self,*args):
754776
returnself._file.readline(*args)
755777

756778
defreadlines(self,*args):
757779
returnself._file.readlines(*args)
758780

781+
defseekable(self):
782+
returnself._file.seekable()
783+
759784
defseek(self,*args):
760785
returnself._file.seek(*args)
761786

@@ -764,11 +789,14 @@ def tell(self):
764789

765790
deftruncate(self,size=None):
766791
ifsizeisNone:
767-
self._file.truncate()
792+
returnself._file.truncate()
768793
else:
769794
ifsize>self._max_size:
770795
self.rollover()
771-
self._file.truncate(size)
796+
returnself._file.truncate(size)
797+
798+
defwritable(self):
799+
returnself._file.writable()
772800

773801
defwrite(self,s):
774802
file=self._file
@@ -782,6 +810,9 @@ def writelines(self, iterable):
782810
self._check(file)
783811
returnrv
784812

813+
defdetach(self):
814+
returnself._file.detach()
815+
785816

786817
classTemporaryDirectory:
787818
"""Create and return a temporary directory. This has the same

‎Lib/test/test_tempfile.py‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,30 @@ def test_basic(self):
10611061
f=self.do_create(max_size=100,pre="a",suf=".txt")
10621062
self.assertFalse(f._rolled)
10631063

1064+
deftest_is_iobase(self):
1065+
# SpooledTemporaryFile should implement io.IOBase
1066+
self.assertIsInstance(self.do_create(),io.IOBase)
1067+
1068+
deftest_iobase_interface(self):
1069+
# SpooledTemporaryFile should implement the io.IOBase interface.
1070+
# Ensure it has all the required methods and properties.
1071+
iobase_attrs= {
1072+
# From IOBase
1073+
'fileno','seek','truncate','close','closed','__enter__',
1074+
'__exit__','flush','isatty','__iter__','__next__','readable',
1075+
'readline','readlines','seekable','tell','writable',
1076+
'writelines',
1077+
# From BufferedIOBase (binary mode) and TextIOBase (text mode)
1078+
'detach','read','read1','write','readinto','readinto1',
1079+
'encoding','errors','newlines',
1080+
}
1081+
spooledtempfile_attrs=set(dir(tempfile.SpooledTemporaryFile))
1082+
missing_attrs=iobase_attrs-spooledtempfile_attrs
1083+
self.assertFalse(
1084+
missing_attrs,
1085+
'SpooledTemporaryFile missing attributes from IOBase/BufferedIOBase/TextIOBase'
1086+
)
1087+
10641088
deftest_del_on_close(self):
10651089
# A SpooledTemporaryFile is deleted when closed
10661090
dir=tempfile.mkdtemp()
@@ -1076,6 +1100,30 @@ def test_del_on_close(self):
10761100
finally:
10771101
os.rmdir(dir)
10781102

1103+
deftest_del_unrolled_file(self):
1104+
# The unrolled SpooledTemporaryFile should raise a ResourceWarning
1105+
# when deleted since the file was not explicitly closed.
1106+
f=self.do_create(max_size=10)
1107+
f.write(b'foo')
1108+
self.assertEqual(f.name,None)# Unrolled so no filename/fd
1109+
withself.assertWarns(ResourceWarning):
1110+
f.__del__()
1111+
1112+
deftest_del_rolled_file(self):
1113+
# The rolled file should be deleted when the SpooledTemporaryFile
1114+
# object is deleted. This should raise a ResourceWarning since the file
1115+
# was not explicitly closed.
1116+
f=self.do_create(max_size=2)
1117+
f.write(b'foo')
1118+
name=f.name# This is a fd on posix+cygwin, a filename everywhere else
1119+
self.assertTrue(os.path.exists(name))
1120+
withself.assertWarns(ResourceWarning):
1121+
f.__del__()
1122+
self.assertFalse(
1123+
os.path.exists(name),
1124+
"Rolled SpooledTemporaryFile (name=%s) exists after delete"%name
1125+
)
1126+
10791127
deftest_rewrite_small(self):
10801128
# A SpooledTemporaryFile can be written to multiple within the max_size
10811129
f=self.do_create(max_size=30)

‎Misc/ACKS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@ Dimitri Merejkowsky
11721172
Brian Merrell
11731173
Bruce Merry
11741174
Alexis Métaireau
1175+
Carey Metcalfe
11751176
Luke Mewburn
11761177
Carl Meyer
11771178
Kyle Meyer
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fully implement the:class:`io.BufferedIOBase` or:class:`io.TextIOBase`
2+
interface for:class:`tempfile.SpooledTemporaryFile` objects. This lets them
3+
work correctly with higher-level layers (like compression modules). Patch by
4+
Carey Metcalfe.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp