We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
max_retries is ignored when using thrift
connection/thrift.py does not catch socket.error in perform_request which cause max_retries to be ignored in the transport.

One can argue that this socket.error exception should be translated into a TException in the offical thrift-library but I think it's better to have it included here aswell.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `elasticsearch/connection/thrift.py`
Content:
```
1 from __future__ import absolute_import
2 from socket import timeout as SocketTimeout
3 import time
4 import logging
5 
6 try:
7     from .esthrift import Rest
8     from .esthrift.ttypes import Method, RestRequest
9 
10     from thrift.transport import TTransport, TSocket, TSSLSocket
11     from thrift.protocol import TBinaryProtocol
12     from thrift.Thrift import TException
13     THRIFT_AVAILABLE = True
14 except ImportError:
15     THRIFT_AVAILABLE = False
16 
17 from ..exceptions import ConnectionError, ImproperlyConfigured, ConnectionTimeout
18 from .pooling import PoolingConnection
19 
20 logger = logging.getLogger('elasticsearch')
21 
22 class ThriftConnection(PoolingConnection):
23     """
24     Connection using the `thrift` protocol to communicate with elasticsearch.
25 
26     See https://github.com/elasticsearch/elasticsearch-transport-thrift for additional info.
27     """
28     transport_schema = 'thrift'
29 
30     def __init__(self, host='localhost', port=9500, framed_transport=False, use_ssl=False, **kwargs):
31         """
32         :arg framed_transport: use `TTransport.TFramedTransport` instead of
33             `TTransport.TBufferedTransport`
34         """
35         if not THRIFT_AVAILABLE:
36             raise ImproperlyConfigured("Thrift is not available.")
37 
38         super(ThriftConnection, self).__init__(host=host, port=port, **kwargs)
39         self._framed_transport = framed_transport
40         self._tsocket_class = TSocket.TSocket
41         if use_ssl:
42             self._tsocket_class = TSSLSocket.TSSLSocket 
43         self._tsocket_args = (host, port)
44 
45     def _make_connection(self):
46         socket = self._tsocket_class(*self._tsocket_args)
47         socket.setTimeout(self.timeout * 1000.0)
48         if self._framed_transport:
49             transport = TTransport.TFramedTransport(socket)
50         else:
51             transport = TTransport.TBufferedTransport(socket)
52 
53         protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)
54         client = Rest.Client(protocol)
55         client.transport = transport
56         transport.open()
57         return client
58 
59     def perform_request(self, method, url, params=None, body=None, timeout=None, ignore=()):
60         request = RestRequest(method=Method._NAMES_TO_VALUES[method.upper()], uri=url,
61                     parameters=params, body=body)
62 
63         start = time.time()
64         tclient = None
65         try:
66             tclient = self._get_connection()
67             response = tclient.execute(request)
68             duration = time.time() - start
69         except SocketTimeout as e:
70             self.log_request_fail(method, url, body, time.time() - start, exception=e)
71             raise ConnectionTimeout('TIMEOUT', str(e), e)
72         except (TException, SocketTimeout) as e:
73             self.log_request_fail(method, url, body, time.time() - start, exception=e)
74             if tclient:
75                 try:
76                     # try closing transport socket
77                     tclient.transport.close()
78                 except Exception as e:
79                     logger.warning(
80                         'Exception %s occured when closing a failed thrift connection.',
81                         e, exc_info=True
82                     )
83             raise ConnectionError('N/A', str(e), e)
84 
85         self._release_connection(tclient)
86 
87         if not (200 <= response.status < 300) and response.status not in ignore:
88             self.log_request_fail(method, url, body, duration, response.status)
89             self._raise_error(response.status, response.body)
90 
91         self.log_request_success(method, url, url, body, response.status,
92             response.body, duration)
93 
94         headers = {}
95         if response.headers:
96             headers = dict((k.lower(), v) for k, v in response.headers.items())
97         return response.status, headers, response.body or ''
98 
99
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/elasticsearch/connection/thrift.py b/elasticsearch/connection/thrift.py
--- a/elasticsearch/connection/thrift.py
+++ b/elasticsearch/connection/thrift.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import
 from socket import timeout as SocketTimeout
+from socket import error as SocketError
 import time
 import logging
 
@@ -69,7 +70,7 @@
         except SocketTimeout as e:
             self.log_request_fail(method, url, body, time.time() - start, exception=e)
             raise ConnectionTimeout('TIMEOUT', str(e), e)
-        except (TException, SocketTimeout) as e:
+        except (TException, SocketError) as e:
             self.log_request_fail(method, url, body, time.time() - start, exception=e)
             if tclient:
                 try:

{"golden_diff": "diff --git a/elasticsearch/connection/thrift.py b/elasticsearch/connection/thrift.py\n--- a/elasticsearch/connection/thrift.py\n+++ b/elasticsearch/connection/thrift.py\n@@ -1,5 +1,6 @@\n from __future__ import absolute_import\n from socket import timeout as SocketTimeout\n+from socket import error as SocketError\n import time\n import logging\n \n@@ -69,7 +70,7 @@\n         except SocketTimeout as e:\n             self.log_request_fail(method, url, body, time.time() - start, exception=e)\n             raise ConnectionTimeout('TIMEOUT', str(e), e)\n-        except (TException, SocketTimeout) as e:\n+        except (TException, SocketError) as e:\n             self.log_request_fail(method, url, body, time.time() - start, exception=e)\n             if tclient:\n                 try:\n", "issue": "max_retries is ignored when using thrift\nconnection/thrift.py does not catch socket.error in perform_request which cause max_retries to be ignored in the transport.\n\nOne can argue that this socket.error exception should be translated into a TException in the offical thrift-library but I think it's better to have it included here aswell.\n\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom socket import timeout as SocketTimeout\nimport time\nimport logging\n\ntry:\n    from .esthrift import Rest\n    from .esthrift.ttypes import Method, RestRequest\n\n    from thrift.transport import TTransport, TSocket, TSSLSocket\n    from thrift.protocol import TBinaryProtocol\n    from thrift.Thrift import TException\n    THRIFT_AVAILABLE = True\nexcept ImportError:\n    THRIFT_AVAILABLE = False\n\nfrom ..exceptions import ConnectionError, ImproperlyConfigured, ConnectionTimeout\nfrom .pooling import PoolingConnection\n\nlogger = logging.getLogger('elasticsearch')\n\nclass ThriftConnection(PoolingConnection):\n    \"\"\"\n    Connection using the `thrift` protocol to communicate with elasticsearch.\n\n    See https://github.com/elasticsearch/elasticsearch-transport-thrift for additional info.\n    \"\"\"\n    transport_schema = 'thrift'\n\n    def __init__(self, host='localhost', port=9500, framed_transport=False, use_ssl=False, **kwargs):\n        \"\"\"\n        :arg framed_transport: use `TTransport.TFramedTransport` instead of\n            `TTransport.TBufferedTransport`\n        \"\"\"\n        if not THRIFT_AVAILABLE:\n            raise ImproperlyConfigured(\"Thrift is not available.\")\n\n        super(ThriftConnection, self).__init__(host=host, port=port, **kwargs)\n        self._framed_transport = framed_transport\n        self._tsocket_class = TSocket.TSocket\n        if use_ssl:\n            self._tsocket_class = TSSLSocket.TSSLSocket \n        self._tsocket_args = (host, port)\n\n    def _make_connection(self):\n        socket = self._tsocket_class(*self._tsocket_args)\n        socket.setTimeout(self.timeout * 1000.0)\n        if self._framed_transport:\n            transport = TTransport.TFramedTransport(socket)\n        else:\n            transport = TTransport.TBufferedTransport(socket)\n\n        protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)\n        client = Rest.Client(protocol)\n        client.transport = transport\n        transport.open()\n        return client\n\n    def perform_request(self, method, url, params=None, body=None, timeout=None, ignore=()):\n        request = RestRequest(method=Method._NAMES_TO_VALUES[method.upper()], uri=url,\n                    parameters=params, body=body)\n\n        start = time.time()\n        tclient = None\n        try:\n            tclient = self._get_connection()\n            response = tclient.execute(request)\n            duration = time.time() - start\n        except SocketTimeout as e:\n            self.log_request_fail(method, url, body, time.time() - start, exception=e)\n            raise ConnectionTimeout('TIMEOUT', str(e), e)\n        except (TException, SocketTimeout) as e:\n            self.log_request_fail(method, url, body, time.time() - start, exception=e)\n            if tclient:\n                try:\n                    # try closing transport socket\n                    tclient.transport.close()\n                except Exception as e:\n                    logger.warning(\n                        'Exception %s occured when closing a failed thrift connection.',\n                        e, exc_info=True\n                    )\n            raise ConnectionError('N/A', str(e), e)\n\n        self._release_connection(tclient)\n\n        if not (200 <= response.status < 300) and response.status not in ignore:\n            self.log_request_fail(method, url, body, duration, response.status)\n            self._raise_error(response.status, response.body)\n\n        self.log_request_success(method, url, url, body, response.status,\n            response.body, duration)\n\n        headers = {}\n        if response.headers:\n            headers = dict((k.lower(), v) for k, v in response.headers.items())\n        return response.status, headers, response.body or ''\n\n", "path": "elasticsearch/connection/thrift.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom socket import timeout as SocketTimeout\nfrom socket import error as SocketError\nimport time\nimport logging\n\ntry:\n    from .esthrift import Rest\n    from .esthrift.ttypes import Method, RestRequest\n\n    from thrift.transport import TTransport, TSocket, TSSLSocket\n    from thrift.protocol import TBinaryProtocol\n    from thrift.Thrift import TException\n    THRIFT_AVAILABLE = True\nexcept ImportError:\n    THRIFT_AVAILABLE = False\n\nfrom ..exceptions import ConnectionError, ImproperlyConfigured, ConnectionTimeout\nfrom .pooling import PoolingConnection\n\nlogger = logging.getLogger('elasticsearch')\n\nclass ThriftConnection(PoolingConnection):\n    \"\"\"\n    Connection using the `thrift` protocol to communicate with elasticsearch.\n\n    See https://github.com/elasticsearch/elasticsearch-transport-thrift for additional info.\n    \"\"\"\n    transport_schema = 'thrift'\n\n    def __init__(self, host='localhost', port=9500, framed_transport=False, use_ssl=False, **kwargs):\n        \"\"\"\n        :arg framed_transport: use `TTransport.TFramedTransport` instead of\n            `TTransport.TBufferedTransport`\n        \"\"\"\n        if not THRIFT_AVAILABLE:\n            raise ImproperlyConfigured(\"Thrift is not available.\")\n\n        super(ThriftConnection, self).__init__(host=host, port=port, **kwargs)\n        self._framed_transport = framed_transport\n        self._tsocket_class = TSocket.TSocket\n        if use_ssl:\n            self._tsocket_class = TSSLSocket.TSSLSocket \n        self._tsocket_args = (host, port)\n\n    def _make_connection(self):\n        socket = self._tsocket_class(*self._tsocket_args)\n        socket.setTimeout(self.timeout * 1000.0)\n        if self._framed_transport:\n            transport = TTransport.TFramedTransport(socket)\n        else:\n            transport = TTransport.TBufferedTransport(socket)\n\n        protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)\n        client = Rest.Client(protocol)\n        client.transport = transport\n        transport.open()\n        return client\n\n    def perform_request(self, method, url, params=None, body=None, timeout=None, ignore=()):\n        request = RestRequest(method=Method._NAMES_TO_VALUES[method.upper()], uri=url,\n                    parameters=params, body=body)\n\n        start = time.time()\n        tclient = None\n        try:\n            tclient = self._get_connection()\n            response = tclient.execute(request)\n            duration = time.time() - start\n        except SocketTimeout as e:\n            self.log_request_fail(method, url, body, time.time() - start, exception=e)\n            raise ConnectionTimeout('TIMEOUT', str(e), e)\n        except (TException, SocketError) as e:\n            self.log_request_fail(method, url, body, time.time() - start, exception=e)\n            if tclient:\n                try:\n                    # try closing transport socket\n                    tclient.transport.close()\n                except Exception as e:\n                    logger.warning(\n                        'Exception %s occured when closing a failed thrift connection.',\n                        e, exc_info=True\n                    )\n            raise ConnectionError('N/A', str(e), e)\n\n        self._release_connection(tclient)\n\n        if not (200 <= response.status < 300) and response.status not in ignore:\n            self.log_request_fail(method, url, body, duration, response.status)\n            self._raise_error(response.status, response.body)\n\n        self.log_request_success(method, url, url, body, response.status,\n            response.body, duration)\n\n        headers = {}\n        if response.headers:\n            headers = dict((k.lower(), v) for k, v in response.headers.items())\n        return response.status, headers, response.body or ''\n\n", "path": "elasticsearch/connection/thrift.py"}]}