lighter-sdk 0.1.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. lighter/__init__.py +140 -0
  2. lighter/api/__init__.py +11 -0
  3. lighter/api/account_api.py +2371 -0
  4. lighter/api/block_api.py +863 -0
  5. lighter/api/candlestick_api.py +718 -0
  6. lighter/api/info_api.py +282 -0
  7. lighter/api/order_api.py +2734 -0
  8. lighter/api/root_api.py +529 -0
  9. lighter/api/transaction_api.py +3525 -0
  10. lighter/api_client.py +784 -0
  11. lighter/api_response.py +21 -0
  12. lighter/configuration.py +475 -0
  13. lighter/exceptions.py +199 -0
  14. lighter/models/__init__.py +112 -0
  15. lighter/models/account.py +110 -0
  16. lighter/models/account_api_keys.py +104 -0
  17. lighter/models/account_market_stats.py +98 -0
  18. lighter/models/account_metadata.py +94 -0
  19. lighter/models/account_pn_l.py +106 -0
  20. lighter/models/account_position.py +112 -0
  21. lighter/models/account_stats.py +102 -0
  22. lighter/models/accounts.py +106 -0
  23. lighter/models/api_key.py +98 -0
  24. lighter/models/block.py +124 -0
  25. lighter/models/blocks.py +106 -0
  26. lighter/models/bridge_supported_network.py +96 -0
  27. lighter/models/candlestick.py +106 -0
  28. lighter/models/candlesticks.py +106 -0
  29. lighter/models/contract_address.py +94 -0
  30. lighter/models/current_height.py +96 -0
  31. lighter/models/cursor.py +92 -0
  32. lighter/models/deposit_history.py +106 -0
  33. lighter/models/deposit_history_item.py +105 -0
  34. lighter/models/detailed_account.py +152 -0
  35. lighter/models/detailed_accounts.py +106 -0
  36. lighter/models/detailed_candlestick.py +108 -0
  37. lighter/models/enriched_tx.py +129 -0
  38. lighter/models/exchange_stats.py +110 -0
  39. lighter/models/fee_bucket.py +96 -0
  40. lighter/models/funding.py +98 -0
  41. lighter/models/fundings.py +106 -0
  42. lighter/models/is_whitelisted.py +98 -0
  43. lighter/models/l1_provider_info.py +98 -0
  44. lighter/models/layer2_basic_info.py +100 -0
  45. lighter/models/liquidation.py +100 -0
  46. lighter/models/market_info.py +116 -0
  47. lighter/models/next_nonce.py +96 -0
  48. lighter/models/order.py +159 -0
  49. lighter/models/order_book.py +119 -0
  50. lighter/models/order_book_depth.py +115 -0
  51. lighter/models/order_book_detail.py +151 -0
  52. lighter/models/order_book_details.py +104 -0
  53. lighter/models/order_book_orders.py +117 -0
  54. lighter/models/order_book_stats.py +102 -0
  55. lighter/models/order_books.py +104 -0
  56. lighter/models/orders.py +106 -0
  57. lighter/models/pn_l_entry.py +94 -0
  58. lighter/models/position_funding.py +111 -0
  59. lighter/models/price_level.py +94 -0
  60. lighter/models/public_pool.py +128 -0
  61. lighter/models/public_pool_info.py +100 -0
  62. lighter/models/public_pool_share.py +96 -0
  63. lighter/models/public_pools.py +106 -0
  64. lighter/models/req_get_account.py +101 -0
  65. lighter/models/req_get_account_active_orders.py +96 -0
  66. lighter/models/req_get_account_api_keys.py +94 -0
  67. lighter/models/req_get_account_by_l1_address.py +92 -0
  68. lighter/models/req_get_account_inactive_orders.py +103 -0
  69. lighter/models/req_get_account_orders.py +99 -0
  70. lighter/models/req_get_account_pending_txs.py +106 -0
  71. lighter/models/req_get_account_pn_l.py +118 -0
  72. lighter/models/req_get_account_txs.py +111 -0
  73. lighter/models/req_get_block.py +101 -0
  74. lighter/models/req_get_block_txs.py +101 -0
  75. lighter/models/req_get_by_account.py +101 -0
  76. lighter/models/req_get_candlesticks.py +109 -0
  77. lighter/models/req_get_deposit_history.py +106 -0
  78. lighter/models/req_get_fee_bucket.py +92 -0
  79. lighter/models/req_get_fundings.py +107 -0
  80. lighter/models/req_get_l1_tx.py +92 -0
  81. lighter/models/req_get_latest_deposit.py +92 -0
  82. lighter/models/req_get_next_nonce.py +94 -0
  83. lighter/models/req_get_order_book_details.py +92 -0
  84. lighter/models/req_get_order_book_orders.py +95 -0
  85. lighter/models/req_get_order_books.py +92 -0
  86. lighter/models/req_get_public_pools.py +109 -0
  87. lighter/models/req_get_range_with_cursor.py +95 -0
  88. lighter/models/req_get_range_with_index.py +95 -0
  89. lighter/models/req_get_range_with_index_sortable.py +107 -0
  90. lighter/models/req_get_recent_trades.py +95 -0
  91. lighter/models/req_get_trades.py +126 -0
  92. lighter/models/req_get_tx.py +101 -0
  93. lighter/models/req_get_withdraw_history.py +106 -0
  94. lighter/models/req_is_whitelisted.py +92 -0
  95. lighter/models/result_code.py +94 -0
  96. lighter/models/simple_order.py +102 -0
  97. lighter/models/status.py +94 -0
  98. lighter/models/sub_accounts.py +106 -0
  99. lighter/models/ticker.py +103 -0
  100. lighter/models/trade.py +125 -0
  101. lighter/models/trades.py +106 -0
  102. lighter/models/tx.py +121 -0
  103. lighter/models/tx_hash.py +96 -0
  104. lighter/models/tx_hashes.py +96 -0
  105. lighter/models/txs.py +104 -0
  106. lighter/models/validator_info.py +94 -0
  107. lighter/models/withdraw_history.py +110 -0
  108. lighter/models/withdraw_history_cursor.py +94 -0
  109. lighter/models/withdraw_history_item.py +114 -0
  110. lighter/models/zk_lighter_info.py +92 -0
  111. lighter/py.typed +0 -0
  112. lighter/rest.py +215 -0
  113. lighter/signer_client.py +440 -0
  114. lighter/signers/signer-amd64.so +0 -0
  115. lighter/signers/signer-arm64.dylib +0 -0
  116. lighter/transactions/__init__.py +3 -0
  117. lighter/transactions/cancel_order.py +27 -0
  118. lighter/transactions/create_order.py +33 -0
  119. lighter/transactions/withdraw.py +25 -0
  120. lighter/ws_client.py +160 -0
  121. lighter_sdk-0.1.0.dist-info/LICENSE +201 -0
  122. lighter_sdk-0.1.0.dist-info/METADATA +26 -0
  123. lighter_sdk-0.1.0.dist-info/RECORD +125 -0
  124. lighter_sdk-0.1.0.dist-info/WHEEL +5 -0
  125. lighter_sdk-0.1.0.dist-info/top_level.txt +1 -0
lighter/api_client.py ADDED
@@ -0,0 +1,784 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+
5
+
6
+ No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
7
+
8
+ The version of the OpenAPI document:
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ import datetime
16
+ from dateutil.parser import parse
17
+ from enum import Enum
18
+ import json
19
+ import mimetypes
20
+ import os
21
+ import re
22
+ import tempfile
23
+
24
+ from urllib.parse import quote
25
+ from typing import Tuple, Optional, List, Dict, Union
26
+ from pydantic import SecretStr
27
+
28
+ from lighter.configuration import Configuration
29
+ from lighter.api_response import ApiResponse, T as ApiResponseT
30
+ import lighter.models
31
+ from lighter import rest
32
+ from lighter.exceptions import (
33
+ ApiValueError,
34
+ ApiException,
35
+ BadRequestException,
36
+ UnauthorizedException,
37
+ ForbiddenException,
38
+ NotFoundException,
39
+ ServiceException
40
+ )
41
+
42
+ RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]]
43
+
44
+ class ApiClient:
45
+ """Generic API client for OpenAPI client library builds.
46
+
47
+ OpenAPI generic API client. This client handles the client-
48
+ server communication, and is invariant across implementations. Specifics of
49
+ the methods and models for each application are generated from the OpenAPI
50
+ templates.
51
+
52
+ :param configuration: .Configuration object for this client
53
+ :param header_name: a header to pass when making calls to the API.
54
+ :param header_value: a header value to pass when making calls to
55
+ the API.
56
+ :param cookie: a cookie to include in the header when making calls
57
+ to the API
58
+ """
59
+
60
+ PRIMITIVE_TYPES = (float, bool, bytes, str, int)
61
+ NATIVE_TYPES_MAPPING = {
62
+ 'int': int,
63
+ 'long': int, # TODO remove as only py3 is supported?
64
+ 'float': float,
65
+ 'str': str,
66
+ 'bool': bool,
67
+ 'date': datetime.date,
68
+ 'datetime': datetime.datetime,
69
+ 'object': object,
70
+ }
71
+ _pool = None
72
+
73
+ def __init__(
74
+ self,
75
+ configuration=None,
76
+ header_name=None,
77
+ header_value=None,
78
+ cookie=None
79
+ ) -> None:
80
+ # use default configuration if none is provided
81
+ if configuration is None:
82
+ configuration = Configuration.get_default()
83
+ self.configuration = configuration
84
+
85
+ self.rest_client = rest.RESTClientObject(configuration)
86
+ self.default_headers = {}
87
+ if header_name is not None:
88
+ self.default_headers[header_name] = header_value
89
+ self.cookie = cookie
90
+ # Set default User-Agent.
91
+ self.user_agent = 'OpenAPI-Generator/1.0.0/python'
92
+ self.client_side_validation = configuration.client_side_validation
93
+
94
+ async def __aenter__(self):
95
+ return self
96
+
97
+ async def __aexit__(self, exc_type, exc_value, traceback):
98
+ await self.close()
99
+
100
+ async def close(self):
101
+ await self.rest_client.close()
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
+
116
+ _default = None
117
+
118
+ @classmethod
119
+ def get_default(cls):
120
+ """Return new instance of ApiClient.
121
+
122
+ This method returns newly created, based on default constructor,
123
+ object of ApiClient class or returns a copy of default
124
+ ApiClient.
125
+
126
+ :return: The ApiClient object.
127
+ """
128
+ if cls._default is None:
129
+ cls._default = ApiClient()
130
+ return cls._default
131
+
132
+ @classmethod
133
+ def set_default(cls, default):
134
+ """Set default instance of ApiClient.
135
+
136
+ It stores default ApiClient.
137
+
138
+ :param default: object of ApiClient.
139
+ """
140
+ cls._default = default
141
+
142
+ def param_serialize(
143
+ self,
144
+ method,
145
+ resource_path,
146
+ path_params=None,
147
+ query_params=None,
148
+ header_params=None,
149
+ body=None,
150
+ post_params=None,
151
+ files=None, auth_settings=None,
152
+ collection_formats=None,
153
+ _host=None,
154
+ _request_auth=None
155
+ ) -> RequestSerialized:
156
+
157
+ """Builds the HTTP request params needed by the request.
158
+ :param method: Method to call.
159
+ :param resource_path: Path to method endpoint.
160
+ :param path_params: Path parameters in the url.
161
+ :param query_params: Query parameters in the url.
162
+ :param header_params: Header parameters to be
163
+ placed in the request header.
164
+ :param body: Request body.
165
+ :param post_params dict: Request post form parameters,
166
+ for `application/x-www-form-urlencoded`, `multipart/form-data`.
167
+ :param auth_settings list: Auth Settings names for the request.
168
+ :param files dict: key -> filename, value -> filepath,
169
+ for `multipart/form-data`.
170
+ :param collection_formats: dict of collection formats for path, query,
171
+ header, and post parameters.
172
+ :param _request_auth: set to override the auth_settings for an a single
173
+ request; this effectively ignores the authentication
174
+ in the spec for a single request.
175
+ :return: tuple of form (path, http_method, query_params, header_params,
176
+ body, post_params, files)
177
+ """
178
+
179
+ config = self.configuration
180
+
181
+ # header parameters
182
+ header_params = header_params or {}
183
+ header_params.update(self.default_headers)
184
+ if self.cookie:
185
+ header_params['Cookie'] = self.cookie
186
+ if header_params:
187
+ header_params = self.sanitize_for_serialization(header_params)
188
+ header_params = dict(
189
+ self.parameters_to_tuples(header_params,collection_formats)
190
+ )
191
+
192
+ # path parameters
193
+ if path_params:
194
+ path_params = self.sanitize_for_serialization(path_params)
195
+ path_params = self.parameters_to_tuples(
196
+ path_params,
197
+ collection_formats
198
+ )
199
+ for k, v in path_params:
200
+ # specified safe chars, encode everything
201
+ resource_path = resource_path.replace(
202
+ '{%s}' % k,
203
+ quote(str(v), safe=config.safe_chars_for_path_param)
204
+ )
205
+
206
+ # post parameters
207
+ if post_params or files:
208
+ post_params = post_params if post_params else []
209
+ post_params = self.sanitize_for_serialization(post_params)
210
+ post_params = self.parameters_to_tuples(
211
+ post_params,
212
+ collection_formats
213
+ )
214
+ if files:
215
+ post_params.extend(self.files_parameters(files))
216
+
217
+ # auth setting
218
+ self.update_params_for_auth(
219
+ header_params,
220
+ query_params,
221
+ auth_settings,
222
+ resource_path,
223
+ method,
224
+ body,
225
+ request_auth=_request_auth
226
+ )
227
+
228
+ # body
229
+ if body:
230
+ body = self.sanitize_for_serialization(body)
231
+
232
+ # request url
233
+ if _host is None or self.configuration.ignore_operation_servers:
234
+ url = self.configuration.host + resource_path
235
+ else:
236
+ # use server/host defined in path or operation instead
237
+ url = _host + resource_path
238
+
239
+ # query parameters
240
+ if query_params:
241
+ query_params = self.sanitize_for_serialization(query_params)
242
+ url_query = self.parameters_to_url_query(
243
+ query_params,
244
+ collection_formats
245
+ )
246
+ url += "?" + url_query
247
+
248
+ return method, url, header_params, body, post_params
249
+
250
+
251
+ async def call_api(
252
+ self,
253
+ method,
254
+ url,
255
+ header_params=None,
256
+ body=None,
257
+ post_params=None,
258
+ _request_timeout=None
259
+ ) -> rest.RESTResponse:
260
+ """Makes the HTTP request (synchronous)
261
+ :param method: Method to call.
262
+ :param url: Path to method endpoint.
263
+ :param header_params: Header parameters to be
264
+ placed in the request header.
265
+ :param body: Request body.
266
+ :param post_params dict: Request post form parameters,
267
+ for `application/x-www-form-urlencoded`, `multipart/form-data`.
268
+ :param _request_timeout: timeout setting for this request.
269
+ :return: RESTResponse
270
+ """
271
+
272
+ try:
273
+ # perform request and return response
274
+ response_data = await self.rest_client.request(
275
+ method, url,
276
+ headers=header_params,
277
+ body=body, post_params=post_params,
278
+ _request_timeout=_request_timeout
279
+ )
280
+
281
+ except ApiException as e:
282
+ raise e
283
+
284
+ return response_data
285
+
286
+ def response_deserialize(
287
+ self,
288
+ response_data: rest.RESTResponse,
289
+ response_types_map: Optional[Dict[str, ApiResponseT]]=None
290
+ ) -> ApiResponse[ApiResponseT]:
291
+ """Deserializes response into an object.
292
+ :param response_data: RESTResponse object to be deserialized.
293
+ :param response_types_map: dict of response types.
294
+ :return: ApiResponse
295
+ """
296
+
297
+ msg = "RESTResponse.read() must be called before passing it to response_deserialize()"
298
+ assert response_data.data is not None, msg
299
+
300
+ response_type = response_types_map.get(str(response_data.status), None)
301
+ if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599:
302
+ # if not found, look for '1XX', '2XX', etc.
303
+ response_type = response_types_map.get(str(response_data.status)[0] + "XX", None)
304
+
305
+ # deserialize response data
306
+ response_text = None
307
+ return_data = None
308
+ try:
309
+ if response_type == "bytearray":
310
+ return_data = response_data.data
311
+ elif response_type == "file":
312
+ return_data = self.__deserialize_file(response_data)
313
+ elif response_type is not None:
314
+ match = None
315
+ content_type = response_data.getheader('content-type')
316
+ if content_type is not None:
317
+ match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
318
+ encoding = match.group(1) if match else "utf-8"
319
+ response_text = response_data.data.decode(encoding)
320
+ return_data = self.deserialize(response_text, response_type, content_type)
321
+ finally:
322
+ if not 200 <= response_data.status <= 299:
323
+ raise ApiException.from_response(
324
+ http_resp=response_data,
325
+ body=response_text,
326
+ data=return_data,
327
+ )
328
+
329
+ return ApiResponse(
330
+ status_code = response_data.status,
331
+ data = return_data,
332
+ headers = response_data.getheaders(),
333
+ raw_data = response_data.data
334
+ )
335
+
336
+ def sanitize_for_serialization(self, obj):
337
+ """Builds a JSON POST object.
338
+
339
+ If obj is None, return None.
340
+ If obj is SecretStr, return obj.get_secret_value()
341
+ If obj is str, int, long, float, bool, return directly.
342
+ If obj is datetime.datetime, datetime.date
343
+ convert to string in iso8601 format.
344
+ If obj is list, sanitize each element in the list.
345
+ If obj is dict, return the dict.
346
+ If obj is OpenAPI model, return the properties dict.
347
+
348
+ :param obj: The data to serialize.
349
+ :return: The serialized form of data.
350
+ """
351
+ if obj is None:
352
+ return None
353
+ elif isinstance(obj, Enum):
354
+ return obj.value
355
+ elif isinstance(obj, SecretStr):
356
+ return obj.get_secret_value()
357
+ elif isinstance(obj, self.PRIMITIVE_TYPES):
358
+ return obj
359
+ elif isinstance(obj, list):
360
+ return [
361
+ self.sanitize_for_serialization(sub_obj) for sub_obj in obj
362
+ ]
363
+ elif isinstance(obj, tuple):
364
+ return tuple(
365
+ self.sanitize_for_serialization(sub_obj) for sub_obj in obj
366
+ )
367
+ elif isinstance(obj, (datetime.datetime, datetime.date)):
368
+ return obj.isoformat()
369
+
370
+ elif isinstance(obj, dict):
371
+ obj_dict = obj
372
+ else:
373
+ # Convert model obj to dict except
374
+ # attributes `openapi_types`, `attribute_map`
375
+ # and attributes which value is not None.
376
+ # Convert attribute name to json key in
377
+ # model definition for request.
378
+ if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
379
+ obj_dict = obj.to_dict()
380
+ else:
381
+ obj_dict = obj.__dict__
382
+
383
+ return {
384
+ key: self.sanitize_for_serialization(val)
385
+ for key, val in obj_dict.items()
386
+ }
387
+
388
+ def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]):
389
+ """Deserializes response into an object.
390
+
391
+ :param response: RESTResponse object to be deserialized.
392
+ :param response_type: class literal for
393
+ deserialized object, or string of class name.
394
+ :param content_type: content type of response.
395
+
396
+ :return: deserialized object.
397
+ """
398
+
399
+ # fetch data from response object
400
+ if content_type is None:
401
+ try:
402
+ data = json.loads(response_text)
403
+ except ValueError:
404
+ data = response_text
405
+ elif content_type.startswith("application/json"):
406
+ if response_text == "":
407
+ data = ""
408
+ else:
409
+ data = json.loads(response_text)
410
+ elif content_type.startswith("text/plain"):
411
+ data = response_text
412
+ else:
413
+ raise ApiException(
414
+ status=0,
415
+ reason="Unsupported content type: {0}".format(content_type)
416
+ )
417
+
418
+ return self.__deserialize(data, response_type)
419
+
420
+ def __deserialize(self, data, klass):
421
+ """Deserializes dict, list, str into an object.
422
+
423
+ :param data: dict, list or str.
424
+ :param klass: class literal, or string of class name.
425
+
426
+ :return: object.
427
+ """
428
+ if data is None:
429
+ return None
430
+
431
+ if isinstance(klass, str):
432
+ if klass.startswith('List['):
433
+ m = re.match(r'List\[(.*)]', klass)
434
+ assert m is not None, "Malformed List type definition"
435
+ sub_kls = m.group(1)
436
+ return [self.__deserialize(sub_data, sub_kls)
437
+ for sub_data in data]
438
+
439
+ if klass.startswith('Dict['):
440
+ m = re.match(r'Dict\[([^,]*), (.*)]', klass)
441
+ assert m is not None, "Malformed Dict type definition"
442
+ sub_kls = m.group(2)
443
+ return {k: self.__deserialize(v, sub_kls)
444
+ for k, v in data.items()}
445
+
446
+ # convert str to class
447
+ if klass in self.NATIVE_TYPES_MAPPING:
448
+ klass = self.NATIVE_TYPES_MAPPING[klass]
449
+ else:
450
+ klass = getattr(lighter.models, klass)
451
+
452
+ if klass in self.PRIMITIVE_TYPES:
453
+ return self.__deserialize_primitive(data, klass)
454
+ elif klass == object:
455
+ return self.__deserialize_object(data)
456
+ elif klass == datetime.date:
457
+ return self.__deserialize_date(data)
458
+ elif klass == datetime.datetime:
459
+ return self.__deserialize_datetime(data)
460
+ elif issubclass(klass, Enum):
461
+ return self.__deserialize_enum(data, klass)
462
+ else:
463
+ return self.__deserialize_model(data, klass)
464
+
465
+ def parameters_to_tuples(self, params, collection_formats):
466
+ """Get parameters as list of tuples, formatting collections.
467
+
468
+ :param params: Parameters as dict or list of two-tuples
469
+ :param dict collection_formats: Parameter collection formats
470
+ :return: Parameters as list of tuples, collections formatted
471
+ """
472
+ new_params: List[Tuple[str, str]] = []
473
+ if collection_formats is None:
474
+ collection_formats = {}
475
+ for k, v in params.items() if isinstance(params, dict) else params:
476
+ if k in collection_formats:
477
+ collection_format = collection_formats[k]
478
+ if collection_format == 'multi':
479
+ new_params.extend((k, value) for value in v)
480
+ else:
481
+ if collection_format == 'ssv':
482
+ delimiter = ' '
483
+ elif collection_format == 'tsv':
484
+ delimiter = '\t'
485
+ elif collection_format == 'pipes':
486
+ delimiter = '|'
487
+ else: # csv is the default
488
+ delimiter = ','
489
+ new_params.append(
490
+ (k, delimiter.join(str(value) for value in v)))
491
+ else:
492
+ new_params.append((k, v))
493
+ return new_params
494
+
495
+ def parameters_to_url_query(self, params, collection_formats):
496
+ """Get parameters as list of tuples, formatting collections.
497
+
498
+ :param params: Parameters as dict or list of two-tuples
499
+ :param dict collection_formats: Parameter collection formats
500
+ :return: URL query string (e.g. a=Hello%20World&b=123)
501
+ """
502
+ new_params: List[Tuple[str, str]] = []
503
+ if collection_formats is None:
504
+ collection_formats = {}
505
+ for k, v in params.items() if isinstance(params, dict) else params:
506
+ if isinstance(v, bool):
507
+ v = str(v).lower()
508
+ if isinstance(v, (int, float)):
509
+ v = str(v)
510
+ if isinstance(v, dict):
511
+ v = json.dumps(v)
512
+
513
+ if k in collection_formats:
514
+ collection_format = collection_formats[k]
515
+ if collection_format == 'multi':
516
+ new_params.extend((k, str(value)) for value in v)
517
+ else:
518
+ if collection_format == 'ssv':
519
+ delimiter = ' '
520
+ elif collection_format == 'tsv':
521
+ delimiter = '\t'
522
+ elif collection_format == 'pipes':
523
+ delimiter = '|'
524
+ else: # csv is the default
525
+ delimiter = ','
526
+ new_params.append(
527
+ (k, delimiter.join(quote(str(value)) for value in v))
528
+ )
529
+ else:
530
+ new_params.append((k, quote(str(v))))
531
+
532
+ return "&".join(["=".join(map(str, item)) for item in new_params])
533
+
534
+ def files_parameters(self, files: Dict[str, Union[str, bytes]]):
535
+ """Builds form parameters.
536
+
537
+ :param files: File parameters.
538
+ :return: Form parameters with files.
539
+ """
540
+ params = []
541
+ for k, v in files.items():
542
+ if isinstance(v, str):
543
+ with open(v, 'rb') as f:
544
+ filename = os.path.basename(f.name)
545
+ filedata = f.read()
546
+ elif isinstance(v, bytes):
547
+ filename = k
548
+ filedata = v
549
+ else:
550
+ raise ValueError("Unsupported file value")
551
+ mimetype = (
552
+ mimetypes.guess_type(filename)[0]
553
+ or 'application/octet-stream'
554
+ )
555
+ params.append(
556
+ tuple([k, tuple([filename, filedata, mimetype])])
557
+ )
558
+ return params
559
+
560
+ def select_header_accept(self, accepts: List[str]) -> Optional[str]:
561
+ """Returns `Accept` based on an array of accepts provided.
562
+
563
+ :param accepts: List of headers.
564
+ :return: Accept (e.g. application/json).
565
+ """
566
+ if not accepts:
567
+ return None
568
+
569
+ for accept in accepts:
570
+ if re.search('json', accept, re.IGNORECASE):
571
+ return accept
572
+
573
+ return accepts[0]
574
+
575
+ def select_header_content_type(self, content_types):
576
+ """Returns `Content-Type` based on an array of content_types provided.
577
+
578
+ :param content_types: List of content-types.
579
+ :return: Content-Type (e.g. application/json).
580
+ """
581
+ if not content_types:
582
+ return None
583
+
584
+ for content_type in content_types:
585
+ if re.search('json', content_type, re.IGNORECASE):
586
+ return content_type
587
+
588
+ return content_types[0]
589
+
590
+ def update_params_for_auth(
591
+ self,
592
+ headers,
593
+ queries,
594
+ auth_settings,
595
+ resource_path,
596
+ method,
597
+ body,
598
+ request_auth=None
599
+ ) -> None:
600
+ """Updates header and query params based on authentication setting.
601
+
602
+ :param headers: Header parameters dict to be updated.
603
+ :param queries: Query parameters tuple list to be updated.
604
+ :param auth_settings: Authentication setting identifiers list.
605
+ :resource_path: A string representation of the HTTP request resource path.
606
+ :method: A string representation of the HTTP request method.
607
+ :body: A object representing the body of the HTTP request.
608
+ The object type is the return value of sanitize_for_serialization().
609
+ :param request_auth: if set, the provided settings will
610
+ override the token in the configuration.
611
+ """
612
+ if not auth_settings:
613
+ return
614
+
615
+ if request_auth:
616
+ self._apply_auth_params(
617
+ headers,
618
+ queries,
619
+ resource_path,
620
+ method,
621
+ body,
622
+ request_auth
623
+ )
624
+ else:
625
+ for auth in auth_settings:
626
+ auth_setting = self.configuration.auth_settings().get(auth)
627
+ if auth_setting:
628
+ self._apply_auth_params(
629
+ headers,
630
+ queries,
631
+ resource_path,
632
+ method,
633
+ body,
634
+ auth_setting
635
+ )
636
+
637
+ def _apply_auth_params(
638
+ self,
639
+ headers,
640
+ queries,
641
+ resource_path,
642
+ method,
643
+ body,
644
+ auth_setting
645
+ ) -> None:
646
+ """Updates the request parameters based on a single auth_setting
647
+
648
+ :param headers: Header parameters dict to be updated.
649
+ :param queries: Query parameters tuple list to be updated.
650
+ :resource_path: A string representation of the HTTP request resource path.
651
+ :method: A string representation of the HTTP request method.
652
+ :body: A object representing the body of the HTTP request.
653
+ The object type is the return value of sanitize_for_serialization().
654
+ :param auth_setting: auth settings for the endpoint
655
+ """
656
+ if auth_setting['in'] == 'cookie':
657
+ headers['Cookie'] = auth_setting['value']
658
+ elif auth_setting['in'] == 'header':
659
+ if auth_setting['type'] != 'http-signature':
660
+ headers[auth_setting['key']] = auth_setting['value']
661
+ elif auth_setting['in'] == 'query':
662
+ queries.append((auth_setting['key'], auth_setting['value']))
663
+ else:
664
+ raise ApiValueError(
665
+ 'Authentication token must be in `query` or `header`'
666
+ )
667
+
668
+ def __deserialize_file(self, response):
669
+ """Deserializes body to file
670
+
671
+ Saves response body into a file in a temporary folder,
672
+ using the filename from the `Content-Disposition` header if provided.
673
+
674
+ handle file downloading
675
+ save response body into a tmp file and return the instance
676
+
677
+ :param response: RESTResponse.
678
+ :return: file path.
679
+ """
680
+ fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
681
+ os.close(fd)
682
+ os.remove(path)
683
+
684
+ content_disposition = response.getheader("Content-Disposition")
685
+ if content_disposition:
686
+ m = re.search(
687
+ r'filename=[\'"]?([^\'"\s]+)[\'"]?',
688
+ content_disposition
689
+ )
690
+ assert m is not None, "Unexpected 'content-disposition' header value"
691
+ filename = m.group(1)
692
+ path = os.path.join(os.path.dirname(path), filename)
693
+
694
+ with open(path, "wb") as f:
695
+ f.write(response.data)
696
+
697
+ return path
698
+
699
+ def __deserialize_primitive(self, data, klass):
700
+ """Deserializes string to primitive type.
701
+
702
+ :param data: str.
703
+ :param klass: class literal.
704
+
705
+ :return: int, long, float, str, bool.
706
+ """
707
+ try:
708
+ return klass(data)
709
+ except UnicodeEncodeError:
710
+ return str(data)
711
+ except TypeError:
712
+ return data
713
+
714
+ def __deserialize_object(self, value):
715
+ """Return an original value.
716
+
717
+ :return: object.
718
+ """
719
+ return value
720
+
721
+ def __deserialize_date(self, string):
722
+ """Deserializes string to date.
723
+
724
+ :param string: str.
725
+ :return: date.
726
+ """
727
+ try:
728
+ return parse(string).date()
729
+ except ImportError:
730
+ return string
731
+ except ValueError:
732
+ raise rest.ApiException(
733
+ status=0,
734
+ reason="Failed to parse `{0}` as date object".format(string)
735
+ )
736
+
737
+ def __deserialize_datetime(self, string):
738
+ """Deserializes string to datetime.
739
+
740
+ The string should be in iso8601 datetime format.
741
+
742
+ :param string: str.
743
+ :return: datetime.
744
+ """
745
+ try:
746
+ return parse(string)
747
+ except ImportError:
748
+ return string
749
+ except ValueError:
750
+ raise rest.ApiException(
751
+ status=0,
752
+ reason=(
753
+ "Failed to parse `{0}` as datetime object"
754
+ .format(string)
755
+ )
756
+ )
757
+
758
+ def __deserialize_enum(self, data, klass):
759
+ """Deserializes primitive type to enum.
760
+
761
+ :param data: primitive type.
762
+ :param klass: class literal.
763
+ :return: enum value.
764
+ """
765
+ try:
766
+ return klass(data)
767
+ except ValueError:
768
+ raise rest.ApiException(
769
+ status=0,
770
+ reason=(
771
+ "Failed to parse `{0}` as `{1}`"
772
+ .format(data, klass)
773
+ )
774
+ )
775
+
776
+ def __deserialize_model(self, data, klass):
777
+ """Deserializes list or dict to model.
778
+
779
+ :param data: dict, list.
780
+ :param klass: class literal.
781
+ :return: model object.
782
+ """
783
+
784
+ return klass.from_dict(data)