mirror of
https://github.com/python/cpython
synced 2024-10-14 09:01:41 +00:00
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
842f00e725
commit
7e7a3dba5f
|
@ -356,7 +356,10 @@ def rewind(self):
|
|||
self._soundpos = 0
|
||||
|
||||
def close(self):
|
||||
self._file.close()
|
||||
file = self._file
|
||||
if file is not None:
|
||||
self._file = None
|
||||
file.close()
|
||||
|
||||
def tell(self):
|
||||
return self._soundpos
|
||||
|
|
|
@ -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
|
||||
|
@ -213,16 +214,21 @@ def write_rsrc(self, data):
|
|||
self._write(data)
|
||||
|
||||
def close(self):
|
||||
if self.state < _DID_DATA:
|
||||
self.close_data()
|
||||
if self.state != _DID_DATA:
|
||||
raise Error('Close at the wrong time')
|
||||
if self.rlen != 0:
|
||||
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
|
||||
self._writecrc()
|
||||
self.ofp.close()
|
||||
self.state = None
|
||||
del self.ofp
|
||||
if self.state is None:
|
||||
return
|
||||
try:
|
||||
if self.state < _DID_DATA:
|
||||
self.close_data()
|
||||
if self.state != _DID_DATA:
|
||||
raise Error('Close at the wrong time')
|
||||
if self.rlen != 0:
|
||||
raise Error("Incorrect resource-datasize, diff=%r" % (self.rlen,))
|
||||
self._writecrc()
|
||||
finally:
|
||||
self.state = None
|
||||
ofp = self.ofp
|
||||
del self.ofp
|
||||
ofp.close()
|
||||
|
||||
def binhex(inp, out):
|
||||
"""binhex(infilename, outfilename): create binhex-encoded copy of a file"""
|
||||
|
@ -436,11 +442,15 @@ def read_rsrc(self, *n):
|
|||
return self._read(n)
|
||||
|
||||
def close(self):
|
||||
if self.rlen:
|
||||
dummy = self.read_rsrc(self.rlen)
|
||||
self._checkcrc()
|
||||
self.state = _DID_RSRC
|
||||
self.ifp.close()
|
||||
if self.state is None:
|
||||
return
|
||||
try:
|
||||
if self.rlen:
|
||||
dummy = self.read_rsrc(self.rlen)
|
||||
self._checkcrc()
|
||||
finally:
|
||||
self.state = None
|
||||
self.ifp.close()
|
||||
|
||||
def hexbin(inp, out):
|
||||
"""hexbin(infilename, outfilename) - Decode binhexed file"""
|
||||
|
|
|
@ -85,8 +85,10 @@ def getsize(self):
|
|||
|
||||
def close(self):
|
||||
if not self.closed:
|
||||
self.skip()
|
||||
self.closed = True
|
||||
try:
|
||||
self.skip()
|
||||
finally:
|
||||
self.closed = True
|
||||
|
||||
def isatty(self):
|
||||
if self.closed:
|
||||
|
|
|
@ -248,8 +248,10 @@ def __len__(self):
|
|||
raise error('DBM object has already been closed') from None
|
||||
|
||||
def close(self):
|
||||
self._commit()
|
||||
self._index = self._datfile = self._dirfile = self._bakfile = None
|
||||
try:
|
||||
self._commit()
|
||||
finally:
|
||||
self._index = self._datfile = self._dirfile = self._bakfile = None
|
||||
|
||||
__del__ = close
|
||||
|
||||
|
|
|
@ -118,10 +118,11 @@ def open(self, filename):
|
|||
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):
|
||||
outmsg = []
|
||||
|
|
|
@ -238,8 +238,10 @@ def __del__(self):
|
|||
self.close()
|
||||
|
||||
def close(self):
|
||||
self.nextfile()
|
||||
self._files = ()
|
||||
try:
|
||||
self.nextfile()
|
||||
finally:
|
||||
self._files = ()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
@ -281,23 +283,25 @@ def nextfile(self):
|
|||
|
||||
output = self._output
|
||||
self._output = 0
|
||||
if output:
|
||||
output.close()
|
||||
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:
|
||||
try: os.unlink(backupfilename)
|
||||
except OSError: pass
|
||||
|
||||
file = self._file
|
||||
self._file = 0
|
||||
if file and not self._isstdin:
|
||||
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
|
||||
self._isstdin = False
|
||||
self._buffer = []
|
||||
self._bufindex = 0
|
||||
|
||||
def readline(self):
|
||||
try:
|
||||
|
|
|
@ -667,11 +667,16 @@ def quit(self):
|
|||
|
||||
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
|
||||
|
|
26
Lib/gzip.py
26
Lib/gzip.py
|
@ -500,19 +500,21 @@ def closed(self):
|
|||
return self.fileobj is None
|
||||
|
||||
def close(self):
|
||||
if self.fileobj is None:
|
||||
fileobj = self.fileobj
|
||||
if fileobj is None:
|
||||
return
|
||||
if self.mode == WRITE:
|
||||
self.fileobj.write(self.compress.flush())
|
||||
write32u(self.fileobj, self.crc)
|
||||
# self.size may exceed 2GB, or even 4GB
|
||||
write32u(self.fileobj, self.size & 0xffffffff)
|
||||
self.fileobj = None
|
||||
elif self.mode == READ:
|
||||
self.fileobj = None
|
||||
if self.myfileobj:
|
||||
self.myfileobj.close()
|
||||
self.myfileobj = None
|
||||
self.fileobj = None
|
||||
try:
|
||||
if self.mode == WRITE:
|
||||
fileobj.write(self.compress.flush())
|
||||
write32u(fileobj, self.crc)
|
||||
# self.size may exceed 2GB, or even 4GB
|
||||
write32u(fileobj, self.size & 0xffffffff)
|
||||
finally:
|
||||
myfileobj = self.myfileobj
|
||||
if myfileobj:
|
||||
self.myfileobj = None
|
||||
myfileobj.close()
|
||||
|
||||
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
|
||||
self._check_closed()
|
||||
|
|
|
@ -492,9 +492,11 @@ def _close_conn(self):
|
|||
fp.close()
|
||||
|
||||
def close(self):
|
||||
super().close() # set "closed" flag
|
||||
if self.fp:
|
||||
self._close_conn()
|
||||
try:
|
||||
super().close() # set "closed" flag
|
||||
finally:
|
||||
if self.fp:
|
||||
self._close_conn()
|
||||
|
||||
# These implementations are for the benefit of io.BufferedReader.
|
||||
|
||||
|
@ -873,13 +875,17 @@ def connect(self):
|
|||
|
||||
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.
|
||||
|
|
|
@ -1011,14 +1011,19 @@ def close(self):
|
|||
"""
|
||||
self.acquire()
|
||||
try:
|
||||
if self.stream:
|
||||
self.flush()
|
||||
if hasattr(self.stream, "close"):
|
||||
self.stream.close()
|
||||
self.stream = None
|
||||
# Issue #19523: call unconditionally to
|
||||
# prevent a handler leak when delay is set
|
||||
StreamHandler.close(self)
|
||||
try:
|
||||
if self.stream:
|
||||
try:
|
||||
self.flush()
|
||||
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)
|
||||
finally:
|
||||
self.release()
|
||||
|
||||
|
|
|
@ -627,9 +627,10 @@ def close(self):
|
|||
"""
|
||||
self.acquire()
|
||||
try:
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
sock = self.sock
|
||||
if sock:
|
||||
self.sock = None
|
||||
sock.close()
|
||||
logging.Handler.close(self)
|
||||
finally:
|
||||
self.release()
|
||||
|
@ -1213,8 +1214,10 @@ def close(self):
|
|||
|
||||
This version just flushes and chains to the parent class' close().
|
||||
"""
|
||||
self.flush()
|
||||
logging.Handler.close(self)
|
||||
try:
|
||||
self.flush()
|
||||
finally:
|
||||
logging.Handler.close(self)
|
||||
|
||||
class MemoryHandler(BufferingHandler):
|
||||
"""
|
||||
|
@ -1268,13 +1271,15 @@ def close(self):
|
|||
"""
|
||||
Flush, set the target to None and lose the buffer.
|
||||
"""
|
||||
self.flush()
|
||||
self.acquire()
|
||||
try:
|
||||
self.target = None
|
||||
BufferingHandler.close(self)
|
||||
self.flush()
|
||||
finally:
|
||||
self.release()
|
||||
self.acquire()
|
||||
try:
|
||||
self.target = None
|
||||
BufferingHandler.close(self)
|
||||
finally:
|
||||
self.release()
|
||||
|
||||
|
||||
class QueueHandler(logging.Handler):
|
||||
|
|
|
@ -722,10 +722,14 @@ def _post_message_hook(self, f):
|
|||
|
||||
def close(self):
|
||||
"""Flush and close the mailbox."""
|
||||
self.flush()
|
||||
if self._locked:
|
||||
self.unlock()
|
||||
self._file.close() # Sync has been done by self.flush() above.
|
||||
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):
|
||||
"""Return (start, stop) or raise KeyError."""
|
||||
|
|
|
@ -469,9 +469,10 @@ def close(self):
|
|||
'''
|
||||
Close the bound socket or named pipe of `self`.
|
||||
'''
|
||||
if self._listener is not None:
|
||||
self._listener.close()
|
||||
listener = self._listener
|
||||
if listener is not None:
|
||||
self._listener = None
|
||||
listener.close()
|
||||
|
||||
address = property(lambda self: self._listener._address)
|
||||
last_accepted = property(lambda self: self._listener._last_accepted)
|
||||
|
@ -609,9 +610,13 @@ def accept(self):
|
|||
return Connection(s.detach())
|
||||
|
||||
def close(self):
|
||||
self._socket.close()
|
||||
if self._unlink is not None:
|
||||
self._unlink()
|
||||
try:
|
||||
self._socket.close()
|
||||
finally:
|
||||
unlink = self._unlink
|
||||
if unlink is not None:
|
||||
self._unlink = None
|
||||
unlink()
|
||||
|
||||
|
||||
def SocketClient(address):
|
||||
|
|
|
@ -133,9 +133,13 @@ def put_nowait(self, obj):
|
|||
|
||||
def close(self):
|
||||
self._closed = True
|
||||
self._reader.close()
|
||||
if self._close:
|
||||
self._close()
|
||||
try:
|
||||
self._reader.close()
|
||||
finally:
|
||||
close = self._close
|
||||
if close:
|
||||
self._close = None
|
||||
close()
|
||||
|
||||
def join_thread(self):
|
||||
debug('Queue.join_thread()')
|
||||
|
|
|
@ -276,18 +276,23 @@ def quit(self):
|
|||
|
||||
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:
|
||||
try:
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
except OSError as e:
|
||||
# The server might already have closed the connection
|
||||
if e.errno != errno.ENOTCONN:
|
||||
raise
|
||||
finally:
|
||||
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:
|
||||
try:
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
except OSError as e:
|
||||
# The server might already have closed the connection
|
||||
if e.errno != errno.ENOTCONN:
|
||||
raise
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
#__del__ = quit
|
||||
|
||||
|
|
|
@ -445,8 +445,10 @@ def select(self, timeout=None):
|
|||
return ready
|
||||
|
||||
def close(self):
|
||||
self._epoll.close()
|
||||
super().close()
|
||||
try:
|
||||
self._epoll.close()
|
||||
finally:
|
||||
super().close()
|
||||
|
||||
|
||||
if hasattr(select, 'kqueue'):
|
||||
|
@ -517,8 +519,10 @@ def select(self, timeout=None):
|
|||
return ready
|
||||
|
||||
def close(self):
|
||||
self._kqueue.close()
|
||||
super().close()
|
||||
try:
|
||||
self._kqueue.close()
|
||||
finally:
|
||||
super().close()
|
||||
|
||||
|
||||
# Choose the best implementation: roughly, epoll|kqueue > poll > select.
|
||||
|
|
|
@ -138,17 +138,21 @@ def __exit__(self, type, value, traceback):
|
|||
self.close()
|
||||
|
||||
def close(self):
|
||||
self.sync()
|
||||
if self.dict is None:
|
||||
return
|
||||
try:
|
||||
self.dict.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
# Catch errors that may happen when close is called from __del__
|
||||
# because CPython is in interpreter shutdown.
|
||||
try:
|
||||
self.dict = _ClosedDict()
|
||||
except (NameError, TypeError):
|
||||
self.dict = None
|
||||
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:
|
||||
self.dict = None
|
||||
|
||||
def __del__(self):
|
||||
if not hasattr(self, 'writeback'):
|
||||
|
|
|
@ -855,12 +855,16 @@ def send_message(self, msg, from_addr=None, to_addrs=None,
|
|||
|
||||
def close(self):
|
||||
"""Close the connection to the SMTP server."""
|
||||
if self.file:
|
||||
self.file.close()
|
||||
self.file = None
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
try:
|
||||
file = self.file
|
||||
self.file = None
|
||||
if file:
|
||||
file.close()
|
||||
finally:
|
||||
sock = self.sock
|
||||
self.sock = None
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
def quit(self):
|
||||
"""Terminate the SMTP session."""
|
||||
|
|
13
Lib/sunau.py
13
Lib/sunau.py
|
@ -295,9 +295,11 @@ def setpos(self, pos):
|
|||
self._soundpos = pos
|
||||
|
||||
def close(self):
|
||||
if self._opened and self._file:
|
||||
self._file.close()
|
||||
self._file = None
|
||||
file = self._file
|
||||
if file:
|
||||
self._file = None
|
||||
if self._opened:
|
||||
file.close()
|
||||
|
||||
class Au_write:
|
||||
|
||||
|
@ -438,9 +440,10 @@ def close(self):
|
|||
self._patchheader()
|
||||
self._file.flush()
|
||||
finally:
|
||||
if self._opened and self._file:
|
||||
self._file.close()
|
||||
file = self._file
|
||||
self._file = None
|
||||
if self._opened:
|
||||
file.close()
|
||||
|
||||
#
|
||||
# private methods
|
||||
|
|
|
@ -449,26 +449,26 @@ def close(self):
|
|||
if self.closed:
|
||||
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
|
||||
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):
|
||||
"""Initialize for reading a gzip compressed fileobj.
|
||||
|
@ -1705,18 +1705,19 @@ def close(self):
|
|||
if self.closed:
|
||||
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
|
||||
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):
|
||||
"""Return a TarInfo object for member `name'. If `name' can not be
|
||||
|
|
|
@ -264,12 +264,13 @@ def set_debuglevel(self, debuglevel):
|
|||
|
||||
def close(self):
|
||||
"""Close the connection."""
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
sock = self.sock
|
||||
self.sock = 0
|
||||
self.eof = 1
|
||||
self.iacseq = b''
|
||||
self.sb = 0
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
def get_socket(self):
|
||||
"""Return the socket object used internally."""
|
||||
|
|
|
@ -357,9 +357,11 @@ def __init__(self, file, name, delete=True):
|
|||
def close(self, unlink=_os.unlink):
|
||||
if not self.close_called and self.file is not None:
|
||||
self.close_called = True
|
||||
self.file.close()
|
||||
if self.delete:
|
||||
unlink(self.name)
|
||||
try:
|
||||
self.file.close()
|
||||
finally:
|
||||
if self.delete:
|
||||
unlink(self.name)
|
||||
|
||||
# Need to ensure the file is deleted on __del__
|
||||
def __del__(self):
|
||||
|
|
|
@ -43,11 +43,15 @@ def __init__(self, fp, closehook, *hookargs):
|
|||
self.hookargs = hookargs
|
||||
|
||||
def close(self):
|
||||
if self.closehook:
|
||||
self.closehook(*self.hookargs)
|
||||
self.closehook = None
|
||||
self.hookargs = None
|
||||
super(addclosehook, self).close()
|
||||
try:
|
||||
closehook = self.closehook
|
||||
hookargs = self.hookargs
|
||||
if closehook:
|
||||
self.closehook = None
|
||||
self.hookargs = None
|
||||
closehook(*hookargs)
|
||||
finally:
|
||||
super(addclosehook, self).close()
|
||||
|
||||
|
||||
class addinfo(addbase):
|
||||
|
|
22
Lib/wave.py
22
Lib/wave.py
|
@ -186,10 +186,11 @@ def rewind(self):
|
|||
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
|
||||
|
@ -428,17 +429,18 @@ def writeframes(self, data):
|
|||
self._patchheader()
|
||||
|
||||
def close(self):
|
||||
if self._file:
|
||||
try:
|
||||
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()
|
||||
self._i_opened_the_file = None
|
||||
finally:
|
||||
self._file = None
|
||||
file = self._i_opened_the_file
|
||||
if file:
|
||||
self._i_opened_the_file = None
|
||||
file.close()
|
||||
|
||||
#
|
||||
# Internal methods.
|
||||
|
|
|
@ -211,17 +211,19 @@ def feed(self, data, isFinal = 0):
|
|||
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
|
||||
self.feed("", isFinal = 1)
|
||||
self._cont_handler.endDocument()
|
||||
self._parsing = 0
|
||||
# break cycle created by expat handlers pointing to our methods
|
||||
self._parser = None
|
||||
bs = self._source.getByteStream()
|
||||
if bs is not None:
|
||||
bs.close()
|
||||
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
|
||||
bs = self._source.getByteStream()
|
||||
if bs is not None:
|
||||
bs.close()
|
||||
|
||||
def _reset_cont_handler(self):
|
||||
self._parser.ProcessingInstructionHandler = \
|
||||
|
|
|
@ -446,8 +446,13 @@ def feed(self, data):
|
|||
self._parser.Parse(data, 0)
|
||||
|
||||
def close(self):
|
||||
self._parser.Parse("", 1) # end of data
|
||||
del self._target, self._parser # get rid of circular references
|
||||
try:
|
||||
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
|
||||
|
@ -1079,8 +1084,10 @@ def __init__(self, response):
|
|||
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
|
||||
|
||||
def close(self):
|
||||
gzip.GzipFile.close(self)
|
||||
self.io.close()
|
||||
try:
|
||||
gzip.GzipFile.close(self)
|
||||
finally:
|
||||
self.io.close()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -1235,9 +1242,10 @@ def make_connection(self, host):
|
|||
# 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 HTTP request.
|
||||
|
|
|
@ -24,6 +24,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.request.ftpwrapper constructor now closes the socket if
|
||||
the FTP connection failed to fix a ResourceWarning.
|
||||
|
||||
|
|
Loading…
Reference in a new issue