Merge heads
diff --git a/.gitignore b/.gitignore
index ba9ee85..3fe3259 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,7 +58,7 @@
 platform
 pybuilddir.txt
 pyconfig.h
-python
+python$
 python-config
 python-config.py
 python.exe
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index d520702..aaa37b8 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -383,7 +383,8 @@
 can't guarantee that the initializer is called.  The initializer isn't called
 when unpickling objects and it can be overridden.  Our initializer accepts
 arguments to provide initial values for our instance. Initializers always accept
-positional and keyword arguments.
+positional and keyword arguments. Initializers should return either 0 on
+success or -1 on error.
 
 Initializers can be called multiple times.  Anyone can call the :meth:`__init__`
 method on our objects.  For this reason, we have to be extra careful when
diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst
index d71a9b4..064728f 100644
--- a/Doc/faq/library.rst
+++ b/Doc/faq/library.rst
@@ -687,7 +687,8 @@
    ### connect and send the server a path
    req = urllib.request.urlopen('http://www.some-server.out-there'
                                 '/cgi-bin/some-cgi-script', data=qs)
-   msg, hdrs = req.read(), req.info()
+   with req:
+       msg, hdrs = req.read(), req.info()
 
 Note that in general for percent-encoded POST operations, query strings must be
 quoted using :func:`urllib.parse.urlencode`.  For example, to send
diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst
index abec053..01ae513 100644
--- a/Doc/howto/urllib2.rst
+++ b/Doc/howto/urllib2.rst
@@ -53,8 +53,8 @@
 The simplest way to use urllib.request is as follows::
 
     import urllib.request
-    response = urllib.request.urlopen('http://python.org/')
-    html = response.read()
+    with urllib.request.urlopen('http://python.org/') as response:
+       html = response.read()
 
 If you wish to retrieve a resource via URL and store it in a temporary location,
 you can do so via the :func:`~urllib.request.urlretrieve` function::
@@ -79,8 +79,8 @@
     import urllib.request
 
     req = urllib.request.Request('http://www.voidspace.org.uk')
-    response = urllib.request.urlopen(req)
-    the_page = response.read()
+    with urllib.request.urlopen(req) as response:
+       the_page = response.read()
 
 Note that urllib.request makes use of the same Request interface to handle all URL
 schemes.  For example, you can make an FTP request like so::
@@ -117,8 +117,8 @@
     data = urllib.parse.urlencode(values)
     data = data.encode('utf-8') # data should be bytes
     req = urllib.request.Request(url, data)
-    response = urllib.request.urlopen(req)
-    the_page = response.read()
+    with urllib.request.urlopen(req) as response:
+       the_page = response.read()
 
 Note that other encodings are sometimes required (e.g. for file upload from HTML
 forms - see `HTML Specification, Form Submission
@@ -183,8 +183,8 @@
     data  = urllib.parse.urlencode(values)
     data = data.encode('utf-8')
     req = urllib.request.Request(url, data, headers)
-    response = urllib.request.urlopen(req)
-    the_page = response.read()
+    with urllib.request.urlopen(req) as response:
+       the_page = response.read()
 
 The response also has two useful methods. See the section on `info and geturl`_
 which comes after we have a look at what happens when things go wrong.
diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst
index bd56696..48b4362 100644
--- a/Doc/library/concurrent.futures.rst
+++ b/Doc/library/concurrent.futures.rst
@@ -138,8 +138,8 @@
 
    # Retrieve a single page and report the url and contents
    def load_url(url, timeout):
-       conn = urllib.request.urlopen(url, timeout=timeout)
-       return conn.readall()
+       with urllib.request.urlopen(url, timeout=timeout) as conn:
+           return conn.read()
 
    # We can use a with statement to ensure threads are cleaned up promptly
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
index ec1dc4f..24e2a30 100644
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -106,8 +106,8 @@
       >>> PurePath('setup.py')      # Running on a Unix machine
       PurePosixPath('setup.py')
 
-   Each element of *pathsegments* can be either a string or bytes object
-   representing a path segment; it can also be another path object::
+   Each element of *pathsegments* can be either a string representing a
+   path segment, or another path object::
 
       >>> PurePath('foo', 'some/path', 'bar')
       PurePosixPath('foo/some/path/bar')
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 465bf8f..394bc9f 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -286,12 +286,14 @@
 
 .. function:: RAND_bytes(num)
 
-   Returns *num* cryptographically strong pseudo-random bytes. Raises an
+   Return *num* cryptographically strong pseudo-random bytes. Raises an
    :class:`SSLError` if the PRNG has not been seeded with enough data or if the
    operation is not supported by the current RAND method. :func:`RAND_status`
    can be used to check the status of the PRNG and :func:`RAND_add` can be used
    to seed the PRNG.
 
+   For almost all applications :func:`os.urandom` is preferable.
+
    Read the Wikipedia article, `Cryptographically secure pseudorandom number
    generator (CSPRNG)
    <http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator>`_,
@@ -301,7 +303,7 @@
 
 .. function:: RAND_pseudo_bytes(num)
 
-   Returns (bytes, is_cryptographic): bytes are *num* pseudo-random bytes,
+   Return (bytes, is_cryptographic): bytes are *num* pseudo-random bytes,
    is_cryptographic is ``True`` if the bytes generated are cryptographically
    strong. Raises an :class:`SSLError` if the operation is not supported by the
    current RAND method.
@@ -311,14 +313,16 @@
    for non-cryptographic purposes and for certain purposes in cryptographic
    protocols, but usually not for key generation etc.
 
+   For almost all applications :func:`os.urandom` is preferable.
+
    .. versionadded:: 3.3
 
 .. function:: RAND_status()
 
-   Returns ``True`` if the SSL pseudo-random number generator has been seeded with
-   'enough' randomness, and ``False`` otherwise.  You can use :func:`ssl.RAND_egd`
-   and :func:`ssl.RAND_add` to increase the randomness of the pseudo-random
-   number generator.
+   Return ``True`` if the SSL pseudo-random number generator has been seeded
+   with 'enough' randomness, and ``False`` otherwise.  You can use
+   :func:`ssl.RAND_egd` and :func:`ssl.RAND_add` to increase the randomness of
+   the pseudo-random number generator.
 
 .. function:: RAND_egd(path)
 
@@ -333,7 +337,7 @@
 
 .. function:: RAND_add(bytes, entropy)
 
-   Mixes the given *bytes* into the SSL pseudo-random number generator.  The
+   Mix the given *bytes* into the SSL pseudo-random number generator.  The
    parameter *entropy* (a float) is a lower bound on the entropy contained in
    string (so you can always use :const:`0.0`).  See :rfc:`1750` for more
    information on sources of entropy.
diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst
index 249396e..d878aac 100644
--- a/Doc/library/urllib.request.rst
+++ b/Doc/library/urllib.request.rst
@@ -1048,8 +1048,9 @@
 it. ::
 
    >>> import urllib.request
-   >>> f = urllib.request.urlopen('http://www.python.org/')
-   >>> print(f.read(300))
+   >>> with urllib.request.urlopen('http://www.python.org/') as f:
+   ...     print(f.read(300))
+   ...
    b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n\n\n<html
    xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n\n<head>\n
@@ -1091,8 +1092,9 @@
    >>> import urllib.request
    >>> req = urllib.request.Request(url='https://localhost/cgi-bin/test.cgi',
    ...                       data=b'This data is passed to stdin of the CGI')
-   >>> f = urllib.request.urlopen(req)
-   >>> print(f.read().decode('utf-8'))
+   >>> with urllib.request.urlopen(req) as f:
+   ...     print(f.read().decode('utf-8'))
+   ...
    Got Data: "This data is passed to stdin of the CGI"
 
 The code for the sample CGI used in the above example is::
@@ -1107,7 +1109,8 @@
     import urllib.request
     DATA=b'some data'
     req = urllib.request.Request(url='http://localhost:8080', data=DATA,method='PUT')
-    f = urllib.request.urlopen(req)
+    with urllib.request.urlopen(req) as f:
+        pass
     print(f.status)
     print(f.reason)
 
@@ -1173,8 +1176,10 @@
    >>> import urllib.request
    >>> import urllib.parse
    >>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
-   >>> f = urllib.request.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
-   >>> print(f.read().decode('utf-8'))
+   >>> url = "http://www.musi-cal.com/cgi-bin/query?%s" % params
+   >>> with urllib.request.urlopen(url) as f:
+   ...     print(f.read().decode('utf-8'))
+   ...
 
 The following example uses the ``POST`` method instead. Note that params output
 from urlencode is encoded to bytes before it is sent to urlopen as data::
@@ -1186,8 +1191,9 @@
    >>> request = urllib.request.Request("http://requestb.in/xrbl82xr")
    >>> # adding charset parameter to the Content-Type header.
    >>> request.add_header("Content-Type","application/x-www-form-urlencoded;charset=utf-8")
-   >>> f = urllib.request.urlopen(request, data)
-   >>> print(f.read().decode('utf-8'))
+   >>> with urllib.request.urlopen(request, data) as f:
+   ...     print(f.read().decode('utf-8'))
+   ...
 
 The following example uses an explicitly specified HTTP proxy, overriding
 environment settings::
@@ -1195,15 +1201,17 @@
    >>> import urllib.request
    >>> proxies = {'http': 'http://proxy.example.com:8080/'}
    >>> opener = urllib.request.FancyURLopener(proxies)
-   >>> f = opener.open("http://www.python.org")
-   >>> f.read().decode('utf-8')
+   >>> with opener.open("http://www.python.org") as f:
+   ...     f.read().decode('utf-8')
+   ...
 
 The following example uses no proxies at all, overriding environment settings::
 
    >>> import urllib.request
    >>> opener = urllib.request.FancyURLopener({})
-   >>> f = opener.open("http://www.python.org/")
-   >>> f.read().decode('utf-8')
+   >>> with opener.open("http://www.python.org/") as f:
+   ...     f.read().decode('utf-8')
+   ...
 
 
 Legacy interface
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index e3646f8..dda18ba 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -2222,9 +2222,9 @@
 :meth:`__getattribute__` method even of the object's metaclass::
 
    >>> class Meta(type):
-   ...    def __getattribute__(*args):
-   ...       print("Metaclass getattribute invoked")
-   ...       return type.__getattribute__(*args)
+   ...     def __getattribute__(*args):
+   ...         print("Metaclass getattribute invoked")
+   ...         return type.__getattribute__(*args)
    ...
    >>> class C(object, metaclass=Meta):
    ...     def __len__(self):
diff --git a/Doc/tutorial/stdlib.rst b/Doc/tutorial/stdlib.rst
index cd73bc2..d71598e 100644
--- a/Doc/tutorial/stdlib.rst
+++ b/Doc/tutorial/stdlib.rst
@@ -153,10 +153,11 @@
 from URLs and :mod:`smtplib` for sending mail::
 
    >>> from urllib.request import urlopen
-   >>> for line in urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'):
-   ...     line = line.decode('utf-8')  # Decoding the binary data to text.
-   ...     if 'EST' in line or 'EDT' in line:  # look for Eastern Time
-   ...         print(line)
+   >>> with urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl') as response:
+   ...     for line in response:
+   ...         line = line.decode('utf-8')  # Decoding the binary data to text.
+   ...         if 'EST' in line or 'EDT' in line:  # look for Eastern Time
+   ...             print(line)
 
    <BR>Nov. 25, 09:43:32 PM EST
 
diff --git a/Lib/aifc.py b/Lib/aifc.py
index 9e64de9..0b4f85a 100644
--- a/Lib/aifc.py
+++ b/Lib/aifc.py
@@ -356,7 +356,10 @@
         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
diff --git a/Lib/binhex.py b/Lib/binhex.py
index 7bf9278..8272d5c 100644
--- a/Lib/binhex.py
+++ b/Lib/binhex.py
@@ -32,7 +32,8 @@
     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 @@
         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 @@
         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"""
diff --git a/Lib/chunk.py b/Lib/chunk.py
index dc90a75..98187b2 100644
--- a/Lib/chunk.py
+++ b/Lib/chunk.py
@@ -85,8 +85,10 @@
 
     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:
diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py
index a9ead68..63bc329 100644
--- a/Lib/dbm/dumb.py
+++ b/Lib/dbm/dumb.py
@@ -248,8 +248,10 @@
             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
 
diff --git a/Lib/distutils/text_file.py b/Lib/distutils/text_file.py
index 40b8484..478336f 100644
--- a/Lib/distutils/text_file.py
+++ b/Lib/distutils/text_file.py
@@ -118,10 +118,11 @@
     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 = []
diff --git a/Lib/fileinput.py b/Lib/fileinput.py
index 87758ad..8af4a57 100644
--- a/Lib/fileinput.py
+++ b/Lib/fileinput.py
@@ -238,8 +238,10 @@
         self.close()
 
     def close(self):
-        self.nextfile()
-        self._files = ()
+        try:
+            self.nextfile()
+        finally:
+            self._files = ()
 
     def __enter__(self):
         return self
@@ -281,23 +283,25 @@
 
         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:
diff --git a/Lib/ftplib.py b/Lib/ftplib.py
index cd8c1a9..4d92b86 100644
--- a/Lib/ftplib.py
+++ b/Lib/ftplib.py
@@ -667,11 +667,16 @@
 
     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
diff --git a/Lib/gzip.py b/Lib/gzip.py
index 8b12225..7ad00e1 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -500,19 +500,21 @@
         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()
diff --git a/Lib/http/client.py b/Lib/http/client.py
index b27aa5d..1c69dcb 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -492,9 +492,11 @@
         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 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.
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index e866b96..67d9d2e 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -1011,14 +1011,19 @@
         """
         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()
 
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index c67ac99..fda8093 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -627,9 +627,10 @@
         """
         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 @@
 
         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 @@
         """
         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):
diff --git a/Lib/mailbox.py b/Lib/mailbox.py
index 2eee76c..4e42ad2 100644
--- a/Lib/mailbox.py
+++ b/Lib/mailbox.py
@@ -722,10 +722,14 @@
 
     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."""
diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
index d2715c2..1eb1a8d 100644
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -469,9 +469,10 @@
         '''
         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 @@
         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):
diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py
index c91535d..293ad76 100644
--- a/Lib/multiprocessing/queues.py
+++ b/Lib/multiprocessing/queues.py
@@ -133,9 +133,13 @@
 
     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()')
diff --git a/Lib/poplib.py b/Lib/poplib.py
index 1224eac..4915628 100644
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -276,18 +276,23 @@
 
     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
 
diff --git a/Lib/selectors.py b/Lib/selectors.py
index beb7ef7..7b6da29 100644
--- a/Lib/selectors.py
+++ b/Lib/selectors.py
@@ -445,8 +445,10 @@
             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 @@
             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.
diff --git a/Lib/shelve.py b/Lib/shelve.py
index cef580e..581baf1 100644
--- a/Lib/shelve.py
+++ b/Lib/shelve.py
@@ -138,17 +138,21 @@
         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'):
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index 99ffdee..db23ff0 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -855,12 +855,16 @@
 
     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."""
diff --git a/Lib/sunau.py b/Lib/sunau.py
index 3da41b7..e760093 100644
--- a/Lib/sunau.py
+++ b/Lib/sunau.py
@@ -295,9 +295,11 @@
         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 @@
                     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
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index f9e5c18..e3a2bb3 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -449,26 +449,26 @@
         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 @@
         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
diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py
index 0cacac8..51738f0 100644
--- a/Lib/telnetlib.py
+++ b/Lib/telnetlib.py
@@ -264,12 +264,13 @@
 
     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."""
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 5eafc1f..a2764d3 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -357,9 +357,11 @@
         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):
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 1164f3f..ecc5507 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -3845,34 +3845,6 @@
     version = ''
 
 
-class TestHelpVersionOptional(HelpTestCase):
-    """Test that the --version argument can be suppressed help messages"""
-
-    parser_signature = Sig(prog='PROG')
-    argument_signatures = [
-        Sig('-v', '--version', action='version', version='1.0'),
-        Sig('--foo', help='foo help'),
-        Sig('spam', help='spam help'),
-    ]
-    argument_group_signatures = []
-    usage = '''\
-        usage: PROG [-h] [-v] [--foo FOO] spam
-        '''
-    help = usage + '''\
-
-        positional arguments:
-          spam           spam help
-
-        optional arguments:
-          -h, --help     show this help message and exit
-          -v, --version  show program's version number and exit
-          --foo FOO      foo help
-        '''
-    version = '''\
-        1.0
-        '''
-
-
 class TestHelpNone(HelpTestCase):
     """Test that no errors occur if no help is specified"""
 
@@ -4080,6 +4052,32 @@
         '''
     version = ''
 
+
+class TestHelpVersionActionSuppress(HelpTestCase):
+    """Test that the --version argument can be suppressed in help messages"""
+
+    parser_signature = Sig(prog='PROG')
+    argument_signatures = [
+        Sig('-v', '--version', action='version', version='1.0',
+            help=argparse.SUPPRESS),
+        Sig('--foo', help='foo help'),
+        Sig('spam', help='spam help'),
+    ]
+    argument_group_signatures = []
+    usage = '''\
+        usage: PROG [-h] [--foo FOO] spam
+        '''
+    help = usage + '''\
+
+        positional arguments:
+          spam        spam help
+
+        optional arguments:
+          -h, --help  show this help message and exit
+          --foo FOO   foo help
+        '''
+
+
 class TestHelpSubparsersOrdering(HelpTestCase):
     """Test ordering of subcommands in help matches the code"""
     parser_signature = Sig(prog='PROG',
diff --git a/Lib/test/test_quopri.py b/Lib/test/test_quopri.py
index 583fd45..92511fa 100644
--- a/Lib/test/test_quopri.py
+++ b/Lib/test/test_quopri.py
@@ -138,6 +138,13 @@
             self.assertEqual(quopri.decodestring(e), p)
 
     @withpythonimplementation
+    def test_decodestring_double_equals(self):
+        # Issue 21511 - Ensure that byte string is compared to byte string
+        # instead of int byte value
+        decoded_value, encoded_value = (b"123=four", b"123==four")
+        self.assertEqual(quopri.decodestring(encoded_value), decoded_value)
+
+    @withpythonimplementation
     def test_idempotent_string(self):
         for p, e in self.STRINGS:
             self.assertEqual(quopri.decodestring(quopri.encodestring(e)), e)
diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py
index 4c8ba2d..42ebb6e 100644
--- a/Lib/test/test_urllibnet.py
+++ b/Lib/test/test_urllibnet.py
@@ -91,7 +91,8 @@
         # test getcode() with the fancy opener to get 404 error codes
         URL = "http://www.example.com/XXXinvalidXXX"
         with support.transient_internet(URL):
-            open_url = urllib.request.FancyURLopener().open(URL)
+            with self.assertWarns(DeprecationWarning):
+                open_url = urllib.request.FancyURLopener().open(URL)
             try:
                 code = open_url.getcode()
             finally:
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index 71b590c..7ae0dce 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -891,8 +891,8 @@
         data = b'\0' * (max_gzip_decode + 1)
         encoded = xmlrpclib.gzip_encode(data)
 
-        with self.assertRaisesRegexp(ValueError,
-                                     "max gzipped payload length exceeded"):
+        with self.assertRaisesRegex(ValueError,
+                                    "max gzipped payload length exceeded"):
             xmlrpclib.gzip_decode(encoded)
 
         xmlrpclib.gzip_decode(encoded, max_decode=-1)
diff --git a/Lib/urllib/response.py b/Lib/urllib/response.py
index 4a143b0..4778118 100644
--- a/Lib/urllib/response.py
+++ b/Lib/urllib/response.py
@@ -43,11 +43,15 @@
         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):
diff --git a/Lib/wave.py b/Lib/wave.py
index b56395e..8fba70f 100644
--- a/Lib/wave.py
+++ b/Lib/wave.py
@@ -186,10 +186,11 @@
         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 @@
             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.
diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py
index a227cda..29d75ab 100644
--- a/Lib/xml/sax/expatreader.py
+++ b/Lib/xml/sax/expatreader.py
@@ -211,17 +211,19 @@
             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 = \
diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py
index e8c1944..4521325 100644
--- a/Lib/xmlrpc/client.py
+++ b/Lib/xmlrpc/client.py
@@ -446,8 +446,13 @@
         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 @@
         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 @@
     # 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.
diff --git a/Misc/NEWS b/Misc/NEWS
index ea222f9..539252e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,10 @@
 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.
 
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 23ca31d..95bcb77 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -267,7 +267,7 @@
     if (fd < 0) {
         if (!PyErr_Occurred()) {
             PyErr_SetString(PyExc_ValueError,
-                            "Negative filedescriptor");
+                            "negative file descriptor");
             return -1;
         }
         PyErr_Clear();
@@ -1094,10 +1094,10 @@
 PyDoc_STRVAR(fileio_doc,
 "file(name: str[, mode: str][, opener: None]) -> file IO object\n"
 "\n"
-"Open a file.  The mode can be 'r', 'w', 'x' or 'a' for reading (default),\n"
+"Open a file.  The mode can be 'r' (default), 'w', 'x' or 'a' for reading,\n"
 "writing, exclusive creation or appending.  The file will be created if it\n"
 "doesn't exist when opened for writing or appending; it will be truncated\n"
-"when opened for writing.  A `FileExistsError` will be raised if it already\n"
+"when opened for writing.  A FileExistsError will be raised if it already\n"
 "exists when opened for creating. Opening a file for creating implies\n"
 "writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n"
 "to allow simultaneous reading and writing. A custom opener can be used by\n"
@@ -1123,22 +1123,22 @@
 "write(b: bytes) -> int.  Write bytes b to file, return number written.\n"
 "\n"
 "Only makes one system call, so not all of the data may be written.\n"
-"The number of bytes actually written is returned.");
+"The number of bytes actually written is returned.  In non-blocking mode,\n"
+"returns None if the write would block."
+);
 
 PyDoc_STRVAR(fileno_doc,
-"fileno() -> int. \"file descriptor\".\n"
-"\n"
-"This is needed for lower-level file interfaces, such the fcntl module.");
+"fileno() -> int.  Return the underlying file descriptor (an integer).");
 
 PyDoc_STRVAR(seek_doc,
 "seek(offset: int[, whence: int]) -> int.  Move to new file position and\n"
 "return the file position.\n"
 "\n"
 "Argument offset is a byte count.  Optional argument whence defaults to\n"
-"0 (offset from start of file, offset should be >= 0); other values are 1\n"
-"(move relative to current position, positive or negative), and 2 (move\n"
-"relative to end of file, usually negative, although many platforms allow\n"
-"seeking beyond the end of a file)."
+"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
+"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
+"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
+"many platforms allow seeking beyond the end of a file).\n"
 "\n"
 "Note that not all file objects are seekable.");
 
@@ -1152,7 +1152,10 @@
 #endif
 
 PyDoc_STRVAR(tell_doc,
-"tell() -> int.  Current file position");
+"tell() -> int.  Current file position.\n"
+"\n"
+"Can raise OSError for non seekable files."
+);
 
 PyDoc_STRVAR(readinto_doc,
 "readinto() -> Same as RawIOBase.readinto().");
@@ -1161,10 +1164,10 @@
 "close() -> None.  Close the file.\n"
 "\n"
 "A closed file cannot be used for further I/O operations.  close() may be\n"
-"called more than once without error.  Changes the fileno to -1.");
+"called more than once without error.");
 
 PyDoc_STRVAR(isatty_doc,
-"isatty() -> bool.  True if the file is connected to a tty device.");
+"isatty() -> bool.  True if the file is connected to a TTY device.");
 
 PyDoc_STRVAR(seekable_doc,
 "seekable() -> bool.  True if file supports random-access.");
@@ -1219,7 +1222,7 @@
 static PyGetSetDef fileio_getsetlist[] = {
     {"closed", (getter)get_closed, NULL, "True if the file is closed"},
     {"closefd", (getter)get_closefd, NULL,
-        "True if the file descriptor will be closed"},
+        "True if the file descriptor will be closed by close()."},
     {"mode", (getter)get_mode, NULL, "String giving the file mode"},
     {NULL},
 };