]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #23865: close() methods in multiple modules now are idempotent and more
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 10 Apr 2015 10:29:28 +0000 (13:29 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Fri, 10 Apr 2015 10:29:28 +0000 (13:29 +0300)
robust at shutdown. If needs to release multiple resources, they are released
even if errors are occured.

19 files changed:
1  2 
Lib/binhex.py
Lib/dbm/dumb.py
Lib/fileinput.py
Lib/ftplib.py
Lib/gzip.py
Lib/http/client.py
Lib/logging/__init__.py
Lib/logging/handlers.py
Lib/mailbox.py
Lib/multiprocessing/connection.py
Lib/multiprocessing/queues.py
Lib/selectors.py
Lib/smtplib.py
Lib/tarfile.py
Lib/telnetlib.py
Lib/tempfile.py
Lib/xml/sax/expatreader.py
Lib/xmlrpc/client.py
Misc/NEWS

diff --cc Lib/binhex.py
Simple merge
diff --cc Lib/dbm/dumb.py
Simple merge
index 87758ad82b3026e87e0391e86edd1f9fc6661a92,8af4a57f021fa5c191e8131ca0357f1bf3bebc6a..af810d1d732e3683a450c0c31caaab605cebacf6
@@@ -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/ftplib.py
Simple merge
diff --cc Lib/gzip.py
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc Lib/mailbox.py
index e7f31df1e53920ab65b370f74654c37957f36fd6,4e42ad24063fa1fda73972717ed035a813b369a9..24d4aec8a48ff377ba89f7d809071a5108da196f
@@@ -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."""
Simple merge
Simple merge
index 44a61508feb1709277eff9d62379ad0f891d4c48,7b6da298639977fc7a7f12a75817cd9a23b4703f..e17ea363c8b5f993ce6c26423b4cff37033d49e0
@@@ -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()
  
  
-             self._devpoll.close()
-             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):
++            try:
++                self._devpoll.close()
++            finally:
++                super().close()
 +
 +
  if hasattr(select, 'kqueue'):
  
      class KqueueSelector(_BaseSelectorImpl):
              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/smtplib.py
Simple merge
diff --cc Lib/tarfile.py
Simple merge
index eebb95290272bc01b0908d42c599e5869576f0e0,51738f0d125d991ab31206993322dc1b03065274..72dabc76e0cd4895e083e80cfac604d547c833f2
@@@ -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/tempfile.py
Simple merge
index 65ac7e30434baffa2c1a1bbab9c328ed8b52b24b,29d75ab4ac45aa3840815cb2579c5c08dfddd1e1..1795b23af60a76c79b22f0c9e040c66a4cbcefc0
@@@ -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 = \
Simple merge
diff --cc Misc/NEWS
index b62e72aeea5269575b0886e39387d99514a28084,539252e6823a2eac1b8b1e546153037b3fcb8e7d..7f913494cfcf0f7db2dc363bfe9c5c63c29667c9
+++ 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.