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)