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.
This commit is contained in:
parent
c26afcc8fc
commit
1aa2c0f073
|
@ -357,9 +357,12 @@ class Aifc_read:
|
|||
self._soundpos = 0
|
||||
|
||||
def close(self):
|
||||
if self._decomp:
|
||||
self._decomp.CloseDecompressor()
|
||||
decomp = self._decomp
|
||||
try:
|
||||
if decomp:
|
||||
self._decomp = None
|
||||
decomp.CloseDecompressor()
|
||||
finally:
|
||||
self._file.close()
|
||||
|
||||
def tell(self):
|
||||
|
|
|
@ -32,7 +32,8 @@ class Error(Exception):
|
|||
pass
|
||||
|
||||
# States (what have we written)
|
||||
[_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3)
|
||||
_DID_HEADER = 0
|
||||
_DID_DATA = 1
|
||||
|
||||
# Various constants
|
||||
REASONABLY_LARGE=32768 # Minimal amount we pass the rle-coder
|
||||
|
@ -235,6 +236,9 @@ class BinHex:
|
|||
self._write(data)
|
||||
|
||||
def close(self):
|
||||
if self.state is None:
|
||||
return
|
||||
try:
|
||||
if self.state < _DID_DATA:
|
||||
self.close_data()
|
||||
if self.state != _DID_DATA:
|
||||
|
@ -243,9 +247,11 @@ class BinHex:
|
|||
raise Error, \
|
||||
"Incorrect resource-datasize, diff=%r" % (self.rlen,)
|
||||
self._writecrc()
|
||||
self.ofp.close()
|
||||
finally:
|
||||
self.state = None
|
||||
ofp = self.ofp
|
||||
del self.ofp
|
||||
ofp.close()
|
||||
|
||||
def binhex(inp, out):
|
||||
"""(infilename, outfilename) - Create binhex-encoded copy of a file"""
|
||||
|
@ -463,10 +469,14 @@ class HexBin:
|
|||
return self._read(n)
|
||||
|
||||
def close(self):
|
||||
if self.state is None:
|
||||
return
|
||||
try:
|
||||
if self.rlen:
|
||||
dummy = self.read_rsrc(self.rlen)
|
||||
self._checkcrc()
|
||||
self.state = _DID_RSRC
|
||||
finally:
|
||||
self.state = None
|
||||
self.ifp.close()
|
||||
|
||||
def hexbin(inp, out):
|
||||
|
|
|
@ -85,7 +85,9 @@ class Chunk:
|
|||
|
||||
def close(self):
|
||||
if not self.closed:
|
||||
try:
|
||||
self.skip()
|
||||
finally:
|
||||
self.closed = True
|
||||
|
||||
def isatty(self):
|
||||
|
|
|
@ -124,11 +124,11 @@ class TextFile:
|
|||
def close (self):
|
||||
"""Close the current file and forget everything we know about it
|
||||
(filename, current line number)."""
|
||||
|
||||
self.file.close ()
|
||||
file = self.file
|
||||
self.file = None
|
||||
self.filename = None
|
||||
self.current_line = None
|
||||
file.close()
|
||||
|
||||
|
||||
def gen_error (self, msg, line=None):
|
||||
|
|
|
@ -209,7 +209,9 @@ class _Database(UserDict.DictMixin):
|
|||
return len(self._index)
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self._commit()
|
||||
finally:
|
||||
self._index = self._datfile = self._dirfile = self._bakfile = None
|
||||
|
||||
__del__ = close
|
||||
|
|
|
@ -233,7 +233,9 @@ class FileInput:
|
|||
self.close()
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.nextfile()
|
||||
finally:
|
||||
self._files = ()
|
||||
|
||||
def __iter__(self):
|
||||
|
@ -270,14 +272,16 @@ class FileInput:
|
|||
|
||||
output = self._output
|
||||
self._output = 0
|
||||
try:
|
||||
if output:
|
||||
output.close()
|
||||
|
||||
finally:
|
||||
file = self._file
|
||||
self._file = 0
|
||||
try:
|
||||
if file and not self._isstdin:
|
||||
file.close()
|
||||
|
||||
finally:
|
||||
backupfilename = self._backupfilename
|
||||
self._backupfilename = 0
|
||||
if backupfilename and not self._backup:
|
||||
|
|
|
@ -594,11 +594,16 @@ class FTP:
|
|||
|
||||
def close(self):
|
||||
'''Close the connection without assuming anything about it.'''
|
||||
if self.file is not None:
|
||||
self.file.close()
|
||||
if self.sock is not None:
|
||||
self.sock.close()
|
||||
self.file = self.sock = None
|
||||
try:
|
||||
file = self.file
|
||||
self.file = None
|
||||
if file is not None:
|
||||
file.close()
|
||||
finally:
|
||||
sock = self.sock
|
||||
self.sock = None
|
||||
if sock is not None:
|
||||
sock.close()
|
||||
|
||||
try:
|
||||
import ssl
|
||||
|
|
20
Lib/gzip.py
20
Lib/gzip.py
|
@ -369,19 +369,21 @@ class GzipFile(io.BufferedIOBase):
|
|||
return self.fileobj is None
|
||||
|
||||
def close(self):
|
||||
if self.fileobj is None:
|
||||
fileobj = self.fileobj
|
||||
if fileobj is None:
|
||||
return
|
||||
self.fileobj = None
|
||||
try:
|
||||
if self.mode == WRITE:
|
||||
self.fileobj.write(self.compress.flush())
|
||||
write32u(self.fileobj, self.crc)
|
||||
fileobj.write(self.compress.flush())
|
||||
write32u(fileobj, self.crc)
|
||||
# self.size may exceed 2GB, or even 4GB
|
||||
write32u(self.fileobj, self.size & 0xffffffffL)
|
||||
self.fileobj = None
|
||||
elif self.mode == READ:
|
||||
self.fileobj = None
|
||||
if self.myfileobj:
|
||||
self.myfileobj.close()
|
||||
write32u(fileobj, self.size & 0xffffffffL)
|
||||
finally:
|
||||
myfileobj = self.myfileobj
|
||||
if myfileobj:
|
||||
self.myfileobj = None
|
||||
myfileobj.close()
|
||||
|
||||
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
|
||||
self._check_closed()
|
||||
|
|
|
@ -560,9 +560,10 @@ class HTTPResponse:
|
|||
return True
|
||||
|
||||
def close(self):
|
||||
if self.fp:
|
||||
self.fp.close()
|
||||
fp = self.fp
|
||||
if fp:
|
||||
self.fp = None
|
||||
fp.close()
|
||||
|
||||
def isclosed(self):
|
||||
# NOTE: it is possible that we will not ever call self.close(). This
|
||||
|
@ -835,13 +836,17 @@ class HTTPConnection:
|
|||
|
||||
def close(self):
|
||||
"""Close the connection to the HTTP server."""
|
||||
if self.sock:
|
||||
self.sock.close() # close it manually... there may be other refs
|
||||
self.sock = None
|
||||
if self.__response:
|
||||
self.__response.close()
|
||||
self.__response = None
|
||||
self.__state = _CS_IDLE
|
||||
try:
|
||||
sock = self.sock
|
||||
if sock:
|
||||
self.sock = None
|
||||
sock.close() # close it manually... there may be other refs
|
||||
finally:
|
||||
response = self.__response
|
||||
if response:
|
||||
self.__response = None
|
||||
response.close()
|
||||
|
||||
def send(self, data):
|
||||
"""Send `data' to the server."""
|
||||
|
|
|
@ -915,12 +915,17 @@ class FileHandler(StreamHandler):
|
|||
Closes the stream.
|
||||
"""
|
||||
self.acquire()
|
||||
try:
|
||||
try:
|
||||
if self.stream:
|
||||
try:
|
||||
self.flush()
|
||||
if hasattr(self.stream, "close"):
|
||||
self.stream.close()
|
||||
finally:
|
||||
stream = self.stream
|
||||
self.stream = None
|
||||
if hasattr(stream, "close"):
|
||||
stream.close()
|
||||
finally:
|
||||
# Issue #19523: call unconditionally to
|
||||
# prevent a handler leak when delay is set
|
||||
StreamHandler.close(self)
|
||||
|
|
|
@ -588,9 +588,10 @@ class SocketHandler(logging.Handler):
|
|||
"""
|
||||
self.acquire()
|
||||
try:
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
sock = self.sock
|
||||
if sock:
|
||||
self.sock = None
|
||||
sock.close()
|
||||
finally:
|
||||
self.release()
|
||||
logging.Handler.close(self)
|
||||
|
@ -1160,7 +1161,9 @@ class BufferingHandler(logging.Handler):
|
|||
|
||||
This version just flushes and chains to the parent class' close().
|
||||
"""
|
||||
try:
|
||||
self.flush()
|
||||
finally:
|
||||
logging.Handler.close(self)
|
||||
|
||||
class MemoryHandler(BufferingHandler):
|
||||
|
@ -1213,7 +1216,9 @@ class MemoryHandler(BufferingHandler):
|
|||
"""
|
||||
Flush, set the target to None and lose the buffer.
|
||||
"""
|
||||
try:
|
||||
self.flush()
|
||||
finally:
|
||||
self.acquire()
|
||||
try:
|
||||
self.target = None
|
||||
|
|
|
@ -719,9 +719,13 @@ class _singlefileMailbox(Mailbox):
|
|||
|
||||
def close(self):
|
||||
"""Flush and close the mailbox."""
|
||||
try:
|
||||
self.flush()
|
||||
finally:
|
||||
try:
|
||||
if self._locked:
|
||||
self.unlock()
|
||||
finally:
|
||||
self._file.close() # Sync has been done by self.flush() above.
|
||||
|
||||
def _lookup(self, key=None):
|
||||
|
|
|
@ -285,9 +285,13 @@ class SocketListener(object):
|
|||
return conn
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self._socket.close()
|
||||
if self._unlink is not None:
|
||||
self._unlink()
|
||||
finally:
|
||||
unlink = self._unlink
|
||||
if unlink is not None:
|
||||
self._unlink = None
|
||||
unlink()
|
||||
|
||||
|
||||
def SocketClient(address):
|
||||
|
|
|
@ -156,9 +156,13 @@ class Queue(object):
|
|||
|
||||
def close(self):
|
||||
self._closed = True
|
||||
try:
|
||||
self._reader.close()
|
||||
if self._close:
|
||||
self._close()
|
||||
finally:
|
||||
close = self._close
|
||||
if close:
|
||||
self._close = None
|
||||
close()
|
||||
|
||||
def join_thread(self):
|
||||
debug('Queue.join_thread()')
|
||||
|
|
|
@ -140,16 +140,20 @@ class Shelf(UserDict.DictMixin):
|
|||
pass
|
||||
|
||||
def close(self):
|
||||
if self.dict is None:
|
||||
return
|
||||
try:
|
||||
self.sync()
|
||||
try:
|
||||
self.dict.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
finally:
|
||||
# Catch errors that may happen when close is called from __del__
|
||||
# because CPython is in interpreter shutdown.
|
||||
try:
|
||||
self.dict = _ClosedDict()
|
||||
except (NameError, TypeError):
|
||||
except:
|
||||
self.dict = None
|
||||
|
||||
def __del__(self):
|
||||
|
|
|
@ -750,12 +750,16 @@ class SMTP:
|
|||
|
||||
def close(self):
|
||||
"""Close the connection to the SMTP server."""
|
||||
if self.file:
|
||||
self.file.close()
|
||||
try:
|
||||
file = self.file
|
||||
self.file = None
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
if file:
|
||||
file.close()
|
||||
finally:
|
||||
sock = self.sock
|
||||
self.sock = None
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
|
||||
def quit(self):
|
||||
|
|
|
@ -492,6 +492,8 @@ class _Stream:
|
|||
if self.closed:
|
||||
return
|
||||
|
||||
self.closed = True
|
||||
try:
|
||||
if self.mode == "w" and self.comptype != "tar":
|
||||
self.buf += self.cmp.flush()
|
||||
|
||||
|
@ -507,12 +509,10 @@ class _Stream:
|
|||
# it to look positive on all boxes.
|
||||
self.fileobj.write(struct.pack("<L", self.crc & 0xffffffffL))
|
||||
self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFFL))
|
||||
|
||||
finally:
|
||||
if not self._extfileobj:
|
||||
self.fileobj.close()
|
||||
|
||||
self.closed = True
|
||||
|
||||
def _init_read_gz(self):
|
||||
"""Initialize for reading a gzip compressed fileobj.
|
||||
"""
|
||||
|
@ -1796,6 +1796,8 @@ class TarFile(object):
|
|||
if self.closed:
|
||||
return
|
||||
|
||||
self.closed = True
|
||||
try:
|
||||
if self.mode in "aw":
|
||||
self.fileobj.write(NUL * (BLOCKSIZE * 2))
|
||||
self.offset += (BLOCKSIZE * 2)
|
||||
|
@ -1804,10 +1806,9 @@ class TarFile(object):
|
|||
blocks, remainder = divmod(self.offset, RECORDSIZE)
|
||||
if remainder > 0:
|
||||
self.fileobj.write(NUL * (RECORDSIZE - remainder))
|
||||
|
||||
finally:
|
||||
if not self._extfileobj:
|
||||
self.fileobj.close()
|
||||
self.closed = True
|
||||
|
||||
def getmember(self, name):
|
||||
"""Return a TarInfo object for member `name'. If `name' can not be
|
||||
|
|
|
@ -254,12 +254,13 @@ class Telnet:
|
|||
|
||||
def close(self):
|
||||
"""Close the connection."""
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
sock = self.sock
|
||||
self.sock = 0
|
||||
self.eof = 1
|
||||
self.iacseq = ''
|
||||
self.sb = 0
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
def get_socket(self):
|
||||
"""Return the socket object used internally."""
|
||||
|
|
|
@ -413,7 +413,9 @@ class _TemporaryFileWrapper:
|
|||
def close(self):
|
||||
if not self.close_called:
|
||||
self.close_called = True
|
||||
try:
|
||||
self.file.close()
|
||||
finally:
|
||||
if self.delete:
|
||||
self.unlink(self.name)
|
||||
|
||||
|
|
|
@ -994,12 +994,17 @@ class addclosehook(addbase):
|
|||
self.hookargs = hookargs
|
||||
|
||||
def close(self):
|
||||
if self.closehook:
|
||||
self.closehook(*self.hookargs)
|
||||
try:
|
||||
closehook = self.closehook
|
||||
hookargs = self.hookargs
|
||||
if closehook:
|
||||
self.closehook = None
|
||||
self.hookargs = None
|
||||
closehook(*hookargs)
|
||||
finally:
|
||||
addbase.close(self)
|
||||
|
||||
|
||||
class addinfo(addbase):
|
||||
"""class to add an info() method to an open file."""
|
||||
|
||||
|
|
14
Lib/wave.py
14
Lib/wave.py
|
@ -180,10 +180,11 @@ class Wave_read:
|
|||
self._soundpos = 0
|
||||
|
||||
def close(self):
|
||||
if self._i_opened_the_file:
|
||||
self._i_opened_the_file.close()
|
||||
self._i_opened_the_file = None
|
||||
self._file = None
|
||||
file = self._i_opened_the_file
|
||||
if file:
|
||||
self._i_opened_the_file = None
|
||||
file.close()
|
||||
|
||||
def tell(self):
|
||||
return self._soundpos
|
||||
|
@ -444,17 +445,18 @@ class Wave_write:
|
|||
self._patchheader()
|
||||
|
||||
def close(self):
|
||||
if self._file:
|
||||
try:
|
||||
if self._file:
|
||||
self._ensure_header_written(0)
|
||||
if self._datalength != self._datawritten:
|
||||
self._patchheader()
|
||||
self._file.flush()
|
||||
finally:
|
||||
self._file = None
|
||||
if self._i_opened_the_file:
|
||||
self._i_opened_the_file.close()
|
||||
file = self._i_opened_the_file
|
||||
if file:
|
||||
self._i_opened_the_file = None
|
||||
file.close()
|
||||
|
||||
#
|
||||
# Internal methods.
|
||||
|
|
|
@ -214,11 +214,13 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
|
|||
self._err_handler.fatalError(exc)
|
||||
|
||||
def close(self):
|
||||
if self._entity_stack:
|
||||
if self._entity_stack or self._parser is None:
|
||||
# If we are completing an external entity, do nothing here
|
||||
return
|
||||
try:
|
||||
self.feed("", isFinal = 1)
|
||||
self._cont_handler.endDocument()
|
||||
finally:
|
||||
self._parsing = 0
|
||||
# break cycle created by expat handlers pointing to our methods
|
||||
self._parser = None
|
||||
|
|
|
@ -558,8 +558,13 @@ else:
|
|||
self._parser.Parse(data, 0)
|
||||
|
||||
def close(self):
|
||||
self._parser.Parse("", 1) # end of data
|
||||
try:
|
||||
parser = self._parser
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
del self._target, self._parser # get rid of circular references
|
||||
parser.Parse("", 1) # end of data
|
||||
|
||||
class SlowParser:
|
||||
"""Default XML parser (based on xmllib.XMLParser)."""
|
||||
|
@ -1214,7 +1219,9 @@ class GzipDecodedResponse(gzip.GzipFile if gzip else object):
|
|||
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
gzip.GzipFile.close(self)
|
||||
finally:
|
||||
self.stringio.close()
|
||||
|
||||
|
||||
|
@ -1384,9 +1391,10 @@ class Transport:
|
|||
# Used in the event of socket errors.
|
||||
#
|
||||
def close(self):
|
||||
if self._connection[1]:
|
||||
self._connection[1].close()
|
||||
host, connection = self._connection
|
||||
if connection:
|
||||
self._connection = (None, None)
|
||||
connection.close()
|
||||
|
||||
##
|
||||
# Send request header.
|
||||
|
|
|
@ -21,6 +21,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- 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.
|
||||
|
||||
- Issue #23881: urllib.ftpwrapper constructor now closes the socket if the FTP
|
||||
connection failed.
|
||||
|
||||
|
|
Loading…
Reference in New Issue