Skip to content

Commit 2116b12

Browse files
Issue #23865: close() methods in multiple modules now are idempotent and more
robust at shutdown. If needs to release multiple resources, they are released even if errors are occured.
2 parents fcbf8f3 + 7e7a3db commit 2116b12

27 files changed

Lines changed: 316 additions & 210 deletions

Lib/aifc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,10 @@ def rewind(self):
356356
self._soundpos = 0
357357

358358
def close(self):
359-
self._file.close()
359+
file = self._file
360+
if file is not None:
361+
self._file = None
362+
file.close()
360363

361364
def tell(self):
362365
return self._soundpos

Lib/binhex.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class Error(Exception):
3232
pass
3333

3434
# States (what have we written)
35-
[_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3)
35+
_DID_HEADER = 0
36+
_DID_DATA = 1
3637

3738
# Various constants
3839
REASONABLY_LARGE = 32768 # Minimal amount we pass the rle-coder
@@ -213,16 +214,21 @@ def write_rsrc(self, data):
213214
self._write(data)
214215

215216
def close(self):
216-
if self.state < _DID_DATA:
217-
self.close_data()
218-
if self.state != _DID_DATA:
219-
raise Error('Close at the wrong time')
220-
if self.rlen != 0:
221-
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
222-
self._writecrc()
223-
self.ofp.close()
224-
self.state = None
225-
del self.ofp
217+
if self.state is None:
218+
return
219+
try:
220+
if self.state < _DID_DATA:
221+
self.close_data()
222+
if self.state != _DID_DATA:
223+
raise Error('Close at the wrong time')
224+
if self.rlen != 0:
225+
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
226+
self._writecrc()
227+
finally:
228+
self.state = None
229+
ofp = self.ofp
230+
del self.ofp
231+
ofp.close()
226232

227233
def binhex(inp, out):
228234
"""binhex(infilename, outfilename): create binhex-encoded copy of a file"""
@@ -435,11 +441,15 @@ def read_rsrc(self, *n):
435441
return self._read(n)
436442

437443
def close(self):
438-
if self.rlen:
439-
dummy = self.read_rsrc(self.rlen)
440-
self._checkcrc()
441-
self.state = _DID_RSRC
442-
self.ifp.close()
444+
if self.state is None:
445+
return
446+
try:
447+
if self.rlen:
448+
dummy = self.read_rsrc(self.rlen)
449+
self._checkcrc()
450+
finally:
451+
self.state = None
452+
self.ifp.close()
443453

444454
def hexbin(inp, out):
445455
"""hexbin(infilename, outfilename) - Decode binhexed file"""

Lib/chunk.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ def getsize(self):
8585

8686
def close(self):
8787
if not self.closed:
88-
self.skip()
89-
self.closed = True
88+
try:
89+
self.skip()
90+
finally:
91+
self.closed = True
9092

9193
def isatty(self):
9294
if self.closed:

Lib/dbm/dumb.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,10 @@ def __len__(self):
258258
raise error('DBM object has already been closed') from None
259259

260260
def close(self):
261-
self._commit()
262-
self._index = self._datfile = self._dirfile = self._bakfile = None
261+
try:
262+
self._commit()
263+
finally:
264+
self._index = self._datfile = self._dirfile = self._bakfile = None
263265

264266
__del__ = close
265267

Lib/distutils/text_file.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,11 @@ def open(self, filename):
118118
def close(self):
119119
"""Close the current file and forget everything we know about it
120120
(filename, current line number)."""
121-
self.file.close()
121+
file = self.file
122122
self.file = None
123123
self.filename = None
124124
self.current_line = None
125+
file.close()
125126

126127
def gen_error(self, msg, line=None):
127128
outmsg = []

Lib/fileinput.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,10 @@ def __del__(self):
238238
self.close()
239239

240240
def close(self):
241-
self.nextfile()
242-
self._files = ()
241+
try:
242+
self.nextfile()
243+
finally:
244+
self._files = ()
243245

244246
def __enter__(self):
245247
return self
@@ -275,29 +277,31 @@ def __getitem__(self, i):
275277

276278
def nextfile(self):
277279
savestdout = self._savestdout
278-
self._savestdout = 0
280+
self._savestdout = None
279281
if savestdout:
280282
sys.stdout = savestdout
281283

282284
output = self._output
283-
self._output = 0
284-
if output:
285-
output.close()
286-
287-
file = self._file
288-
self._file = 0
289-
if file and not self._isstdin:
290-
file.close()
291-
292-
backupfilename = self._backupfilename
293-
self._backupfilename = 0
294-
if backupfilename and not self._backup:
295-
try: os.unlink(backupfilename)
296-
except OSError: pass
297-
298-
self._isstdin = False
299-
self._buffer = []
300-
self._bufindex = 0
285+
self._output = None
286+
try:
287+
if output:
288+
output.close()
289+
finally:
290+
file = self._file
291+
self._file = None
292+
try:
293+
if file and not self._isstdin:
294+
file.close()
295+
finally:
296+
backupfilename = self._backupfilename
297+
self._backupfilename = None
298+
if backupfilename and not self._backup:
299+
try: os.unlink(backupfilename)
300+
except OSError: pass
301+
302+
self._isstdin = False
303+
self._buffer = []
304+
self._bufindex = 0
301305

302306
def readline(self):
303307
try:

Lib/ftplib.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -667,11 +667,16 @@ def quit(self):
667667

668668
def close(self):
669669
'''Close the connection without assuming anything about it.'''
670-
if self.file is not None:
671-
self.file.close()
672-
if self.sock is not None:
673-
self.sock.close()
674-
self.file = self.sock = None
670+
try:
671+
file = self.file
672+
self.file = None
673+
if file is not None:
674+
file.close()
675+
finally:
676+
sock = self.sock
677+
self.sock = None
678+
if sock is not None:
679+
sock.close()
675680

676681
try:
677682
import ssl

Lib/gzip.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -503,19 +503,21 @@ def closed(self):
503503
return self.fileobj is None
504504

505505
def close(self):
506-
if self.fileobj is None:
506+
fileobj = self.fileobj
507+
if fileobj is None:
507508
return
508-
if self.mode == WRITE:
509-
self.fileobj.write(self.compress.flush())
510-
write32u(self.fileobj, self.crc)
511-
# self.size may exceed 2GB, or even 4GB
512-
write32u(self.fileobj, self.size & 0xffffffff)
513-
self.fileobj = None
514-
elif self.mode == READ:
515-
self.fileobj = None
516-
if self.myfileobj:
517-
self.myfileobj.close()
518-
self.myfileobj = None
509+
self.fileobj = None
510+
try:
511+
if self.mode == WRITE:
512+
fileobj.write(self.compress.flush())
513+
write32u(fileobj, self.crc)
514+
# self.size may exceed 2GB, or even 4GB
515+
write32u(fileobj, self.size & 0xffffffff)
516+
finally:
517+
myfileobj = self.myfileobj
518+
if myfileobj:
519+
self.myfileobj = None
520+
myfileobj.close()
519521

520522
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
521523
self._check_closed()

Lib/http/client.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,11 @@ def _close_conn(self):
388388
fp.close()
389389

390390
def close(self):
391-
super().close() # set "closed" flag
392-
if self.fp:
393-
self._close_conn()
391+
try:
392+
super().close() # set "closed" flag
393+
finally:
394+
if self.fp:
395+
self._close_conn()
394396

395397
# These implementations are for the benefit of io.BufferedReader.
396398

@@ -829,13 +831,17 @@ def connect(self):
829831

830832
def close(self):
831833
"""Close the connection to the HTTP server."""
832-
if self.sock:
833-
self.sock.close() # close it manually... there may be other refs
834-
self.sock = None
835-
if self.__response:
836-
self.__response.close()
837-
self.__response = None
838834
self.__state = _CS_IDLE
835+
try:
836+
sock = self.sock
837+
if sock:
838+
self.sock = None
839+
sock.close() # close it manually... there may be other refs
840+
finally:
841+
response = self.__response
842+
if response:
843+
self.__response = None
844+
response.close()
839845

840846
def send(self, data):
841847
"""Send `data' to the server.

Lib/logging/__init__.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,14 +1013,19 @@ def close(self):
10131013
"""
10141014
self.acquire()
10151015
try:
1016-
if self.stream:
1017-
self.flush()
1018-
if hasattr(self.stream, "close"):
1019-
self.stream.close()
1020-
self.stream = None
1021-
# Issue #19523: call unconditionally to
1022-
# prevent a handler leak when delay is set
1023-
StreamHandler.close(self)
1016+
try:
1017+
if self.stream:
1018+
try:
1019+
self.flush()
1020+
finally:
1021+
stream = self.stream
1022+
self.stream = None
1023+
if hasattr(stream, "close"):
1024+
stream.close()
1025+
finally:
1026+
# Issue #19523: call unconditionally to
1027+
# prevent a handler leak when delay is set
1028+
StreamHandler.close(self)
10241029
finally:
10251030
self.release()
10261031

0 commit comments

Comments
 (0)