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:
commit
2116b12da5
@ -356,7 +356,10 @@ class Aifc_read:
|
|||||||
self._soundpos = 0
|
self._soundpos = 0
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._file.close()
|
file = self._file
|
||||||
|
if file is not None:
|
||||||
|
self._file = None
|
||||||
|
file.close()
|
||||||
|
|
||||||
def tell(self):
|
def tell(self):
|
||||||
return self._soundpos
|
return self._soundpos
|
||||||
|
@ -32,7 +32,8 @@ class Error(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# States (what have we written)
|
# States (what have we written)
|
||||||
[_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3)
|
_DID_HEADER = 0
|
||||||
|
_DID_DATA = 1
|
||||||
|
|
||||||
# Various constants
|
# Various constants
|
||||||
REASONABLY_LARGE = 32768 # Minimal amount we pass the rle-coder
|
REASONABLY_LARGE = 32768 # Minimal amount we pass the rle-coder
|
||||||
@ -213,16 +214,21 @@ class BinHex:
|
|||||||
self._write(data)
|
self._write(data)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.state < _DID_DATA:
|
if self.state is None:
|
||||||
self.close_data()
|
return
|
||||||
if self.state != _DID_DATA:
|
try:
|
||||||
raise Error('Close at the wrong time')
|
if self.state < _DID_DATA:
|
||||||
if self.rlen != 0:
|
self.close_data()
|
||||||
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
|
if self.state != _DID_DATA:
|
||||||
self._writecrc()
|
raise Error('Close at the wrong time')
|
||||||
self.ofp.close()
|
if self.rlen != 0:
|
||||||
self.state = None
|
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
|
||||||
del self.ofp
|
self._writecrc()
|
||||||
|
finally:
|
||||||
|
self.state = None
|
||||||
|
ofp = self.ofp
|
||||||
|
del self.ofp
|
||||||
|
ofp.close()
|
||||||
|
|
||||||
def binhex(inp, out):
|
def binhex(inp, out):
|
||||||
"""binhex(infilename, outfilename): create binhex-encoded copy of a file"""
|
"""binhex(infilename, outfilename): create binhex-encoded copy of a file"""
|
||||||
@ -435,11 +441,15 @@ class HexBin:
|
|||||||
return self._read(n)
|
return self._read(n)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.rlen:
|
if self.state is None:
|
||||||
dummy = self.read_rsrc(self.rlen)
|
return
|
||||||
self._checkcrc()
|
try:
|
||||||
self.state = _DID_RSRC
|
if self.rlen:
|
||||||
self.ifp.close()
|
dummy = self.read_rsrc(self.rlen)
|
||||||
|
self._checkcrc()
|
||||||
|
finally:
|
||||||
|
self.state = None
|
||||||
|
self.ifp.close()
|
||||||
|
|
||||||
def hexbin(inp, out):
|
def hexbin(inp, out):
|
||||||
"""hexbin(infilename, outfilename) - Decode binhexed file"""
|
"""hexbin(infilename, outfilename) - Decode binhexed file"""
|
||||||
|
@ -85,8 +85,10 @@ class Chunk:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if not self.closed:
|
if not self.closed:
|
||||||
self.skip()
|
try:
|
||||||
self.closed = True
|
self.skip()
|
||||||
|
finally:
|
||||||
|
self.closed = True
|
||||||
|
|
||||||
def isatty(self):
|
def isatty(self):
|
||||||
if self.closed:
|
if self.closed:
|
||||||
|
@ -258,8 +258,10 @@ class _Database(collections.MutableMapping):
|
|||||||
raise error('DBM object has already been closed') from None
|
raise error('DBM object has already been closed') from None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._commit()
|
try:
|
||||||
self._index = self._datfile = self._dirfile = self._bakfile = None
|
self._commit()
|
||||||
|
finally:
|
||||||
|
self._index = self._datfile = self._dirfile = self._bakfile = None
|
||||||
|
|
||||||
__del__ = close
|
__del__ = close
|
||||||
|
|
||||||
|
@ -118,10 +118,11 @@ class TextFile:
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""Close the current file and forget everything we know about it
|
"""Close the current file and forget everything we know about it
|
||||||
(filename, current line number)."""
|
(filename, current line number)."""
|
||||||
self.file.close()
|
file = self.file
|
||||||
self.file = None
|
self.file = None
|
||||||
self.filename = None
|
self.filename = None
|
||||||
self.current_line = None
|
self.current_line = None
|
||||||
|
file.close()
|
||||||
|
|
||||||
def gen_error(self, msg, line=None):
|
def gen_error(self, msg, line=None):
|
||||||
outmsg = []
|
outmsg = []
|
||||||
|
@ -238,8 +238,10 @@ class FileInput:
|
|||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.nextfile()
|
try:
|
||||||
self._files = ()
|
self.nextfile()
|
||||||
|
finally:
|
||||||
|
self._files = ()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@ -275,29 +277,31 @@ class FileInput:
|
|||||||
|
|
||||||
def nextfile(self):
|
def nextfile(self):
|
||||||
savestdout = self._savestdout
|
savestdout = self._savestdout
|
||||||
self._savestdout = 0
|
self._savestdout = None
|
||||||
if savestdout:
|
if savestdout:
|
||||||
sys.stdout = savestdout
|
sys.stdout = savestdout
|
||||||
|
|
||||||
output = self._output
|
output = self._output
|
||||||
self._output = 0
|
self._output = None
|
||||||
if output:
|
try:
|
||||||
output.close()
|
if output:
|
||||||
|
output.close()
|
||||||
|
finally:
|
||||||
|
file = self._file
|
||||||
|
self._file = None
|
||||||
|
try:
|
||||||
|
if file and not self._isstdin:
|
||||||
|
file.close()
|
||||||
|
finally:
|
||||||
|
backupfilename = self._backupfilename
|
||||||
|
self._backupfilename = None
|
||||||
|
if backupfilename and not self._backup:
|
||||||
|
try: os.unlink(backupfilename)
|
||||||
|
except OSError: pass
|
||||||
|
|
||||||
file = self._file
|
self._isstdin = False
|
||||||
self._file = 0
|
self._buffer = []
|
||||||
if file and not self._isstdin:
|
self._bufindex = 0
|
||||||
file.close()
|
|
||||||
|
|
||||||
backupfilename = self._backupfilename
|
|
||||||
self._backupfilename = 0
|
|
||||||
if backupfilename and not self._backup:
|
|
||||||
try: os.unlink(backupfilename)
|
|
||||||
except OSError: pass
|
|
||||||
|
|
||||||
self._isstdin = False
|
|
||||||
self._buffer = []
|
|
||||||
self._bufindex = 0
|
|
||||||
|
|
||||||
def readline(self):
|
def readline(self):
|
||||||
try:
|
try:
|
||||||
|
@ -667,11 +667,16 @@ class FTP:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
'''Close the connection without assuming anything about it.'''
|
'''Close the connection without assuming anything about it.'''
|
||||||
if self.file is not None:
|
try:
|
||||||
self.file.close()
|
file = self.file
|
||||||
if self.sock is not None:
|
self.file = None
|
||||||
self.sock.close()
|
if file is not None:
|
||||||
self.file = self.sock = None
|
file.close()
|
||||||
|
finally:
|
||||||
|
sock = self.sock
|
||||||
|
self.sock = None
|
||||||
|
if sock is not None:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ssl
|
import ssl
|
||||||
|
26
Lib/gzip.py
26
Lib/gzip.py
@ -503,19 +503,21 @@ class GzipFile(io.BufferedIOBase):
|
|||||||
return self.fileobj is None
|
return self.fileobj is None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.fileobj is None:
|
fileobj = self.fileobj
|
||||||
|
if fileobj is None:
|
||||||
return
|
return
|
||||||
if self.mode == WRITE:
|
self.fileobj = None
|
||||||
self.fileobj.write(self.compress.flush())
|
try:
|
||||||
write32u(self.fileobj, self.crc)
|
if self.mode == WRITE:
|
||||||
# self.size may exceed 2GB, or even 4GB
|
fileobj.write(self.compress.flush())
|
||||||
write32u(self.fileobj, self.size & 0xffffffff)
|
write32u(fileobj, self.crc)
|
||||||
self.fileobj = None
|
# self.size may exceed 2GB, or even 4GB
|
||||||
elif self.mode == READ:
|
write32u(fileobj, self.size & 0xffffffff)
|
||||||
self.fileobj = None
|
finally:
|
||||||
if self.myfileobj:
|
myfileobj = self.myfileobj
|
||||||
self.myfileobj.close()
|
if myfileobj:
|
||||||
self.myfileobj = None
|
self.myfileobj = None
|
||||||
|
myfileobj.close()
|
||||||
|
|
||||||
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
|
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
|
||||||
self._check_closed()
|
self._check_closed()
|
||||||
|
@ -388,9 +388,11 @@ class HTTPResponse(io.BufferedIOBase):
|
|||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
super().close() # set "closed" flag
|
try:
|
||||||
if self.fp:
|
super().close() # set "closed" flag
|
||||||
self._close_conn()
|
finally:
|
||||||
|
if self.fp:
|
||||||
|
self._close_conn()
|
||||||
|
|
||||||
# These implementations are for the benefit of io.BufferedReader.
|
# These implementations are for the benefit of io.BufferedReader.
|
||||||
|
|
||||||
@ -829,13 +831,17 @@ class HTTPConnection:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the connection to the HTTP server."""
|
"""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
|
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):
|
def send(self, data):
|
||||||
"""Send `data' to the server.
|
"""Send `data' to the server.
|
||||||
|
@ -1013,14 +1013,19 @@ class FileHandler(StreamHandler):
|
|||||||
"""
|
"""
|
||||||
self.acquire()
|
self.acquire()
|
||||||
try:
|
try:
|
||||||
if self.stream:
|
try:
|
||||||
self.flush()
|
if self.stream:
|
||||||
if hasattr(self.stream, "close"):
|
try:
|
||||||
self.stream.close()
|
self.flush()
|
||||||
self.stream = None
|
finally:
|
||||||
# Issue #19523: call unconditionally to
|
stream = self.stream
|
||||||
# prevent a handler leak when delay is set
|
self.stream = None
|
||||||
StreamHandler.close(self)
|
if hasattr(stream, "close"):
|
||||||
|
stream.close()
|
||||||
|
finally:
|
||||||
|
# Issue #19523: call unconditionally to
|
||||||
|
# prevent a handler leak when delay is set
|
||||||
|
StreamHandler.close(self)
|
||||||
finally:
|
finally:
|
||||||
self.release()
|
self.release()
|
||||||
|
|
||||||
|
@ -627,9 +627,10 @@ class SocketHandler(logging.Handler):
|
|||||||
"""
|
"""
|
||||||
self.acquire()
|
self.acquire()
|
||||||
try:
|
try:
|
||||||
if self.sock:
|
sock = self.sock
|
||||||
self.sock.close()
|
if sock:
|
||||||
self.sock = None
|
self.sock = None
|
||||||
|
sock.close()
|
||||||
logging.Handler.close(self)
|
logging.Handler.close(self)
|
||||||
finally:
|
finally:
|
||||||
self.release()
|
self.release()
|
||||||
@ -1213,8 +1214,10 @@ class BufferingHandler(logging.Handler):
|
|||||||
|
|
||||||
This version just flushes and chains to the parent class' close().
|
This version just flushes and chains to the parent class' close().
|
||||||
"""
|
"""
|
||||||
self.flush()
|
try:
|
||||||
logging.Handler.close(self)
|
self.flush()
|
||||||
|
finally:
|
||||||
|
logging.Handler.close(self)
|
||||||
|
|
||||||
class MemoryHandler(BufferingHandler):
|
class MemoryHandler(BufferingHandler):
|
||||||
"""
|
"""
|
||||||
@ -1268,13 +1271,15 @@ class MemoryHandler(BufferingHandler):
|
|||||||
"""
|
"""
|
||||||
Flush, set the target to None and lose the buffer.
|
Flush, set the target to None and lose the buffer.
|
||||||
"""
|
"""
|
||||||
self.flush()
|
|
||||||
self.acquire()
|
|
||||||
try:
|
try:
|
||||||
self.target = None
|
self.flush()
|
||||||
BufferingHandler.close(self)
|
|
||||||
finally:
|
finally:
|
||||||
self.release()
|
self.acquire()
|
||||||
|
try:
|
||||||
|
self.target = None
|
||||||
|
BufferingHandler.close(self)
|
||||||
|
finally:
|
||||||
|
self.release()
|
||||||
|
|
||||||
|
|
||||||
class QueueHandler(logging.Handler):
|
class QueueHandler(logging.Handler):
|
||||||
|
@ -722,10 +722,14 @@ class _singlefileMailbox(Mailbox):
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Flush and close the mailbox."""
|
"""Flush and close the mailbox."""
|
||||||
self.flush()
|
try:
|
||||||
if self._locked:
|
self.flush()
|
||||||
self.unlock()
|
finally:
|
||||||
self._file.close() # Sync has been done by self.flush() above.
|
try:
|
||||||
|
if self._locked:
|
||||||
|
self.unlock()
|
||||||
|
finally:
|
||||||
|
self._file.close() # Sync has been done by self.flush() above.
|
||||||
|
|
||||||
def _lookup(self, key=None):
|
def _lookup(self, key=None):
|
||||||
"""Return (start, stop) or raise KeyError."""
|
"""Return (start, stop) or raise KeyError."""
|
||||||
@ -1966,9 +1970,11 @@ class _ProxyFile:
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""Close the file."""
|
"""Close the file."""
|
||||||
if hasattr(self, '_file'):
|
if hasattr(self, '_file'):
|
||||||
if hasattr(self._file, 'close'):
|
try:
|
||||||
self._file.close()
|
if hasattr(self._file, 'close'):
|
||||||
del self._file
|
self._file.close()
|
||||||
|
finally:
|
||||||
|
del self._file
|
||||||
|
|
||||||
def _read(self, size, read_method):
|
def _read(self, size, read_method):
|
||||||
"""Read size bytes using read_method."""
|
"""Read size bytes using read_method."""
|
||||||
|
@ -460,9 +460,10 @@ class Listener(object):
|
|||||||
'''
|
'''
|
||||||
Close the bound socket or named pipe of `self`.
|
Close the bound socket or named pipe of `self`.
|
||||||
'''
|
'''
|
||||||
if self._listener is not None:
|
listener = self._listener
|
||||||
self._listener.close()
|
if listener is not None:
|
||||||
self._listener = None
|
self._listener = None
|
||||||
|
listener.close()
|
||||||
|
|
||||||
address = property(lambda self: self._listener._address)
|
address = property(lambda self: self._listener._address)
|
||||||
last_accepted = property(lambda self: self._listener._last_accepted)
|
last_accepted = property(lambda self: self._listener._last_accepted)
|
||||||
@ -594,9 +595,13 @@ class SocketListener(object):
|
|||||||
return Connection(s.detach())
|
return Connection(s.detach())
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._socket.close()
|
try:
|
||||||
if self._unlink is not None:
|
self._socket.close()
|
||||||
self._unlink()
|
finally:
|
||||||
|
unlink = self._unlink
|
||||||
|
if unlink is not None:
|
||||||
|
self._unlink = None
|
||||||
|
unlink()
|
||||||
|
|
||||||
|
|
||||||
def SocketClient(address):
|
def SocketClient(address):
|
||||||
|
@ -130,9 +130,13 @@ class Queue(object):
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._closed = True
|
self._closed = True
|
||||||
self._reader.close()
|
try:
|
||||||
if self._close:
|
self._reader.close()
|
||||||
self._close()
|
finally:
|
||||||
|
close = self._close
|
||||||
|
if close:
|
||||||
|
self._close = None
|
||||||
|
close()
|
||||||
|
|
||||||
def join_thread(self):
|
def join_thread(self):
|
||||||
debug('Queue.join_thread()')
|
debug('Queue.join_thread()')
|
||||||
|
@ -276,18 +276,23 @@ class POP3:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the connection without assuming anything about it."""
|
"""Close the connection without assuming anything about it."""
|
||||||
if self.file is not None:
|
try:
|
||||||
self.file.close()
|
file = self.file
|
||||||
if self.sock is not None:
|
self.file = None
|
||||||
try:
|
if file is not None:
|
||||||
self.sock.shutdown(socket.SHUT_RDWR)
|
file.close()
|
||||||
except OSError as e:
|
finally:
|
||||||
# The server might already have closed the connection
|
sock = self.sock
|
||||||
if e.errno != errno.ENOTCONN:
|
self.sock = None
|
||||||
raise
|
if sock is not None:
|
||||||
finally:
|
try:
|
||||||
self.sock.close()
|
sock.shutdown(socket.SHUT_RDWR)
|
||||||
self.file = self.sock = None
|
except OSError as e:
|
||||||
|
# The server might already have closed the connection
|
||||||
|
if e.errno != errno.ENOTCONN:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
#__del__ = quit
|
#__del__ = quit
|
||||||
|
|
||||||
|
@ -439,8 +439,10 @@ if hasattr(select, 'epoll'):
|
|||||||
return ready
|
return ready
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._epoll.close()
|
try:
|
||||||
super().close()
|
self._epoll.close()
|
||||||
|
finally:
|
||||||
|
super().close()
|
||||||
|
|
||||||
|
|
||||||
if hasattr(select, 'devpoll'):
|
if hasattr(select, 'devpoll'):
|
||||||
@ -496,8 +498,10 @@ if hasattr(select, 'devpoll'):
|
|||||||
return ready
|
return ready
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._devpoll.close()
|
try:
|
||||||
super().close()
|
self._devpoll.close()
|
||||||
|
finally:
|
||||||
|
super().close()
|
||||||
|
|
||||||
|
|
||||||
if hasattr(select, 'kqueue'):
|
if hasattr(select, 'kqueue'):
|
||||||
@ -566,8 +570,10 @@ if hasattr(select, 'kqueue'):
|
|||||||
return ready
|
return ready
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._kqueue.close()
|
try:
|
||||||
super().close()
|
self._kqueue.close()
|
||||||
|
finally:
|
||||||
|
super().close()
|
||||||
|
|
||||||
|
|
||||||
# Choose the best implementation, roughly:
|
# Choose the best implementation, roughly:
|
||||||
|
@ -138,17 +138,21 @@ class Shelf(collections.MutableMapping):
|
|||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.sync()
|
if self.dict is None:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.dict.close()
|
self.sync()
|
||||||
except AttributeError:
|
try:
|
||||||
pass
|
self.dict.close()
|
||||||
# Catch errors that may happen when close is called from __del__
|
except AttributeError:
|
||||||
# because CPython is in interpreter shutdown.
|
pass
|
||||||
try:
|
finally:
|
||||||
self.dict = _ClosedDict()
|
# Catch errors that may happen when close is called from __del__
|
||||||
except (NameError, TypeError):
|
# because CPython is in interpreter shutdown.
|
||||||
self.dict = None
|
try:
|
||||||
|
self.dict = _ClosedDict()
|
||||||
|
except:
|
||||||
|
self.dict = None
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if not hasattr(self, 'writeback'):
|
if not hasattr(self, 'writeback'):
|
||||||
|
@ -880,12 +880,16 @@ class SMTP:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the connection to the SMTP server."""
|
"""Close the connection to the SMTP server."""
|
||||||
if self.file:
|
try:
|
||||||
self.file.close()
|
file = self.file
|
||||||
self.file = None
|
self.file = None
|
||||||
if self.sock:
|
if file:
|
||||||
self.sock.close()
|
file.close()
|
||||||
self.sock = None
|
finally:
|
||||||
|
sock = self.sock
|
||||||
|
self.sock = None
|
||||||
|
if sock:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
"""Terminate the SMTP session."""
|
"""Terminate the SMTP session."""
|
||||||
|
13
Lib/sunau.py
13
Lib/sunau.py
@ -295,9 +295,11 @@ class Au_read:
|
|||||||
self._soundpos = pos
|
self._soundpos = pos
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self._opened and self._file:
|
file = self._file
|
||||||
self._file.close()
|
if file:
|
||||||
self._file = None
|
self._file = None
|
||||||
|
if self._opened:
|
||||||
|
file.close()
|
||||||
|
|
||||||
class Au_write:
|
class Au_write:
|
||||||
|
|
||||||
@ -438,9 +440,10 @@ class Au_write:
|
|||||||
self._patchheader()
|
self._patchheader()
|
||||||
self._file.flush()
|
self._file.flush()
|
||||||
finally:
|
finally:
|
||||||
if self._opened and self._file:
|
file = self._file
|
||||||
self._file.close()
|
|
||||||
self._file = None
|
self._file = None
|
||||||
|
if self._opened:
|
||||||
|
file.close()
|
||||||
|
|
||||||
#
|
#
|
||||||
# private methods
|
# private methods
|
||||||
|
@ -449,26 +449,26 @@ class _Stream:
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.mode == "w" and self.comptype != "tar":
|
|
||||||
self.buf += self.cmp.flush()
|
|
||||||
|
|
||||||
if self.mode == "w" and self.buf:
|
|
||||||
self.fileobj.write(self.buf)
|
|
||||||
self.buf = b""
|
|
||||||
if self.comptype == "gz":
|
|
||||||
# The native zlib crc is an unsigned 32-bit integer, but
|
|
||||||
# the Python wrapper implicitly casts that to a signed C
|
|
||||||
# long. So, on a 32-bit box self.crc may "look negative",
|
|
||||||
# while the same crc on a 64-bit box may "look positive".
|
|
||||||
# To avoid irksome warnings from the `struct` module, force
|
|
||||||
# it to look positive on all boxes.
|
|
||||||
self.fileobj.write(struct.pack("<L", self.crc & 0xffffffff))
|
|
||||||
self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFF))
|
|
||||||
|
|
||||||
if not self._extfileobj:
|
|
||||||
self.fileobj.close()
|
|
||||||
|
|
||||||
self.closed = True
|
self.closed = True
|
||||||
|
try:
|
||||||
|
if self.mode == "w" and self.comptype != "tar":
|
||||||
|
self.buf += self.cmp.flush()
|
||||||
|
|
||||||
|
if self.mode == "w" and self.buf:
|
||||||
|
self.fileobj.write(self.buf)
|
||||||
|
self.buf = b""
|
||||||
|
if self.comptype == "gz":
|
||||||
|
# The native zlib crc is an unsigned 32-bit integer, but
|
||||||
|
# the Python wrapper implicitly casts that to a signed C
|
||||||
|
# long. So, on a 32-bit box self.crc may "look negative",
|
||||||
|
# while the same crc on a 64-bit box may "look positive".
|
||||||
|
# To avoid irksome warnings from the `struct` module, force
|
||||||
|
# it to look positive on all boxes.
|
||||||
|
self.fileobj.write(struct.pack("<L", self.crc & 0xffffffff))
|
||||||
|
self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFF))
|
||||||
|
finally:
|
||||||
|
if not self._extfileobj:
|
||||||
|
self.fileobj.close()
|
||||||
|
|
||||||
def _init_read_gz(self):
|
def _init_read_gz(self):
|
||||||
"""Initialize for reading a gzip compressed fileobj.
|
"""Initialize for reading a gzip compressed fileobj.
|
||||||
@ -1714,18 +1714,19 @@ class TarFile(object):
|
|||||||
if self.closed:
|
if self.closed:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.mode in "aw":
|
|
||||||
self.fileobj.write(NUL * (BLOCKSIZE * 2))
|
|
||||||
self.offset += (BLOCKSIZE * 2)
|
|
||||||
# fill up the end with zero-blocks
|
|
||||||
# (like option -b20 for tar does)
|
|
||||||
blocks, remainder = divmod(self.offset, RECORDSIZE)
|
|
||||||
if remainder > 0:
|
|
||||||
self.fileobj.write(NUL * (RECORDSIZE - remainder))
|
|
||||||
|
|
||||||
if not self._extfileobj:
|
|
||||||
self.fileobj.close()
|
|
||||||
self.closed = True
|
self.closed = True
|
||||||
|
try:
|
||||||
|
if self.mode in "aw":
|
||||||
|
self.fileobj.write(NUL * (BLOCKSIZE * 2))
|
||||||
|
self.offset += (BLOCKSIZE * 2)
|
||||||
|
# fill up the end with zero-blocks
|
||||||
|
# (like option -b20 for tar does)
|
||||||
|
blocks, remainder = divmod(self.offset, RECORDSIZE)
|
||||||
|
if remainder > 0:
|
||||||
|
self.fileobj.write(NUL * (RECORDSIZE - remainder))
|
||||||
|
finally:
|
||||||
|
if not self._extfileobj:
|
||||||
|
self.fileobj.close()
|
||||||
|
|
||||||
def getmember(self, name):
|
def getmember(self, name):
|
||||||
"""Return a TarInfo object for member `name'. If `name' can not be
|
"""Return a TarInfo object for member `name'. If `name' can not be
|
||||||
|
@ -261,12 +261,13 @@ class Telnet:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the connection."""
|
"""Close the connection."""
|
||||||
if self.sock:
|
sock = self.sock
|
||||||
self.sock.close()
|
self.sock = None
|
||||||
self.sock = 0
|
self.eof = True
|
||||||
self.eof = 1
|
|
||||||
self.iacseq = b''
|
self.iacseq = b''
|
||||||
self.sb = 0
|
self.sb = 0
|
||||||
|
if sock:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
def get_socket(self):
|
def get_socket(self):
|
||||||
"""Return the socket object used internally."""
|
"""Return the socket object used internally."""
|
||||||
|
@ -357,9 +357,11 @@ class _TemporaryFileCloser:
|
|||||||
def close(self, unlink=_os.unlink):
|
def close(self, unlink=_os.unlink):
|
||||||
if not self.close_called and self.file is not None:
|
if not self.close_called and self.file is not None:
|
||||||
self.close_called = True
|
self.close_called = True
|
||||||
self.file.close()
|
try:
|
||||||
if self.delete:
|
self.file.close()
|
||||||
unlink(self.name)
|
finally:
|
||||||
|
if self.delete:
|
||||||
|
unlink(self.name)
|
||||||
|
|
||||||
# Need to ensure the file is deleted on __del__
|
# Need to ensure the file is deleted on __del__
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
@ -43,11 +43,15 @@ class addclosehook(addbase):
|
|||||||
self.hookargs = hookargs
|
self.hookargs = hookargs
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.closehook:
|
try:
|
||||||
self.closehook(*self.hookargs)
|
closehook = self.closehook
|
||||||
self.closehook = None
|
hookargs = self.hookargs
|
||||||
self.hookargs = None
|
if closehook:
|
||||||
super(addclosehook, self).close()
|
self.closehook = None
|
||||||
|
self.hookargs = None
|
||||||
|
closehook(*hookargs)
|
||||||
|
finally:
|
||||||
|
super(addclosehook, self).close()
|
||||||
|
|
||||||
|
|
||||||
class addinfo(addbase):
|
class addinfo(addbase):
|
||||||
|
22
Lib/wave.py
22
Lib/wave.py
@ -186,10 +186,11 @@ class Wave_read:
|
|||||||
self._soundpos = 0
|
self._soundpos = 0
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self._i_opened_the_file:
|
|
||||||
self._i_opened_the_file.close()
|
|
||||||
self._i_opened_the_file = None
|
|
||||||
self._file = None
|
self._file = None
|
||||||
|
file = self._i_opened_the_file
|
||||||
|
if file:
|
||||||
|
self._i_opened_the_file = None
|
||||||
|
file.close()
|
||||||
|
|
||||||
def tell(self):
|
def tell(self):
|
||||||
return self._soundpos
|
return self._soundpos
|
||||||
@ -428,17 +429,18 @@ class Wave_write:
|
|||||||
self._patchheader()
|
self._patchheader()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self._file:
|
try:
|
||||||
try:
|
if self._file:
|
||||||
self._ensure_header_written(0)
|
self._ensure_header_written(0)
|
||||||
if self._datalength != self._datawritten:
|
if self._datalength != self._datawritten:
|
||||||
self._patchheader()
|
self._patchheader()
|
||||||
self._file.flush()
|
self._file.flush()
|
||||||
finally:
|
finally:
|
||||||
self._file = None
|
self._file = None
|
||||||
if self._i_opened_the_file:
|
file = self._i_opened_the_file
|
||||||
self._i_opened_the_file.close()
|
if file:
|
||||||
self._i_opened_the_file = None
|
self._i_opened_the_file = None
|
||||||
|
file.close()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Internal methods.
|
# Internal methods.
|
||||||
|
@ -211,22 +211,24 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
|
|||||||
self._err_handler.fatalError(exc)
|
self._err_handler.fatalError(exc)
|
||||||
|
|
||||||
def close(self):
|
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
|
# If we are completing an external entity, do nothing here
|
||||||
return
|
return
|
||||||
self.feed("", isFinal = 1)
|
|
||||||
self._cont_handler.endDocument()
|
|
||||||
self._parsing = 0
|
|
||||||
# break cycle created by expat handlers pointing to our methods
|
|
||||||
self._parser = None
|
|
||||||
try:
|
try:
|
||||||
file = self._source.getCharacterStream()
|
self.feed("", isFinal = 1)
|
||||||
if file is not None:
|
self._cont_handler.endDocument()
|
||||||
file.close()
|
|
||||||
finally:
|
finally:
|
||||||
file = self._source.getByteStream()
|
self._parsing = 0
|
||||||
if file is not None:
|
# break cycle created by expat handlers pointing to our methods
|
||||||
file.close()
|
self._parser = None
|
||||||
|
try:
|
||||||
|
file = self._source.getCharacterStream()
|
||||||
|
if file is not None:
|
||||||
|
file.close()
|
||||||
|
finally:
|
||||||
|
file = self._source.getByteStream()
|
||||||
|
if file is not None:
|
||||||
|
file.close()
|
||||||
|
|
||||||
def _reset_cont_handler(self):
|
def _reset_cont_handler(self):
|
||||||
self._parser.ProcessingInstructionHandler = \
|
self._parser.ProcessingInstructionHandler = \
|
||||||
|
@ -438,8 +438,13 @@ class ExpatParser:
|
|||||||
self._parser.Parse(data, 0)
|
self._parser.Parse(data, 0)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._parser.Parse("", 1) # end of data
|
try:
|
||||||
del self._target, self._parser # get rid of circular references
|
parser = self._parser
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del self._target, self._parser # get rid of circular references
|
||||||
|
parser.Parse(b"", True) # end of data
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# XML-RPC marshalling and unmarshalling code
|
# XML-RPC marshalling and unmarshalling code
|
||||||
@ -1065,8 +1070,10 @@ class GzipDecodedResponse(gzip.GzipFile if gzip else object):
|
|||||||
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
|
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
gzip.GzipFile.close(self)
|
try:
|
||||||
self.io.close()
|
gzip.GzipFile.close(self)
|
||||||
|
finally:
|
||||||
|
self.io.close()
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
@ -1221,9 +1228,10 @@ class Transport:
|
|||||||
# Used in the event of socket errors.
|
# Used in the event of socket errors.
|
||||||
#
|
#
|
||||||
def close(self):
|
def close(self):
|
||||||
if self._connection[1]:
|
host, connection = self._connection
|
||||||
self._connection[1].close()
|
if connection:
|
||||||
self._connection = (None, None)
|
self._connection = (None, None)
|
||||||
|
connection.close()
|
||||||
|
|
||||||
##
|
##
|
||||||
# Send HTTP request.
|
# Send HTTP request.
|
||||||
|
@ -19,6 +19,10 @@ Core and Builtins
|
|||||||
Library
|
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 #23400: Raise same exception on both Python 2 and 3 if sem_open is not
|
- Issue #23400: Raise same exception on both Python 2 and 3 if sem_open is not
|
||||||
available. Patch by Davin Potts.
|
available. Patch by Davin Potts.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user