From: Serhiy Storchaka Date: Fri, 10 Apr 2015 10:29:28 +0000 (+0300) Subject: Issue #23865: close() methods in multiple modules now are idempotent and more X-Git-Tag: v3.5.0a4~123 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2116b12da59f77358cc539b90f58a3cdea43c2fd;p=thirdparty%2FPython%2Fcpython.git 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. --- 2116b12da59f77358cc539b90f58a3cdea43c2fd diff --cc Lib/fileinput.py index 87758ad82b30,8af4a57f021f..af810d1d732e --- a/Lib/fileinput.py +++ b/Lib/fileinput.py @@@ -275,29 -277,31 +277,31 @@@ class FileInput def nextfile(self): savestdout = self._savestdout -- self._savestdout = 0 ++ self._savestdout = None if savestdout: sys.stdout = savestdout output = self._output -- self._output = 0 - if output: - output.close() - - 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._output = None + try: + if output: + output.close() + finally: + file = self._file - self._file = 0 ++ self._file = None + try: + if file and not self._isstdin: + file.close() + finally: + backupfilename = self._backupfilename - self._backupfilename = 0 ++ self._backupfilename = None + if backupfilename and not self._backup: + try: os.unlink(backupfilename) + except OSError: pass + + self._isstdin = False + self._buffer = [] + self._bufindex = 0 def readline(self): try: diff --cc Lib/mailbox.py index e7f31df1e539,4e42ad24063f..24d4aec8a48f --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@@ -1966,9 -1970,9 +1970,11 @@@ class _ProxyFile def close(self): """Close the file.""" if hasattr(self, '_file'): -- if hasattr(self._file, 'close'): -- self._file.close() -- del self._file ++ try: ++ if hasattr(self._file, 'close'): ++ self._file.close() ++ finally: ++ del self._file def _read(self, size, read_method): """Read size bytes using read_method.""" diff --cc Lib/selectors.py index 44a61508feb1,7b6da2986399..e17ea363c8b5 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@@ -439,67 -445,12 +439,71 @@@ if hasattr(select, 'epoll') return ready def close(self): - self._epoll.close() - super().close() + try: + self._epoll.close() + finally: + super().close() +if hasattr(select, 'devpoll'): + + class DevpollSelector(_BaseSelectorImpl): + """Solaris /dev/poll selector.""" + + def __init__(self): + super().__init__() + self._devpoll = select.devpoll() + + def fileno(self): + return self._devpoll.fileno() + + def register(self, fileobj, events, data=None): + key = super().register(fileobj, events, data) + poll_events = 0 + if events & EVENT_READ: + poll_events |= select.POLLIN + if events & EVENT_WRITE: + poll_events |= select.POLLOUT + self._devpoll.register(key.fd, poll_events) + return key + + def unregister(self, fileobj): + key = super().unregister(fileobj) + self._devpoll.unregister(key.fd) + return key + + def select(self, timeout=None): + if timeout is None: + timeout = None + elif timeout <= 0: + timeout = 0 + else: + # devpoll() has a resolution of 1 millisecond, round away from + # zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) + + fd_event_list = self._devpoll.poll(timeout) + + ready = [] + for fd, event in fd_event_list: + events = 0 + if event & ~select.POLLIN: + events |= EVENT_WRITE + if event & ~select.POLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + def close(self): - self._devpoll.close() - super().close() ++ try: ++ self._devpoll.close() ++ finally: ++ super().close() + + if hasattr(select, 'kqueue'): class KqueueSelector(_BaseSelectorImpl): @@@ -566,12 -519,13 +570,14 @@@ 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. +# Choose the best implementation, roughly: +# epoll|kqueue|devpoll > poll > select. # select() also can't accept a FD > FD_SETSIZE (usually around 1024) if 'KqueueSelector' in globals(): DefaultSelector = KqueueSelector diff --cc Lib/telnetlib.py index eebb95290272,51738f0d125d..72dabc76e0cd --- a/Lib/telnetlib.py +++ b/Lib/telnetlib.py @@@ -261,12 -264,13 +261,13 @@@ class Telnet def close(self): """Close the connection.""" - if self.sock: - self.sock.close() - self.sock = 0 - self.eof = 1 + sock = self.sock - self.sock = 0 - self.eof = 1 ++ self.sock = None ++ self.eof = True self.iacseq = b'' self.sb = 0 + if sock: + sock.close() def get_socket(self): """Return the socket object used internally.""" diff --cc Lib/xml/sax/expatreader.py index 65ac7e30434b,29d75ab4ac45..1795b23af60a --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@@ -211,22 -211,19 +211,24 @@@ class ExpatParser(xmlreader.Incremental 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 try: - file = self._source.getCharacterStream() - if file is not None: - file.close() + self.feed("", isFinal = 1) + self._cont_handler.endDocument() finally: - file = self._source.getByteStream() - if file is not None: - file.close() + 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: ++ 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): self._parser.ProcessingInstructionHandler = \ diff --cc Misc/NEWS index b62e72aeea52,539252e6823a..7f913494cfcf --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -19,17 -24,10 +19,21 @@@ Core and Builtin 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 + available. Patch by Davin Potts. + +- Issue #10838: The subprocess now module includes SubprocessError and + TimeoutError in its list of exported names for the users wild enough + to use "from subprocess import *". + +- Issue #23411: Added DefragResult, ParseResult, SplitResult, DefragResultBytes, + ParseResultBytes, and SplitResultBytes to urllib.parse.__all__. + Patch by Martin Panter. + - Issue #23881: urllib.request.ftpwrapper constructor now closes the socket if the FTP connection failed to fix a ResourceWarning.