github.com/phrase/openapi@v0.0.0-20240514140800-49e8a106740e/openapi-generator/templates/python/python-experimental/api_client.mustache (about)

     1  # coding: utf-8
     2  {{>partial_header}}
     3  from __future__ import absolute_import
     4  
     5  import json
     6  import atexit
     7  import mimetypes
     8  from multiprocessing.pool import ThreadPool
     9  import os
    10  
    11  # python 2 and python 3 compatibility library
    12  import six
    13  from six.moves.urllib.parse import quote
    14  {{#tornado}}
    15  import tornado.gen
    16  {{/tornado}}
    17  
    18  from {{packageName}} import rest
    19  from {{packageName}}.configuration import Configuration
    20  from {{packageName}}.exceptions import ApiValueError
    21  from {{packageName}}.model_utils import (
    22      ModelNormal,
    23      ModelSimple,
    24      ModelComposed,
    25      date,
    26      datetime,
    27      deserialize_file,
    28      file_type,
    29      model_to_dict,
    30      str,
    31      validate_and_convert_types
    32  )
    33  
    34  
    35  class ApiClient(object):
    36      """Generic API client for OpenAPI client library builds.
    37  
    38      OpenAPI generic API client. This client handles the client-
    39      server communication, and is invariant across implementations. Specifics of
    40      the methods and models for each application are generated from the OpenAPI
    41      templates.
    42  
    43      NOTE: This class is auto generated by OpenAPI Generator.
    44      Ref: https://openapi-generator.tech
    45      Do not edit the class manually.
    46  
    47      :param configuration: .Configuration object for this client
    48      :param header_name: a header to pass when making calls to the API.
    49      :param header_value: a header value to pass when making calls to
    50          the API.
    51      :param cookie: a cookie to include in the header when making calls
    52          to the API
    53      :param pool_threads: The number of threads to use for async requests
    54          to the API. More threads means more concurrent API requests.
    55      """
    56  
    57      # six.binary_type python2=str, python3=bytes
    58      # six.text_type python2=unicode, python3=str
    59      PRIMITIVE_TYPES = (
    60          (float, bool, six.binary_type, six.text_type) + six.integer_types
    61      )
    62      _pool = None
    63  
    64      def __init__(self, configuration=None, header_name=None, header_value=None,
    65                   cookie=None, pool_threads=1):
    66          if configuration is None:
    67              configuration = Configuration()
    68          self.configuration = configuration
    69          self.pool_threads = pool_threads
    70  
    71          self.rest_client = rest.RESTClientObject(configuration)
    72          self.default_headers = {}
    73          if header_name is not None:
    74              self.default_headers[header_name] = header_value
    75          self.cookie = cookie
    76          # Set default User-Agent.
    77          self.user_agent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{packageVersion}}}/python{{/httpUserAgent}}'
    78  
    79      def __enter__(self):
    80          return self
    81  
    82      def __exit__(self, exc_type, exc_value, traceback):
    83          self.close()
    84  
    85      def close(self):
    86          if self._pool:
    87              self._pool.close()
    88              self._pool.join()
    89              self._pool = None
    90              if hasattr(atexit, 'unregister'):
    91                  atexit.unregister(self.close)
    92  
    93      @property
    94      def pool(self):
    95          """Create thread pool on first request
    96           avoids instantiating unused threadpool for blocking clients.
    97          """
    98          if self._pool is None:
    99              atexit.register(self.close)
   100              self._pool = ThreadPool(self.pool_threads)
   101          return self._pool
   102  
   103      @property
   104      def user_agent(self):
   105          """User agent for this API client"""
   106          return self.default_headers['User-Agent']
   107  
   108      @user_agent.setter
   109      def user_agent(self, value):
   110          self.default_headers['User-Agent'] = value
   111  
   112      def set_default_header(self, header_name, header_value):
   113          self.default_headers[header_name] = header_value
   114  
   115      {{#tornado}}
   116      @tornado.gen.coroutine
   117      {{/tornado}}
   118      {{#asyncio}}async {{/asyncio}}def __call_api(
   119              self, resource_path, method, path_params=None,
   120              query_params=None, header_params=None, body=None, post_params=None,
   121              files=None, response_type=None, auth_settings=None,
   122              _return_http_data_only=None, collection_formats=None,
   123              _preload_content=True, _request_timeout=None, _host=None,
   124              _check_type=None):
   125  
   126          config = self.configuration
   127  
   128          # header parameters
   129          header_params = header_params or {}
   130          header_params.update(self.default_headers)
   131          if self.cookie:
   132              header_params['Cookie'] = self.cookie
   133          if header_params:
   134              header_params = self.sanitize_for_serialization(header_params)
   135              header_params = dict(self.parameters_to_tuples(header_params,
   136                                                             collection_formats))
   137  
   138          # path parameters
   139          if path_params:
   140              path_params = self.sanitize_for_serialization(path_params)
   141              path_params = self.parameters_to_tuples(path_params,
   142                                                      collection_formats)
   143              for k, v in path_params:
   144                  # specified safe chars, encode everything
   145                  resource_path = resource_path.replace(
   146                      '{%s}' % k,
   147                      quote(str(v), safe=config.safe_chars_for_path_param)
   148                  )
   149  
   150          # query parameters
   151          if query_params:
   152              query_params = self.sanitize_for_serialization(query_params)
   153              query_params = self.parameters_to_tuples(query_params,
   154                                                       collection_formats)
   155  
   156          # post parameters
   157          if post_params or files:
   158              post_params = post_params if post_params else []
   159              post_params = self.sanitize_for_serialization(post_params)
   160              post_params = self.parameters_to_tuples(post_params,
   161                                                      collection_formats)
   162              post_params.extend(self.files_parameters(files))
   163  
   164          # body
   165          if body:
   166              body = self.sanitize_for_serialization(body)
   167  
   168          # auth setting
   169          self.update_params_for_auth(header_params, query_params,
   170                                      auth_settings, resource_path, method, body)
   171  
   172          # request url
   173          if _host is None:
   174              url = self.configuration.host + resource_path
   175          else:
   176              # use server/host defined in path or operation instead
   177              url = _host + resource_path
   178  
   179          # perform request and return response
   180          response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request(
   181              method, url, query_params=query_params, headers=header_params,
   182              post_params=post_params, body=body,
   183              _preload_content=_preload_content,
   184              _request_timeout=_request_timeout)
   185  
   186          self.last_response = response_data
   187  
   188          return_data = response_data
   189          if _preload_content:
   190              # deserialize response data
   191              if response_type:
   192                  return_data = self.deserialize(
   193                      response_data,
   194                      response_type,
   195                      _check_type
   196                  )
   197              else:
   198                  return_data = None
   199  
   200  {{^tornado}}
   201          if _return_http_data_only:
   202              return (return_data)
   203          else:
   204              return (return_data, response_data.status,
   205                      response_data.getheaders())
   206  {{/tornado}}
   207  {{#tornado}}
   208          if _return_http_data_only:
   209              raise tornado.gen.Return(return_data)
   210          else:
   211              raise tornado.gen.Return((return_data, response_data.status,
   212                                        response_data.getheaders()))
   213  {{/tornado}}
   214  
   215      def sanitize_for_serialization(self, obj):
   216          """Builds a JSON POST object.
   217  
   218          If obj is None, return None.
   219          If obj is str, int, long, float, bool, return directly.
   220          If obj is datetime.datetime, datetime.date
   221              convert to string in iso8601 format.
   222          If obj is list, sanitize each element in the list.
   223          If obj is dict, return the dict.
   224          If obj is OpenAPI model, return the properties dict.
   225  
   226          :param obj: The data to serialize.
   227          :return: The serialized form of data.
   228          """
   229          if obj is None:
   230              return None
   231          elif isinstance(obj, self.PRIMITIVE_TYPES):
   232              return obj
   233          elif isinstance(obj, list):
   234              return [self.sanitize_for_serialization(sub_obj)
   235                      for sub_obj in obj]
   236          elif isinstance(obj, tuple):
   237              return tuple(self.sanitize_for_serialization(sub_obj)
   238                           for sub_obj in obj)
   239          elif isinstance(obj, (datetime, date)):
   240              return obj.isoformat()
   241  
   242          if isinstance(obj, dict):
   243              obj_dict = obj
   244          elif isinstance(obj, ModelNormal) or isinstance(obj, ModelComposed):
   245              # Convert model obj to dict
   246              # Convert attribute name to json key in
   247              # model definition for request
   248              obj_dict = model_to_dict(obj, serialize=True)
   249          elif isinstance(obj, ModelSimple):
   250              return self.sanitize_for_serialization(obj.value)
   251  
   252          return {key: self.sanitize_for_serialization(val)
   253                  for key, val in six.iteritems(obj_dict)}
   254  
   255      def deserialize(self, response, response_type, _check_type):
   256          """Deserializes response into an object.
   257  
   258          :param response: RESTResponse object to be deserialized.
   259          :param response_type: For the response, a tuple containing:
   260              valid classes
   261              a list containing valid classes (for list schemas)
   262              a dict containing a tuple of valid classes as the value
   263              Example values:
   264              (str,)
   265              (Pet,)
   266              (float, none_type)
   267              ([int, none_type],)
   268              ({str: (bool, str, int, float, date, datetime, str, none_type)},)
   269          :param _check_type: boolean, whether to check the types of the data
   270              received from the server
   271  
   272          :return: deserialized object.
   273          """
   274          # handle file downloading
   275          # save response body into a tmp file and return the instance
   276          if response_type == (file_type,):
   277              content_disposition = response.getheader("Content-Disposition")
   278              return deserialize_file(response.data, self.configuration,
   279                                      content_disposition=content_disposition)
   280  
   281          # fetch data from response object
   282          try:
   283              received_data = json.loads(response.data)
   284          except ValueError:
   285              received_data = response.data
   286  
   287          # store our data under the key of 'received_data' so users have some
   288          # context if they are deserializing a string and the data type is wrong
   289          deserialized_data = validate_and_convert_types(
   290              received_data,
   291              response_type,
   292              ['received_data'],
   293              True,
   294              _check_type,
   295              configuration=self.configuration
   296          )
   297          return deserialized_data
   298  
   299      def call_api(self, resource_path, method,
   300                   path_params=None, query_params=None, header_params=None,
   301                   body=None, post_params=None, files=None,
   302                   response_type=None, auth_settings=None, async_req=None,
   303                   _return_http_data_only=None, collection_formats=None,
   304                   _preload_content=True, _request_timeout=None, _host=None,
   305                   _check_type=None):
   306          """Makes the HTTP request (synchronous) and returns deserialized data.
   307  
   308          To make an async_req request, set the async_req parameter.
   309  
   310          :param resource_path: Path to method endpoint.
   311          :param method: Method to call.
   312          :param path_params: Path parameters in the url.
   313          :param query_params: Query parameters in the url.
   314          :param header_params: Header parameters to be
   315              placed in the request header.
   316          :param body: Request body.
   317          :param post_params dict: Request post form parameters,
   318              for `application/x-www-form-urlencoded`, `multipart/form-data`.
   319          :param auth_settings list: Auth Settings names for the request.
   320          :param response_type: For the response, a tuple containing:
   321              valid classes
   322              a list containing valid classes (for list schemas)
   323              a dict containing a tuple of valid classes as the value
   324              Example values:
   325              (str,)
   326              (Pet,)
   327              (float, none_type)
   328              ([int, none_type],)
   329              ({str: (bool, str, int, float, date, datetime, str, none_type)},)
   330          :param files dict: key -> field name, value -> a list of open file
   331              objects for `multipart/form-data`.
   332          :param async_req bool: execute request asynchronously
   333          :param _return_http_data_only: response data without head status code
   334                                         and headers
   335          :param collection_formats: dict of collection formats for path, query,
   336              header, and post parameters.
   337          :param _preload_content: if False, the urllib3.HTTPResponse object will
   338                                   be returned without reading/decoding response
   339                                   data. Default is True.
   340          :param _request_timeout: timeout setting for this request. If one
   341                                   number provided, it will be total request
   342                                   timeout. It can also be a pair (tuple) of
   343                                   (connection, read) timeouts.
   344          :param _check_type: boolean describing if the data back from the server
   345              should have its type checked.
   346          :return:
   347              If async_req parameter is True,
   348              the request will be called asynchronously.
   349              The method will return the request thread.
   350              If parameter async_req is False or missing,
   351              then the method will return the response directly.
   352          """
   353          if not async_req:
   354              return self.__call_api(resource_path, method,
   355                                     path_params, query_params, header_params,
   356                                     body, post_params, files,
   357                                     response_type, auth_settings,
   358                                     _return_http_data_only, collection_formats,
   359                                     _preload_content, _request_timeout, _host,
   360                                     _check_type)
   361  
   362          return self.pool.apply_async(self.__call_api, (resource_path,
   363                                                         method, path_params,
   364                                                         query_params,
   365                                                         header_params, body,
   366                                                         post_params, files,
   367                                                         response_type,
   368                                                         auth_settings,
   369                                                         _return_http_data_only,
   370                                                         collection_formats,
   371                                                         _preload_content,
   372                                                         _request_timeout,
   373                                                         _host, _check_type))
   374  
   375      def request(self, method, url, query_params=None, headers=None,
   376                  post_params=None, body=None, _preload_content=True,
   377                  _request_timeout=None):
   378          """Makes the HTTP request using RESTClient."""
   379          if method == "GET":
   380              return self.rest_client.GET(url,
   381                                          query_params=query_params,
   382                                          _preload_content=_preload_content,
   383                                          _request_timeout=_request_timeout,
   384                                          headers=headers)
   385          elif method == "HEAD":
   386              return self.rest_client.HEAD(url,
   387                                           query_params=query_params,
   388                                           _preload_content=_preload_content,
   389                                           _request_timeout=_request_timeout,
   390                                           headers=headers)
   391          elif method == "OPTIONS":
   392              return self.rest_client.OPTIONS(url,
   393                                              query_params=query_params,
   394                                              headers=headers,
   395                                              post_params=post_params,
   396                                              _preload_content=_preload_content,
   397                                              _request_timeout=_request_timeout,
   398                                              body=body)
   399          elif method == "POST":
   400              return self.rest_client.POST(url,
   401                                           query_params=query_params,
   402                                           headers=headers,
   403                                           post_params=post_params,
   404                                           _preload_content=_preload_content,
   405                                           _request_timeout=_request_timeout,
   406                                           body=body)
   407          elif method == "PUT":
   408              return self.rest_client.PUT(url,
   409                                          query_params=query_params,
   410                                          headers=headers,
   411                                          post_params=post_params,
   412                                          _preload_content=_preload_content,
   413                                          _request_timeout=_request_timeout,
   414                                          body=body)
   415          elif method == "PATCH":
   416              return self.rest_client.PATCH(url,
   417                                            query_params=query_params,
   418                                            headers=headers,
   419                                            post_params=post_params,
   420                                            _preload_content=_preload_content,
   421                                            _request_timeout=_request_timeout,
   422                                            body=body)
   423          elif method == "DELETE":
   424              return self.rest_client.DELETE(url,
   425                                             query_params=query_params,
   426                                             headers=headers,
   427                                             _preload_content=_preload_content,
   428                                             _request_timeout=_request_timeout,
   429                                             body=body)
   430          else:
   431              raise ApiValueError(
   432                  "http method must be `GET`, `HEAD`, `OPTIONS`,"
   433                  " `POST`, `PATCH`, `PUT` or `DELETE`."
   434              )
   435  
   436      def parameters_to_tuples(self, params, collection_formats):
   437          """Get parameters as list of tuples, formatting collections.
   438  
   439          :param params: Parameters as dict or list of two-tuples
   440          :param dict collection_formats: Parameter collection formats
   441          :return: Parameters as list of tuples, collections formatted
   442          """
   443          new_params = []
   444          if collection_formats is None:
   445              collection_formats = {}
   446          for k, v in six.iteritems(params) if isinstance(params, dict) else params:  # noqa: E501
   447              if k in collection_formats:
   448                  collection_format = collection_formats[k]
   449                  if collection_format == 'multi':
   450                      new_params.extend((k, value) for value in v)
   451                  else:
   452                      if collection_format == 'ssv':
   453                          delimiter = ' '
   454                      elif collection_format == 'tsv':
   455                          delimiter = '\t'
   456                      elif collection_format == 'pipes':
   457                          delimiter = '|'
   458                      else:  # csv is the default
   459                          delimiter = ','
   460                      new_params.append(
   461                          (k, delimiter.join(str(value) for value in v)))
   462              else:
   463                  new_params.append((k, v))
   464          return new_params
   465  
   466      def files_parameters(self, files=None):
   467          """Builds form parameters.
   468  
   469          :param files: None or a dict with key=param_name and
   470              value is a list of open file objects
   471          :return: List of tuples of form parameters with file data
   472          """
   473          if files is None:
   474              return []
   475  
   476          params = []
   477          for param_name, file_instances in six.iteritems(files):
   478              if file_instances is None:
   479                  # if the file field is nullable, skip None values
   480                  continue
   481              for file_instance in file_instances:
   482                  if file_instance is None:
   483                      # if the file field is nullable, skip None values
   484                      continue
   485                  if file_instance.closed is True:
   486                      raise ApiValueError(
   487                          "Cannot read a closed file. The passed in file_type "
   488                          "for %s must be open." % param_name
   489                      )
   490                  filename = os.path.basename(file_instance.name)
   491                  filedata = file_instance.read()
   492                  mimetype = (mimetypes.guess_type(filename)[0] or
   493                              'application/octet-stream')
   494                  params.append(
   495                      tuple([param_name, tuple([filename, filedata, mimetype])]))
   496                  file_instance.close()
   497  
   498          return params
   499  
   500      def select_header_accept(self, accepts):
   501          """Returns `Accept` based on an array of accepts provided.
   502  
   503          :param accepts: List of headers.
   504          :return: Accept (e.g. application/json).
   505          """
   506          if not accepts:
   507              return
   508  
   509          accepts = [x.lower() for x in accepts]
   510  
   511          if 'application/json' in accepts:
   512              return 'application/json'
   513          else:
   514              return ', '.join(accepts)
   515  
   516      def select_header_content_type(self, content_types):
   517          """Returns `Content-Type` based on an array of content_types provided.
   518  
   519          :param content_types: List of content-types.
   520          :return: Content-Type (e.g. application/json).
   521          """
   522          if not content_types:
   523              return 'application/json'
   524  
   525          content_types = [x.lower() for x in content_types]
   526  
   527          if 'application/json' in content_types or '*/*' in content_types:
   528              return 'application/json'
   529          else:
   530              return content_types[0]
   531  
   532      def update_params_for_auth(self, headers, querys, auth_settings,
   533                                 resource_path, method, body):
   534          """Updates header and query params based on authentication setting.
   535  
   536          :param headers: Header parameters dict to be updated.
   537          :param querys: Query parameters tuple list to be updated.
   538          :param auth_settings: Authentication setting identifiers list.
   539          :resource_path: A string representation of the HTTP request resource path.
   540          :method: A string representation of the HTTP request method.
   541          :body: A object representing the body of the HTTP request.
   542              The object type is the return value of sanitize_for_serialization().
   543          """
   544          if not auth_settings:
   545              return
   546  
   547          for auth in auth_settings:
   548              auth_setting = self.configuration.auth_settings().get(auth)
   549              if auth_setting:
   550                  if auth_setting['in'] == 'cookie':
   551                      headers['Cookie'] = auth_setting['value']
   552                  elif auth_setting['in'] == 'header':
   553                      if auth_setting['type'] != 'http-signature':
   554                          headers[auth_setting['key']] = auth_setting['value']
   555  {{#hasHttpSignatureMethods}}
   556                      else:
   557                          # The HTTP signature scheme requires multiple HTTP headers
   558                          # that are calculated dynamically.
   559                          signing_info = self.configuration.signing_info
   560                          auth_headers = signing_info.get_http_signature_headers(
   561                                              resource_path, method, headers, body, querys)
   562                          headers.update(auth_headers)
   563  {{/hasHttpSignatureMethods}}
   564                  elif auth_setting['in'] == 'query':
   565                      querys.append((auth_setting['key'], auth_setting['value']))
   566                  else:
   567                      raise ApiValueError(
   568                          'Authentication token must be in `query` or `header`'
   569                      )