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.
- lighter/__init__.py +140 -0
- lighter/api/__init__.py +11 -0
- lighter/api/account_api.py +2371 -0
- lighter/api/block_api.py +863 -0
- lighter/api/candlestick_api.py +718 -0
- lighter/api/info_api.py +282 -0
- lighter/api/order_api.py +2734 -0
- lighter/api/root_api.py +529 -0
- lighter/api/transaction_api.py +3525 -0
- lighter/api_client.py +784 -0
- lighter/api_response.py +21 -0
- lighter/configuration.py +475 -0
- lighter/exceptions.py +199 -0
- lighter/models/__init__.py +112 -0
- lighter/models/account.py +110 -0
- lighter/models/account_api_keys.py +104 -0
- lighter/models/account_market_stats.py +98 -0
- lighter/models/account_metadata.py +94 -0
- lighter/models/account_pn_l.py +106 -0
- lighter/models/account_position.py +112 -0
- lighter/models/account_stats.py +102 -0
- lighter/models/accounts.py +106 -0
- lighter/models/api_key.py +98 -0
- lighter/models/block.py +124 -0
- lighter/models/blocks.py +106 -0
- lighter/models/bridge_supported_network.py +96 -0
- lighter/models/candlestick.py +106 -0
- lighter/models/candlesticks.py +106 -0
- lighter/models/contract_address.py +94 -0
- lighter/models/current_height.py +96 -0
- lighter/models/cursor.py +92 -0
- lighter/models/deposit_history.py +106 -0
- lighter/models/deposit_history_item.py +105 -0
- lighter/models/detailed_account.py +152 -0
- lighter/models/detailed_accounts.py +106 -0
- lighter/models/detailed_candlestick.py +108 -0
- lighter/models/enriched_tx.py +129 -0
- lighter/models/exchange_stats.py +110 -0
- lighter/models/fee_bucket.py +96 -0
- lighter/models/funding.py +98 -0
- lighter/models/fundings.py +106 -0
- lighter/models/is_whitelisted.py +98 -0
- lighter/models/l1_provider_info.py +98 -0
- lighter/models/layer2_basic_info.py +100 -0
- lighter/models/liquidation.py +100 -0
- lighter/models/market_info.py +116 -0
- lighter/models/next_nonce.py +96 -0
- lighter/models/order.py +159 -0
- lighter/models/order_book.py +119 -0
- lighter/models/order_book_depth.py +115 -0
- lighter/models/order_book_detail.py +151 -0
- lighter/models/order_book_details.py +104 -0
- lighter/models/order_book_orders.py +117 -0
- lighter/models/order_book_stats.py +102 -0
- lighter/models/order_books.py +104 -0
- lighter/models/orders.py +106 -0
- lighter/models/pn_l_entry.py +94 -0
- lighter/models/position_funding.py +111 -0
- lighter/models/price_level.py +94 -0
- lighter/models/public_pool.py +128 -0
- lighter/models/public_pool_info.py +100 -0
- lighter/models/public_pool_share.py +96 -0
- lighter/models/public_pools.py +106 -0
- lighter/models/req_get_account.py +101 -0
- lighter/models/req_get_account_active_orders.py +96 -0
- lighter/models/req_get_account_api_keys.py +94 -0
- lighter/models/req_get_account_by_l1_address.py +92 -0
- lighter/models/req_get_account_inactive_orders.py +103 -0
- lighter/models/req_get_account_orders.py +99 -0
- lighter/models/req_get_account_pending_txs.py +106 -0
- lighter/models/req_get_account_pn_l.py +118 -0
- lighter/models/req_get_account_txs.py +111 -0
- lighter/models/req_get_block.py +101 -0
- lighter/models/req_get_block_txs.py +101 -0
- lighter/models/req_get_by_account.py +101 -0
- lighter/models/req_get_candlesticks.py +109 -0
- lighter/models/req_get_deposit_history.py +106 -0
- lighter/models/req_get_fee_bucket.py +92 -0
- lighter/models/req_get_fundings.py +107 -0
- lighter/models/req_get_l1_tx.py +92 -0
- lighter/models/req_get_latest_deposit.py +92 -0
- lighter/models/req_get_next_nonce.py +94 -0
- lighter/models/req_get_order_book_details.py +92 -0
- lighter/models/req_get_order_book_orders.py +95 -0
- lighter/models/req_get_order_books.py +92 -0
- lighter/models/req_get_public_pools.py +109 -0
- lighter/models/req_get_range_with_cursor.py +95 -0
- lighter/models/req_get_range_with_index.py +95 -0
- lighter/models/req_get_range_with_index_sortable.py +107 -0
- lighter/models/req_get_recent_trades.py +95 -0
- lighter/models/req_get_trades.py +126 -0
- lighter/models/req_get_tx.py +101 -0
- lighter/models/req_get_withdraw_history.py +106 -0
- lighter/models/req_is_whitelisted.py +92 -0
- lighter/models/result_code.py +94 -0
- lighter/models/simple_order.py +102 -0
- lighter/models/status.py +94 -0
- lighter/models/sub_accounts.py +106 -0
- lighter/models/ticker.py +103 -0
- lighter/models/trade.py +125 -0
- lighter/models/trades.py +106 -0
- lighter/models/tx.py +121 -0
- lighter/models/tx_hash.py +96 -0
- lighter/models/tx_hashes.py +96 -0
- lighter/models/txs.py +104 -0
- lighter/models/validator_info.py +94 -0
- lighter/models/withdraw_history.py +110 -0
- lighter/models/withdraw_history_cursor.py +94 -0
- lighter/models/withdraw_history_item.py +114 -0
- lighter/models/zk_lighter_info.py +92 -0
- lighter/py.typed +0 -0
- lighter/rest.py +215 -0
- lighter/signer_client.py +440 -0
- lighter/signers/signer-amd64.so +0 -0
- lighter/signers/signer-arm64.dylib +0 -0
- lighter/transactions/__init__.py +3 -0
- lighter/transactions/cancel_order.py +27 -0
- lighter/transactions/create_order.py +33 -0
- lighter/transactions/withdraw.py +25 -0
- lighter/ws_client.py +160 -0
- lighter_sdk-0.1.0.dist-info/LICENSE +201 -0
- lighter_sdk-0.1.0.dist-info/METADATA +26 -0
- lighter_sdk-0.1.0.dist-info/RECORD +125 -0
- lighter_sdk-0.1.0.dist-info/WHEEL +5 -0
- 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)
|