You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
29 KiB

2 years ago
  1. # coding: utf-8
  2. """
  3. Seaweedfs Master Server API
  4. The Seaweedfs Master Server API allows you to store blobs # noqa: E501
  5. The version of the OpenAPI document: 3.43.0
  6. Generated by: https://openapi-generator.tech
  7. """
  8. from __future__ import absolute_import
  9. import atexit
  10. import datetime
  11. from dateutil.parser import parse
  12. import json
  13. import mimetypes
  14. from multiprocessing.pool import ThreadPool
  15. import os
  16. import re
  17. import tempfile
  18. from urllib.parse import quote
  19. from openapi_client.configuration import Configuration
  20. import openapi_client.models
  21. from openapi_client import rest
  22. from openapi_client.exceptions import ApiValueError, ApiException
  23. class ApiClient(object):
  24. """Generic API client for OpenAPI client library builds.
  25. OpenAPI generic API client. This client handles the client-
  26. server communication, and is invariant across implementations. Specifics of
  27. the methods and models for each application are generated from the OpenAPI
  28. templates.
  29. NOTE: This class is auto generated by OpenAPI Generator.
  30. Ref: https://openapi-generator.tech
  31. Do not edit the class manually.
  32. :param configuration: .Configuration object for this client
  33. :param header_name: a header to pass when making calls to the API.
  34. :param header_value: a header value to pass when making calls to
  35. the API.
  36. :param cookie: a cookie to include in the header when making calls
  37. to the API
  38. :param pool_threads: The number of threads to use for async requests
  39. to the API. More threads means more concurrent API requests.
  40. """
  41. PRIMITIVE_TYPES = (float, bool, bytes, str, int)
  42. NATIVE_TYPES_MAPPING = {
  43. 'int': int,
  44. 'long': int, # TODO remove as only py3 is supported?
  45. 'float': float,
  46. 'str': str,
  47. 'bool': bool,
  48. 'date': datetime.date,
  49. 'datetime': datetime.datetime,
  50. 'object': object,
  51. }
  52. _pool = None
  53. def __init__(self, configuration=None, header_name=None, header_value=None,
  54. cookie=None, pool_threads=1):
  55. # use default configuraiton if none is provided
  56. if configuration is None:
  57. configuration = Configuration.get_default()
  58. self.configuration = configuration
  59. self.pool_threads = pool_threads
  60. self.rest_client = rest.RESTClientObject(configuration)
  61. self.default_headers = {}
  62. if header_name is not None:
  63. self.default_headers[header_name] = header_value
  64. self.cookie = cookie
  65. # Set default User-Agent.
  66. self.user_agent = 'OpenAPI-Generator/1.0.0/python'
  67. self.client_side_validation = configuration.client_side_validation
  68. def __enter__(self):
  69. return self
  70. def __exit__(self, exc_type, exc_value, traceback):
  71. self.close()
  72. def close(self):
  73. if self._pool:
  74. self._pool.close()
  75. self._pool.join()
  76. self._pool = None
  77. if hasattr(atexit, 'unregister'):
  78. atexit.unregister(self.close)
  79. @property
  80. def pool(self):
  81. """Create thread pool on first request
  82. avoids instantiating unused threadpool for blocking clients.
  83. """
  84. if self._pool is None:
  85. atexit.register(self.close)
  86. self._pool = ThreadPool(self.pool_threads)
  87. return self._pool
  88. @property
  89. def user_agent(self):
  90. """User agent for this API client"""
  91. return self.default_headers['User-Agent']
  92. @user_agent.setter
  93. def user_agent(self, value):
  94. self.default_headers['User-Agent'] = value
  95. def set_default_header(self, header_name, header_value):
  96. self.default_headers[header_name] = header_value
  97. _default = None
  98. @classmethod
  99. def get_default(cls):
  100. """Return new instance of ApiClient.
  101. This method returns newly created, based on default constructor,
  102. object of ApiClient class or returns a copy of default
  103. ApiClient.
  104. :return: The ApiClient object.
  105. """
  106. if cls._default is None:
  107. cls._default = ApiClient()
  108. return cls._default
  109. @classmethod
  110. def set_default(cls, default):
  111. """Set default instance of ApiClient.
  112. It stores default ApiClient.
  113. :param default: object of ApiClient.
  114. """
  115. cls._default = default
  116. def __call_api(
  117. self, resource_path, method, path_params=None,
  118. query_params=None, header_params=None, body=None, post_params=None,
  119. files=None, response_types_map=None, auth_settings=None,
  120. _return_http_data_only=None, collection_formats=None,
  121. _preload_content=True, _request_timeout=None, _host=None,
  122. _request_auth=None):
  123. config = self.configuration
  124. # header parameters
  125. header_params = header_params or {}
  126. header_params.update(self.default_headers)
  127. if self.cookie:
  128. header_params['Cookie'] = self.cookie
  129. if header_params:
  130. header_params = self.sanitize_for_serialization(header_params)
  131. header_params = dict(self.parameters_to_tuples(header_params,
  132. collection_formats))
  133. # path parameters
  134. if path_params:
  135. path_params = self.sanitize_for_serialization(path_params)
  136. path_params = self.parameters_to_tuples(path_params,
  137. collection_formats)
  138. for k, v in path_params:
  139. # specified safe chars, encode everything
  140. resource_path = resource_path.replace(
  141. '{%s}' % k,
  142. quote(str(v), safe=config.safe_chars_for_path_param)
  143. )
  144. # post parameters
  145. if post_params or files:
  146. post_params = post_params if post_params else []
  147. post_params = self.sanitize_for_serialization(post_params)
  148. post_params = self.parameters_to_tuples(post_params,
  149. collection_formats)
  150. post_params.extend(self.files_parameters(files))
  151. # auth setting
  152. self.update_params_for_auth(
  153. header_params, query_params, auth_settings,
  154. resource_path, method, body,
  155. request_auth=_request_auth)
  156. # body
  157. if body:
  158. body = self.sanitize_for_serialization(body)
  159. # request url
  160. if _host is None:
  161. url = self.configuration.host + resource_path
  162. else:
  163. # use server/host defined in path or operation instead
  164. url = _host + resource_path
  165. # query parameters
  166. if query_params:
  167. query_params = self.sanitize_for_serialization(query_params)
  168. url_query = self.parameters_to_url_query(query_params,
  169. collection_formats)
  170. url += "?" + url_query
  171. try:
  172. # perform request and return response
  173. response_data = self.request(
  174. method, url,
  175. query_params=query_params,
  176. headers=header_params,
  177. post_params=post_params, body=body,
  178. _preload_content=_preload_content,
  179. _request_timeout=_request_timeout)
  180. except ApiException as e:
  181. if e.body:
  182. e.body = e.body.decode('utf-8')
  183. raise e
  184. self.last_response = response_data
  185. return_data = response_data
  186. if not _preload_content:
  187. return return_data
  188. response_type = response_types_map.get(str(response_data.status), None)
  189. if response_type not in ["file", "bytes"]:
  190. match = None
  191. content_type = response_data.getheader('content-type')
  192. if content_type is not None:
  193. match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
  194. encoding = match.group(1) if match else "utf-8"
  195. response_data.data = response_data.data.decode(encoding)
  196. # deserialize response data
  197. if response_type:
  198. return_data = self.deserialize(response_data, response_type)
  199. else:
  200. return_data = None
  201. if _return_http_data_only:
  202. return (return_data)
  203. else:
  204. return (return_data, response_data.status,
  205. response_data.getheaders())
  206. def sanitize_for_serialization(self, obj):
  207. """Builds a JSON POST object.
  208. If obj is None, return None.
  209. If obj is str, int, long, float, bool, return directly.
  210. If obj is datetime.datetime, datetime.date
  211. convert to string in iso8601 format.
  212. If obj is list, sanitize each element in the list.
  213. If obj is dict, return the dict.
  214. If obj is OpenAPI model, return the properties dict.
  215. :param obj: The data to serialize.
  216. :return: The serialized form of data.
  217. """
  218. if obj is None:
  219. return None
  220. elif isinstance(obj, self.PRIMITIVE_TYPES):
  221. return obj
  222. elif isinstance(obj, list):
  223. return [self.sanitize_for_serialization(sub_obj)
  224. for sub_obj in obj]
  225. elif isinstance(obj, tuple):
  226. return tuple(self.sanitize_for_serialization(sub_obj)
  227. for sub_obj in obj)
  228. elif isinstance(obj, (datetime.datetime, datetime.date)):
  229. return obj.isoformat()
  230. if isinstance(obj, dict):
  231. obj_dict = obj
  232. else:
  233. # Convert model obj to dict except
  234. # attributes `openapi_types`, `attribute_map`
  235. # and attributes which value is not None.
  236. # Convert attribute name to json key in
  237. # model definition for request.
  238. obj_dict = obj.to_dict()
  239. return {key: self.sanitize_for_serialization(val)
  240. for key, val in obj_dict.items()}
  241. def deserialize(self, response, response_type):
  242. """Deserializes response into an object.
  243. :param response: RESTResponse object to be deserialized.
  244. :param response_type: class literal for
  245. deserialized object, or string of class name.
  246. :return: deserialized object.
  247. """
  248. # handle file downloading
  249. # save response body into a tmp file and return the instance
  250. if response_type == "file":
  251. return self.__deserialize_file(response)
  252. # fetch data from response object
  253. try:
  254. data = json.loads(response.data)
  255. except ValueError:
  256. data = response.data
  257. return self.__deserialize(data, response_type)
  258. def __deserialize(self, data, klass):
  259. """Deserializes dict, list, str into an object.
  260. :param data: dict, list or str.
  261. :param klass: class literal, or string of class name.
  262. :return: object.
  263. """
  264. if data is None:
  265. return None
  266. if type(klass) == str:
  267. if klass.startswith('List['):
  268. sub_kls = re.match(r'List\[(.*)]', klass).group(1)
  269. return [self.__deserialize(sub_data, sub_kls)
  270. for sub_data in data]
  271. if klass.startswith('Dict['):
  272. sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2)
  273. return {k: self.__deserialize(v, sub_kls)
  274. for k, v in data.items()}
  275. # convert str to class
  276. if klass in self.NATIVE_TYPES_MAPPING:
  277. klass = self.NATIVE_TYPES_MAPPING[klass]
  278. else:
  279. klass = getattr(openapi_client.models, klass)
  280. if klass in self.PRIMITIVE_TYPES:
  281. return self.__deserialize_primitive(data, klass)
  282. elif klass == object:
  283. return self.__deserialize_object(data)
  284. elif klass == datetime.date:
  285. return self.__deserialize_date(data)
  286. elif klass == datetime.datetime:
  287. return self.__deserialize_datetime(data)
  288. else:
  289. return self.__deserialize_model(data, klass)
  290. def call_api(self, resource_path, method,
  291. path_params=None, query_params=None, header_params=None,
  292. body=None, post_params=None, files=None,
  293. response_types_map=None, auth_settings=None,
  294. async_req=None, _return_http_data_only=None,
  295. collection_formats=None,_preload_content=True,
  296. _request_timeout=None, _host=None, _request_auth=None):
  297. """Makes the HTTP request (synchronous) and returns deserialized data.
  298. To make an async_req request, set the async_req parameter.
  299. :param resource_path: Path to method endpoint.
  300. :param method: Method to call.
  301. :param path_params: Path parameters in the url.
  302. :param query_params: Query parameters in the url.
  303. :param header_params: Header parameters to be
  304. placed in the request header.
  305. :param body: Request body.
  306. :param post_params dict: Request post form parameters,
  307. for `application/x-www-form-urlencoded`, `multipart/form-data`.
  308. :param auth_settings list: Auth Settings names for the request.
  309. :param response: Response data type.
  310. :param files dict: key -> filename, value -> filepath,
  311. for `multipart/form-data`.
  312. :param async_req bool: execute request asynchronously
  313. :param _return_http_data_only: response data without head status code
  314. and headers
  315. :param collection_formats: dict of collection formats for path, query,
  316. header, and post parameters.
  317. :param _preload_content: if False, the urllib3.HTTPResponse object will
  318. be returned without reading/decoding response
  319. data. Default is True.
  320. :param _request_timeout: timeout setting for this request. If one
  321. number provided, it will be total request
  322. timeout. It can also be a pair (tuple) of
  323. (connection, read) timeouts.
  324. :param _request_auth: set to override the auth_settings for an a single
  325. request; this effectively ignores the authentication
  326. in the spec for a single request.
  327. :type _request_token: dict, optional
  328. :return:
  329. If async_req parameter is True,
  330. the request will be called asynchronously.
  331. The method will return the request thread.
  332. If parameter async_req is False or missing,
  333. then the method will return the response directly.
  334. """
  335. if not async_req:
  336. return self.__call_api(resource_path, method,
  337. path_params, query_params, header_params,
  338. body, post_params, files,
  339. response_types_map, auth_settings,
  340. _return_http_data_only, collection_formats,
  341. _preload_content, _request_timeout, _host,
  342. _request_auth)
  343. return self.pool.apply_async(self.__call_api, (resource_path,
  344. method, path_params,
  345. query_params,
  346. header_params, body,
  347. post_params, files,
  348. response_types_map,
  349. auth_settings,
  350. _return_http_data_only,
  351. collection_formats,
  352. _preload_content,
  353. _request_timeout,
  354. _host, _request_auth))
  355. def request(self, method, url, query_params=None, headers=None,
  356. post_params=None, body=None, _preload_content=True,
  357. _request_timeout=None):
  358. """Makes the HTTP request using RESTClient."""
  359. if method == "GET":
  360. return self.rest_client.get_request(url,
  361. query_params=query_params,
  362. _preload_content=_preload_content,
  363. _request_timeout=_request_timeout,
  364. headers=headers)
  365. elif method == "HEAD":
  366. return self.rest_client.head_request(url,
  367. query_params=query_params,
  368. _preload_content=_preload_content,
  369. _request_timeout=_request_timeout,
  370. headers=headers)
  371. elif method == "OPTIONS":
  372. return self.rest_client.options_request(url,
  373. query_params=query_params,
  374. headers=headers,
  375. _preload_content=_preload_content,
  376. _request_timeout=_request_timeout)
  377. elif method == "POST":
  378. return self.rest_client.post_request(url,
  379. query_params=query_params,
  380. headers=headers,
  381. post_params=post_params,
  382. _preload_content=_preload_content,
  383. _request_timeout=_request_timeout,
  384. body=body)
  385. elif method == "PUT":
  386. return self.rest_client.put_request(url,
  387. query_params=query_params,
  388. headers=headers,
  389. post_params=post_params,
  390. _preload_content=_preload_content,
  391. _request_timeout=_request_timeout,
  392. body=body)
  393. elif method == "PATCH":
  394. return self.rest_client.patch_request(url,
  395. query_params=query_params,
  396. headers=headers,
  397. post_params=post_params,
  398. _preload_content=_preload_content,
  399. _request_timeout=_request_timeout,
  400. body=body)
  401. elif method == "DELETE":
  402. return self.rest_client.delete_request(url,
  403. query_params=query_params,
  404. headers=headers,
  405. _preload_content=_preload_content,
  406. _request_timeout=_request_timeout,
  407. body=body)
  408. else:
  409. raise ApiValueError(
  410. "http method must be `GET`, `HEAD`, `OPTIONS`,"
  411. " `POST`, `PATCH`, `PUT` or `DELETE`."
  412. )
  413. def parameters_to_tuples(self, params, collection_formats):
  414. """Get parameters as list of tuples, formatting collections.
  415. :param params: Parameters as dict or list of two-tuples
  416. :param dict collection_formats: Parameter collection formats
  417. :return: Parameters as list of tuples, collections formatted
  418. """
  419. new_params = []
  420. if collection_formats is None:
  421. collection_formats = {}
  422. for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
  423. if k in collection_formats:
  424. collection_format = collection_formats[k]
  425. if collection_format == 'multi':
  426. new_params.extend((k, value) for value in v)
  427. else:
  428. if collection_format == 'ssv':
  429. delimiter = ' '
  430. elif collection_format == 'tsv':
  431. delimiter = '\t'
  432. elif collection_format == 'pipes':
  433. delimiter = '|'
  434. else: # csv is the default
  435. delimiter = ','
  436. new_params.append(
  437. (k, delimiter.join(str(value) for value in v)))
  438. else:
  439. new_params.append((k, v))
  440. return new_params
  441. def parameters_to_url_query(self, params, collection_formats):
  442. """Get parameters as list of tuples, formatting collections.
  443. :param params: Parameters as dict or list of two-tuples
  444. :param dict collection_formats: Parameter collection formats
  445. :return: URL query string (e.g. a=Hello%20World&b=123)
  446. """
  447. new_params = []
  448. if collection_formats is None:
  449. collection_formats = {}
  450. for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
  451. if isinstance(v, (int, float)):
  452. v = str(v)
  453. if isinstance(v, bool):
  454. v = str(v).lower()
  455. if k in collection_formats:
  456. collection_format = collection_formats[k]
  457. if collection_format == 'multi':
  458. new_params.extend((k, value) for value in v)
  459. else:
  460. if collection_format == 'ssv':
  461. delimiter = ' '
  462. elif collection_format == 'tsv':
  463. delimiter = '\t'
  464. elif collection_format == 'pipes':
  465. delimiter = '|'
  466. else: # csv is the default
  467. delimiter = ','
  468. new_params.append(
  469. (k, delimiter.join(quote(str(value)) for value in v)))
  470. else:
  471. new_params.append((k, v))
  472. return "&".join(["=".join(item) for item in new_params])
  473. def files_parameters(self, files=None):
  474. """Builds form parameters.
  475. :param files: File parameters.
  476. :return: Form parameters with files.
  477. """
  478. params = []
  479. if files:
  480. for k, v in files.items():
  481. if not v:
  482. continue
  483. file_names = v if type(v) is list else [v]
  484. for n in file_names:
  485. with open(n, 'rb') as f:
  486. filename = os.path.basename(f.name)
  487. filedata = f.read()
  488. mimetype = (mimetypes.guess_type(filename)[0] or
  489. 'application/octet-stream')
  490. params.append(
  491. tuple([k, tuple([filename, filedata, mimetype])]))
  492. return params
  493. def select_header_accept(self, accepts):
  494. """Returns `Accept` based on an array of accepts provided.
  495. :param accepts: List of headers.
  496. :return: Accept (e.g. application/json).
  497. """
  498. if not accepts:
  499. return
  500. for accept in accepts:
  501. if re.search('json', accept, re.IGNORECASE):
  502. return accept
  503. return accepts[0]
  504. def select_header_content_type(self, content_types):
  505. """Returns `Content-Type` based on an array of content_types provided.
  506. :param content_types: List of content-types.
  507. :return: Content-Type (e.g. application/json).
  508. """
  509. if not content_types:
  510. return None
  511. for content_type in content_types:
  512. if re.search('json', content_type, re.IGNORECASE):
  513. return content_type
  514. return content_types[0]
  515. def update_params_for_auth(self, headers, queries, auth_settings,
  516. resource_path, method, body,
  517. request_auth=None):
  518. """Updates header and query params based on authentication setting.
  519. :param headers: Header parameters dict to be updated.
  520. :param queries: Query parameters tuple list to be updated.
  521. :param auth_settings: Authentication setting identifiers list.
  522. :resource_path: A string representation of the HTTP request resource path.
  523. :method: A string representation of the HTTP request method.
  524. :body: A object representing the body of the HTTP request.
  525. The object type is the return value of sanitize_for_serialization().
  526. :param request_auth: if set, the provided settings will
  527. override the token in the configuration.
  528. """
  529. if not auth_settings:
  530. return
  531. if request_auth:
  532. self._apply_auth_params(headers, queries,
  533. resource_path, method, body,
  534. request_auth)
  535. return
  536. for auth in auth_settings:
  537. auth_setting = self.configuration.auth_settings().get(auth)
  538. if auth_setting:
  539. self._apply_auth_params(headers, queries,
  540. resource_path, method, body,
  541. auth_setting)
  542. def _apply_auth_params(self, headers, queries,
  543. resource_path, method, body,
  544. auth_setting):
  545. """Updates the request parameters based on a single auth_setting
  546. :param headers: Header parameters dict to be updated.
  547. :param queries: Query parameters tuple list to be updated.
  548. :resource_path: A string representation of the HTTP request resource path.
  549. :method: A string representation of the HTTP request method.
  550. :body: A object representing the body of the HTTP request.
  551. The object type is the return value of sanitize_for_serialization().
  552. :param auth_setting: auth settings for the endpoint
  553. """
  554. if auth_setting['in'] == 'cookie':
  555. headers['Cookie'] = auth_setting['value']
  556. elif auth_setting['in'] == 'header':
  557. if auth_setting['type'] != 'http-signature':
  558. headers[auth_setting['key']] = auth_setting['value']
  559. elif auth_setting['in'] == 'query':
  560. queries.append((auth_setting['key'], auth_setting['value']))
  561. else:
  562. raise ApiValueError(
  563. 'Authentication token must be in `query` or `header`'
  564. )
  565. def __deserialize_file(self, response):
  566. """Deserializes body to file
  567. Saves response body into a file in a temporary folder,
  568. using the filename from the `Content-Disposition` header if provided.
  569. :param response: RESTResponse.
  570. :return: file path.
  571. """
  572. fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
  573. os.close(fd)
  574. os.remove(path)
  575. content_disposition = response.getheader("Content-Disposition")
  576. if content_disposition:
  577. filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?',
  578. content_disposition).group(1)
  579. path = os.path.join(os.path.dirname(path), filename)
  580. with open(path, "wb") as f:
  581. f.write(response.data)
  582. return path
  583. def __deserialize_primitive(self, data, klass):
  584. """Deserializes string to primitive type.
  585. :param data: str.
  586. :param klass: class literal.
  587. :return: int, long, float, str, bool.
  588. """
  589. try:
  590. return klass(data)
  591. except UnicodeEncodeError:
  592. return str(data)
  593. except TypeError:
  594. return data
  595. def __deserialize_object(self, value):
  596. """Return an original value.
  597. :return: object.
  598. """
  599. return value
  600. def __deserialize_date(self, string):
  601. """Deserializes string to date.
  602. :param string: str.
  603. :return: date.
  604. """
  605. try:
  606. return parse(string).date()
  607. except ImportError:
  608. return string
  609. except ValueError:
  610. raise rest.ApiException(
  611. status=0,
  612. reason="Failed to parse `{0}` as date object".format(string)
  613. )
  614. def __deserialize_datetime(self, string):
  615. """Deserializes string to datetime.
  616. The string should be in iso8601 datetime format.
  617. :param string: str.
  618. :return: datetime.
  619. """
  620. try:
  621. return parse(string)
  622. except ImportError:
  623. return string
  624. except ValueError:
  625. raise rest.ApiException(
  626. status=0,
  627. reason=(
  628. "Failed to parse `{0}` as datetime object"
  629. .format(string)
  630. )
  631. )
  632. def __deserialize_model(self, data, klass):
  633. """Deserializes list or dict to model.
  634. :param data: dict, list.
  635. :param klass: class literal.
  636. :return: model object.
  637. """
  638. return klass.from_dict(data)