github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/clients/python-legacy/lakefs_client/rest.py (about) 1 """ 2 lakeFS API 3 4 lakeFS HTTP API # noqa: E501 5 6 The version of the OpenAPI document: 1.0.0 7 Contact: services@treeverse.io 8 Generated by: https://openapi-generator.tech 9 """ 10 11 12 import io 13 import json 14 import logging 15 import re 16 import ssl 17 from urllib.parse import urlencode 18 19 import urllib3 20 21 from lakefs_client.exceptions import ApiException, UnauthorizedException, ForbiddenException, NotFoundException, ServiceException, ApiValueError 22 23 24 logger = logging.getLogger(__name__) 25 26 27 class RESTResponse(io.IOBase): 28 29 def __init__(self, resp): 30 self.urllib3_response = resp 31 self.status = resp.status 32 self.reason = resp.reason 33 self.data = resp.data 34 35 def getheaders(self): 36 """Returns a dictionary of the response headers.""" 37 return self.urllib3_response.getheaders() 38 39 def getheader(self, name, default=None): 40 """Returns a given response header.""" 41 return self.urllib3_response.getheader(name, default) 42 43 44 class RESTClientObject(object): 45 46 def __init__(self, configuration, pools_size=4, maxsize=None): 47 # urllib3.PoolManager will pass all kw parameters to connectionpool 48 # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501 49 # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501 50 # maxsize is the number of requests to host that are allowed in parallel # noqa: E501 51 # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501 52 53 # cert_reqs 54 if configuration.verify_ssl: 55 cert_reqs = ssl.CERT_REQUIRED 56 else: 57 cert_reqs = ssl.CERT_NONE 58 59 addition_pool_args = {} 60 if configuration.assert_hostname is not None: 61 addition_pool_args['assert_hostname'] = configuration.assert_hostname # noqa: E501 62 63 if configuration.retries is not None: 64 addition_pool_args['retries'] = configuration.retries 65 66 if configuration.socket_options is not None: 67 addition_pool_args['socket_options'] = configuration.socket_options 68 69 if maxsize is None: 70 if configuration.connection_pool_maxsize is not None: 71 maxsize = configuration.connection_pool_maxsize 72 else: 73 maxsize = 4 74 75 # https pool manager 76 if configuration.proxy: 77 self.pool_manager = urllib3.ProxyManager( 78 num_pools=pools_size, 79 maxsize=maxsize, 80 cert_reqs=cert_reqs, 81 ca_certs=configuration.ssl_ca_cert, 82 cert_file=configuration.cert_file, 83 key_file=configuration.key_file, 84 proxy_url=configuration.proxy, 85 proxy_headers=configuration.proxy_headers, 86 **addition_pool_args 87 ) 88 else: 89 self.pool_manager = urllib3.PoolManager( 90 num_pools=pools_size, 91 maxsize=maxsize, 92 cert_reqs=cert_reqs, 93 ca_certs=configuration.ssl_ca_cert, 94 cert_file=configuration.cert_file, 95 key_file=configuration.key_file, 96 **addition_pool_args 97 ) 98 99 def request(self, method, url, query_params=None, headers=None, 100 body=None, post_params=None, _preload_content=True, 101 _request_timeout=None): 102 """Perform requests. 103 104 :param method: http request method 105 :param url: http request url 106 :param query_params: query parameters in the url 107 :param headers: http request headers 108 :param body: request json body, for `application/json` 109 :param post_params: request post parameters, 110 `application/x-www-form-urlencoded` 111 and `multipart/form-data` 112 :param _preload_content: if False, the urllib3.HTTPResponse object will 113 be returned without reading/decoding response 114 data. Default is True. 115 :param _request_timeout: timeout setting for this request. If one 116 number provided, it will be total request 117 timeout. It can also be a pair (tuple) of 118 (connection, read) timeouts. 119 """ 120 method = method.upper() 121 assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', 122 'PATCH', 'OPTIONS'] 123 124 if post_params and body: 125 raise ApiValueError( 126 "body parameter cannot be used with post_params parameter." 127 ) 128 129 post_params = post_params or {} 130 headers = headers or {} 131 132 timeout = None 133 if _request_timeout: 134 if isinstance(_request_timeout, (int, float)): # noqa: E501,F821 135 timeout = urllib3.Timeout(total=_request_timeout) 136 elif (isinstance(_request_timeout, tuple) and 137 len(_request_timeout) == 2): 138 timeout = urllib3.Timeout( 139 connect=_request_timeout[0], read=_request_timeout[1]) 140 141 try: 142 # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` 143 if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: 144 # Only set a default Content-Type for POST, PUT, PATCH and OPTIONS requests 145 if (method != 'DELETE') and ('Content-Type' not in headers): 146 headers['Content-Type'] = 'application/json' 147 if query_params: 148 url += '?' + urlencode(query_params) 149 if ('Content-Type' not in headers) or (re.search('json', headers['Content-Type'], re.IGNORECASE)): 150 request_body = None 151 if body is not None: 152 request_body = json.dumps(body) 153 r = self.pool_manager.request( 154 method, url, 155 body=request_body, 156 preload_content=_preload_content, 157 timeout=timeout, 158 headers=headers) 159 elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 160 r = self.pool_manager.request( 161 method, url, 162 fields=post_params, 163 encode_multipart=False, 164 preload_content=_preload_content, 165 timeout=timeout, 166 headers=headers) 167 elif headers['Content-Type'] == 'multipart/form-data': 168 # must del headers['Content-Type'], or the correct 169 # Content-Type which generated by urllib3 will be 170 # overwritten. 171 del headers['Content-Type'] 172 r = self.pool_manager.request( 173 method, url, 174 fields=post_params, 175 encode_multipart=True, 176 preload_content=_preload_content, 177 timeout=timeout, 178 headers=headers) 179 # Pass a `string` parameter directly in the body to support 180 # other content types than Json when `body` argument is 181 # provided in serialized form 182 elif isinstance(body, str) or isinstance(body, bytes): 183 request_body = body 184 r = self.pool_manager.request( 185 method, url, 186 body=request_body, 187 preload_content=_preload_content, 188 timeout=timeout, 189 headers=headers) 190 else: 191 # Cannot generate the request from given parameters 192 msg = """Cannot prepare a request message for provided 193 arguments. Please check that your arguments match 194 declared content type.""" 195 raise ApiException(status=0, reason=msg) 196 # For `GET`, `HEAD` 197 else: 198 r = self.pool_manager.request(method, url, 199 fields=query_params, 200 preload_content=_preload_content, 201 timeout=timeout, 202 headers=headers) 203 except urllib3.exceptions.SSLError as e: 204 msg = "{0}\n{1}".format(type(e).__name__, str(e)) 205 raise ApiException(status=0, reason=msg) 206 207 if _preload_content: 208 r = RESTResponse(r) 209 210 # log response body 211 logger.debug("response body: %s", r.data) 212 213 if not 200 <= r.status <= 299: 214 if r.status == 401: 215 raise UnauthorizedException(http_resp=r) 216 217 if r.status == 403: 218 raise ForbiddenException(http_resp=r) 219 220 if r.status == 404: 221 raise NotFoundException(http_resp=r) 222 223 if 500 <= r.status <= 599: 224 raise ServiceException(http_resp=r) 225 226 raise ApiException(http_resp=r) 227 228 return r 229 230 def GET(self, url, headers=None, query_params=None, _preload_content=True, 231 _request_timeout=None): 232 return self.request("GET", url, 233 headers=headers, 234 _preload_content=_preload_content, 235 _request_timeout=_request_timeout, 236 query_params=query_params) 237 238 def HEAD(self, url, headers=None, query_params=None, _preload_content=True, 239 _request_timeout=None): 240 return self.request("HEAD", url, 241 headers=headers, 242 _preload_content=_preload_content, 243 _request_timeout=_request_timeout, 244 query_params=query_params) 245 246 def OPTIONS(self, url, headers=None, query_params=None, post_params=None, 247 body=None, _preload_content=True, _request_timeout=None): 248 return self.request("OPTIONS", url, 249 headers=headers, 250 query_params=query_params, 251 post_params=post_params, 252 _preload_content=_preload_content, 253 _request_timeout=_request_timeout, 254 body=body) 255 256 def DELETE(self, url, headers=None, query_params=None, body=None, 257 _preload_content=True, _request_timeout=None): 258 return self.request("DELETE", url, 259 headers=headers, 260 query_params=query_params, 261 _preload_content=_preload_content, 262 _request_timeout=_request_timeout, 263 body=body) 264 265 def POST(self, url, headers=None, query_params=None, post_params=None, 266 body=None, _preload_content=True, _request_timeout=None): 267 return self.request("POST", url, 268 headers=headers, 269 query_params=query_params, 270 post_params=post_params, 271 _preload_content=_preload_content, 272 _request_timeout=_request_timeout, 273 body=body) 274 275 def PUT(self, url, headers=None, query_params=None, post_params=None, 276 body=None, _preload_content=True, _request_timeout=None): 277 return self.request("PUT", url, 278 headers=headers, 279 query_params=query_params, 280 post_params=post_params, 281 _preload_content=_preload_content, 282 _request_timeout=_request_timeout, 283 body=body) 284 285 def PATCH(self, url, headers=None, query_params=None, post_params=None, 286 body=None, _preload_content=True, _request_timeout=None): 287 return self.request("PATCH", url, 288 headers=headers, 289 query_params=query_params, 290 post_params=post_params, 291 _preload_content=_preload_content, 292 _request_timeout=_request_timeout, 293 body=body)