gsctl 0.29.0a20250114__py2.py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- graphscope/flex/rest/__init__.py +106 -0
- graphscope/flex/rest/api/__init__.py +12 -0
- graphscope/flex/rest/api/alert_api.py +2790 -0
- graphscope/flex/rest/api/data_source_api.py +1177 -0
- graphscope/flex/rest/api/deployment_api.py +1323 -0
- graphscope/flex/rest/api/graph_api.py +2813 -0
- graphscope/flex/rest/api/job_api.py +1408 -0
- graphscope/flex/rest/api/service_api.py +1316 -0
- graphscope/flex/rest/api/stored_procedure_api.py +1454 -0
- graphscope/flex/rest/api/utils_api.py +310 -0
- graphscope/flex/rest/api_client.py +789 -0
- graphscope/flex/rest/api_response.py +21 -0
- graphscope/flex/rest/configuration.py +451 -0
- graphscope/flex/rest/exceptions.py +200 -0
- graphscope/flex/rest/models/__init__.py +82 -0
- graphscope/flex/rest/models/base_edge_type.py +102 -0
- graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner.py +108 -0
- graphscope/flex/rest/models/base_edge_type_vertex_type_pair_relations_inner_x_csr_params.py +98 -0
- graphscope/flex/rest/models/base_property_meta.py +105 -0
- graphscope/flex/rest/models/base_vertex_type.py +96 -0
- graphscope/flex/rest/models/base_vertex_type_x_csr_params.py +88 -0
- graphscope/flex/rest/models/column_mapping.py +94 -0
- graphscope/flex/rest/models/column_mapping_column.py +90 -0
- graphscope/flex/rest/models/create_alert_receiver_request.py +103 -0
- graphscope/flex/rest/models/create_alert_rule_request.py +112 -0
- graphscope/flex/rest/models/create_dataloading_job_response.py +88 -0
- graphscope/flex/rest/models/create_edge_type.py +114 -0
- graphscope/flex/rest/models/create_graph_request.py +106 -0
- graphscope/flex/rest/models/create_graph_response.py +88 -0
- graphscope/flex/rest/models/create_graph_schema_request.py +106 -0
- graphscope/flex/rest/models/create_property_meta.py +105 -0
- graphscope/flex/rest/models/create_stored_proc_request.py +101 -0
- graphscope/flex/rest/models/create_stored_proc_response.py +88 -0
- graphscope/flex/rest/models/create_vertex_type.py +108 -0
- graphscope/flex/rest/models/dataloading_job_config.py +136 -0
- graphscope/flex/rest/models/dataloading_job_config_edges_inner.py +92 -0
- graphscope/flex/rest/models/dataloading_job_config_loading_config.py +104 -0
- graphscope/flex/rest/models/dataloading_job_config_loading_config_format.py +90 -0
- graphscope/flex/rest/models/dataloading_job_config_vertices_inner.py +88 -0
- graphscope/flex/rest/models/dataloading_mr_job_config.py +88 -0
- graphscope/flex/rest/models/date_type.py +88 -0
- graphscope/flex/rest/models/edge_mapping.py +122 -0
- graphscope/flex/rest/models/edge_mapping_type_triplet.py +92 -0
- graphscope/flex/rest/models/error.py +90 -0
- graphscope/flex/rest/models/get_alert_message_response.py +123 -0
- graphscope/flex/rest/models/get_alert_receiver_response.py +107 -0
- graphscope/flex/rest/models/get_alert_rule_response.py +114 -0
- graphscope/flex/rest/models/get_edge_type.py +116 -0
- graphscope/flex/rest/models/get_graph_response.py +139 -0
- graphscope/flex/rest/models/get_graph_schema_response.py +106 -0
- graphscope/flex/rest/models/get_pod_log_response.py +88 -0
- graphscope/flex/rest/models/get_property_meta.py +107 -0
- graphscope/flex/rest/models/get_resource_usage_response.py +105 -0
- graphscope/flex/rest/models/get_storage_usage_response.py +88 -0
- graphscope/flex/rest/models/get_stored_proc_response.py +130 -0
- graphscope/flex/rest/models/get_vertex_type.py +110 -0
- graphscope/flex/rest/models/gs_data_type.py +152 -0
- graphscope/flex/rest/models/job_status.py +107 -0
- graphscope/flex/rest/models/long_text.py +93 -0
- graphscope/flex/rest/models/node_status.py +94 -0
- graphscope/flex/rest/models/parameter.py +96 -0
- graphscope/flex/rest/models/pod_status.py +108 -0
- graphscope/flex/rest/models/primitive_type.py +95 -0
- graphscope/flex/rest/models/resource_usage.py +92 -0
- graphscope/flex/rest/models/running_deployment_info.py +128 -0
- graphscope/flex/rest/models/running_deployment_status.py +124 -0
- graphscope/flex/rest/models/schema_mapping.py +106 -0
- graphscope/flex/rest/models/service_status.py +112 -0
- graphscope/flex/rest/models/service_status_sdk_endpoints.py +94 -0
- graphscope/flex/rest/models/start_service_request.py +88 -0
- graphscope/flex/rest/models/stored_procedure_meta.py +126 -0
- graphscope/flex/rest/models/string_type.py +92 -0
- graphscope/flex/rest/models/string_type_string.py +124 -0
- graphscope/flex/rest/models/temporal_type.py +92 -0
- graphscope/flex/rest/models/temporal_type_temporal.py +138 -0
- graphscope/flex/rest/models/time_stamp_type.py +88 -0
- graphscope/flex/rest/models/update_alert_message_status_request.py +97 -0
- graphscope/flex/rest/models/update_stored_proc_request.py +88 -0
- graphscope/flex/rest/models/upload_file_response.py +90 -0
- graphscope/flex/rest/models/vertex_mapping.py +100 -0
- graphscope/flex/rest/py.typed +0 -0
- graphscope/flex/rest/rest.py +258 -0
- graphscope/gsctl/V6D_VERSION +1 -0
- graphscope/gsctl/VERSION +1 -0
- graphscope/gsctl/__init__.py +22 -0
- graphscope/gsctl/commands/__init__.py +148 -0
- graphscope/gsctl/commands/common.py +200 -0
- graphscope/gsctl/commands/dev.py +448 -0
- graphscope/gsctl/commands/insight/__init__.py +17 -0
- graphscope/gsctl/commands/insight/glob.py +234 -0
- graphscope/gsctl/commands/insight/graph.py +205 -0
- graphscope/gsctl/commands/interactive/__init__.py +17 -0
- graphscope/gsctl/commands/interactive/glob.py +280 -0
- graphscope/gsctl/commands/interactive/graph.py +259 -0
- graphscope/gsctl/config.py +221 -0
- graphscope/gsctl/gsctl.py +51 -0
- graphscope/gsctl/impl/__init__.py +64 -0
- graphscope/gsctl/impl/alert.py +135 -0
- graphscope/gsctl/impl/common.py +53 -0
- graphscope/gsctl/impl/datasource.py +80 -0
- graphscope/gsctl/impl/deployment.py +62 -0
- graphscope/gsctl/impl/graph.py +150 -0
- graphscope/gsctl/impl/job.py +63 -0
- graphscope/gsctl/impl/service.py +62 -0
- graphscope/gsctl/impl/stored_procedure.py +92 -0
- graphscope/gsctl/impl/utils.py +38 -0
- graphscope/gsctl/scripts/install_deps.sh +969 -0
- graphscope/gsctl/tests/__init__.py +17 -0
- graphscope/gsctl/tests/test_graphscope_insight.py +401 -0
- graphscope/gsctl/tests/test_interactive.py +516 -0
- graphscope/gsctl/utils.py +337 -0
- graphscope/gsctl/version.py +31 -0
- gsctl-0.29.0a20250114.dist-info/METADATA +20 -0
- gsctl-0.29.0a20250114.dist-info/RECORD +117 -0
- gsctl-0.29.0a20250114.dist-info/WHEEL +6 -0
- gsctl-0.29.0a20250114.dist-info/entry_points.txt +3 -0
- gsctl-0.29.0a20250114.dist-info/top_level.txt +1 -0
@@ -0,0 +1,789 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
"""
|
4
|
+
GraphScope FLEX HTTP SERVICE API
|
5
|
+
|
6
|
+
This is a specification for GraphScope FLEX HTTP service based on the OpenAPI 3.0 specification. You can find out more details about specification at [doc](https://swagger.io/specification/v3/).
|
7
|
+
|
8
|
+
The version of the OpenAPI document: 1.0.0
|
9
|
+
Contact: graphscope@alibaba-inc.com
|
10
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
11
|
+
|
12
|
+
Do not edit the class manually.
|
13
|
+
""" # noqa: E501
|
14
|
+
|
15
|
+
|
16
|
+
import datetime
|
17
|
+
from dateutil.parser import parse
|
18
|
+
from enum import Enum
|
19
|
+
import decimal
|
20
|
+
import json
|
21
|
+
import mimetypes
|
22
|
+
import os
|
23
|
+
import re
|
24
|
+
import tempfile
|
25
|
+
|
26
|
+
from urllib.parse import quote
|
27
|
+
from typing import Tuple, Optional, List, Dict, Union
|
28
|
+
from pydantic import SecretStr
|
29
|
+
|
30
|
+
from graphscope.flex.rest.configuration import Configuration
|
31
|
+
from graphscope.flex.rest.api_response import ApiResponse, T as ApiResponseT
|
32
|
+
import graphscope.flex.rest.models
|
33
|
+
from graphscope.flex.rest import rest
|
34
|
+
from graphscope.flex.rest.exceptions import (
|
35
|
+
ApiValueError,
|
36
|
+
ApiException,
|
37
|
+
BadRequestException,
|
38
|
+
UnauthorizedException,
|
39
|
+
ForbiddenException,
|
40
|
+
NotFoundException,
|
41
|
+
ServiceException
|
42
|
+
)
|
43
|
+
|
44
|
+
RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]]
|
45
|
+
|
46
|
+
class ApiClient:
|
47
|
+
"""Generic API client for OpenAPI client library builds.
|
48
|
+
|
49
|
+
OpenAPI generic API client. This client handles the client-
|
50
|
+
server communication, and is invariant across implementations. Specifics of
|
51
|
+
the methods and models for each application are generated from the OpenAPI
|
52
|
+
templates.
|
53
|
+
|
54
|
+
:param configuration: .Configuration object for this client
|
55
|
+
:param header_name: a header to pass when making calls to the API.
|
56
|
+
:param header_value: a header value to pass when making calls to
|
57
|
+
the API.
|
58
|
+
:param cookie: a cookie to include in the header when making calls
|
59
|
+
to the API
|
60
|
+
"""
|
61
|
+
|
62
|
+
PRIMITIVE_TYPES = (float, bool, bytes, str, int)
|
63
|
+
NATIVE_TYPES_MAPPING = {
|
64
|
+
'int': int,
|
65
|
+
'long': int, # TODO remove as only py3 is supported?
|
66
|
+
'float': float,
|
67
|
+
'str': str,
|
68
|
+
'bool': bool,
|
69
|
+
'date': datetime.date,
|
70
|
+
'datetime': datetime.datetime,
|
71
|
+
'decimal': decimal.Decimal,
|
72
|
+
'object': object,
|
73
|
+
}
|
74
|
+
_pool = None
|
75
|
+
|
76
|
+
def __init__(
|
77
|
+
self,
|
78
|
+
configuration=None,
|
79
|
+
header_name=None,
|
80
|
+
header_value=None,
|
81
|
+
cookie=None
|
82
|
+
) -> None:
|
83
|
+
# use default configuration if none is provided
|
84
|
+
if configuration is None:
|
85
|
+
configuration = Configuration.get_default()
|
86
|
+
self.configuration = configuration
|
87
|
+
|
88
|
+
self.rest_client = rest.RESTClientObject(configuration)
|
89
|
+
self.default_headers = {}
|
90
|
+
if header_name is not None:
|
91
|
+
self.default_headers[header_name] = header_value
|
92
|
+
self.cookie = cookie
|
93
|
+
# Set default User-Agent.
|
94
|
+
self.user_agent = 'OpenAPI-Generator/1.0.0/python'
|
95
|
+
self.client_side_validation = configuration.client_side_validation
|
96
|
+
|
97
|
+
def __enter__(self):
|
98
|
+
return self
|
99
|
+
|
100
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
101
|
+
pass
|
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
|
+
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 = 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 decimal.Decimal return string representation.
|
345
|
+
If obj is list, sanitize each element in the list.
|
346
|
+
If obj is dict, return the dict.
|
347
|
+
If obj is OpenAPI model, return the properties dict.
|
348
|
+
|
349
|
+
:param obj: The data to serialize.
|
350
|
+
:return: The serialized form of data.
|
351
|
+
"""
|
352
|
+
if obj is None:
|
353
|
+
return None
|
354
|
+
elif isinstance(obj, Enum):
|
355
|
+
return obj.value
|
356
|
+
elif isinstance(obj, SecretStr):
|
357
|
+
return obj.get_secret_value()
|
358
|
+
elif isinstance(obj, self.PRIMITIVE_TYPES):
|
359
|
+
return obj
|
360
|
+
elif isinstance(obj, list):
|
361
|
+
return [
|
362
|
+
self.sanitize_for_serialization(sub_obj) for sub_obj in obj
|
363
|
+
]
|
364
|
+
elif isinstance(obj, tuple):
|
365
|
+
return tuple(
|
366
|
+
self.sanitize_for_serialization(sub_obj) for sub_obj in obj
|
367
|
+
)
|
368
|
+
elif isinstance(obj, (datetime.datetime, datetime.date)):
|
369
|
+
return obj.isoformat()
|
370
|
+
elif isinstance(obj, decimal.Decimal):
|
371
|
+
return str(obj)
|
372
|
+
|
373
|
+
elif isinstance(obj, dict):
|
374
|
+
obj_dict = obj
|
375
|
+
else:
|
376
|
+
# Convert model obj to dict except
|
377
|
+
# attributes `openapi_types`, `attribute_map`
|
378
|
+
# and attributes which value is not None.
|
379
|
+
# Convert attribute name to json key in
|
380
|
+
# model definition for request.
|
381
|
+
if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')):
|
382
|
+
obj_dict = obj.to_dict()
|
383
|
+
else:
|
384
|
+
obj_dict = obj.__dict__
|
385
|
+
|
386
|
+
return {
|
387
|
+
key: self.sanitize_for_serialization(val)
|
388
|
+
for key, val in obj_dict.items()
|
389
|
+
}
|
390
|
+
|
391
|
+
def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]):
|
392
|
+
"""Deserializes response into an object.
|
393
|
+
|
394
|
+
:param response: RESTResponse object to be deserialized.
|
395
|
+
:param response_type: class literal for
|
396
|
+
deserialized object, or string of class name.
|
397
|
+
:param content_type: content type of response.
|
398
|
+
|
399
|
+
:return: deserialized object.
|
400
|
+
"""
|
401
|
+
|
402
|
+
# fetch data from response object
|
403
|
+
if content_type is None:
|
404
|
+
try:
|
405
|
+
data = json.loads(response_text)
|
406
|
+
except ValueError:
|
407
|
+
data = response_text
|
408
|
+
elif content_type.startswith("application/json"):
|
409
|
+
if response_text == "":
|
410
|
+
data = ""
|
411
|
+
else:
|
412
|
+
data = json.loads(response_text)
|
413
|
+
elif content_type.startswith("text/plain"):
|
414
|
+
data = response_text
|
415
|
+
else:
|
416
|
+
raise ApiException(
|
417
|
+
status=0,
|
418
|
+
reason="Unsupported content type: {0}".format(content_type)
|
419
|
+
)
|
420
|
+
|
421
|
+
return self.__deserialize(data, response_type)
|
422
|
+
|
423
|
+
def __deserialize(self, data, klass):
|
424
|
+
"""Deserializes dict, list, str into an object.
|
425
|
+
|
426
|
+
:param data: dict, list or str.
|
427
|
+
:param klass: class literal, or string of class name.
|
428
|
+
|
429
|
+
:return: object.
|
430
|
+
"""
|
431
|
+
if data is None:
|
432
|
+
return None
|
433
|
+
|
434
|
+
if isinstance(klass, str):
|
435
|
+
if klass.startswith('List['):
|
436
|
+
m = re.match(r'List\[(.*)]', klass)
|
437
|
+
assert m is not None, "Malformed List type definition"
|
438
|
+
sub_kls = m.group(1)
|
439
|
+
return [self.__deserialize(sub_data, sub_kls)
|
440
|
+
for sub_data in data]
|
441
|
+
|
442
|
+
if klass.startswith('Dict['):
|
443
|
+
m = re.match(r'Dict\[([^,]*), (.*)]', klass)
|
444
|
+
assert m is not None, "Malformed Dict type definition"
|
445
|
+
sub_kls = m.group(2)
|
446
|
+
return {k: self.__deserialize(v, sub_kls)
|
447
|
+
for k, v in data.items()}
|
448
|
+
|
449
|
+
# convert str to class
|
450
|
+
if klass in self.NATIVE_TYPES_MAPPING:
|
451
|
+
klass = self.NATIVE_TYPES_MAPPING[klass]
|
452
|
+
else:
|
453
|
+
klass = getattr(graphscope.flex.rest.models, klass)
|
454
|
+
|
455
|
+
if klass in self.PRIMITIVE_TYPES:
|
456
|
+
return self.__deserialize_primitive(data, klass)
|
457
|
+
elif klass == object:
|
458
|
+
return self.__deserialize_object(data)
|
459
|
+
elif klass == datetime.date:
|
460
|
+
return self.__deserialize_date(data)
|
461
|
+
elif klass == datetime.datetime:
|
462
|
+
return self.__deserialize_datetime(data)
|
463
|
+
elif klass == decimal.Decimal:
|
464
|
+
return decimal.Decimal(data)
|
465
|
+
elif issubclass(klass, Enum):
|
466
|
+
return self.__deserialize_enum(data, klass)
|
467
|
+
else:
|
468
|
+
return self.__deserialize_model(data, klass)
|
469
|
+
|
470
|
+
def parameters_to_tuples(self, params, collection_formats):
|
471
|
+
"""Get parameters as list of tuples, formatting collections.
|
472
|
+
|
473
|
+
:param params: Parameters as dict or list of two-tuples
|
474
|
+
:param dict collection_formats: Parameter collection formats
|
475
|
+
:return: Parameters as list of tuples, collections formatted
|
476
|
+
"""
|
477
|
+
new_params: List[Tuple[str, str]] = []
|
478
|
+
if collection_formats is None:
|
479
|
+
collection_formats = {}
|
480
|
+
for k, v in params.items() if isinstance(params, dict) else params:
|
481
|
+
if k in collection_formats:
|
482
|
+
collection_format = collection_formats[k]
|
483
|
+
if collection_format == 'multi':
|
484
|
+
new_params.extend((k, value) for value in v)
|
485
|
+
else:
|
486
|
+
if collection_format == 'ssv':
|
487
|
+
delimiter = ' '
|
488
|
+
elif collection_format == 'tsv':
|
489
|
+
delimiter = '\t'
|
490
|
+
elif collection_format == 'pipes':
|
491
|
+
delimiter = '|'
|
492
|
+
else: # csv is the default
|
493
|
+
delimiter = ','
|
494
|
+
new_params.append(
|
495
|
+
(k, delimiter.join(str(value) for value in v)))
|
496
|
+
else:
|
497
|
+
new_params.append((k, v))
|
498
|
+
return new_params
|
499
|
+
|
500
|
+
def parameters_to_url_query(self, params, collection_formats):
|
501
|
+
"""Get parameters as list of tuples, formatting collections.
|
502
|
+
|
503
|
+
:param params: Parameters as dict or list of two-tuples
|
504
|
+
:param dict collection_formats: Parameter collection formats
|
505
|
+
:return: URL query string (e.g. a=Hello%20World&b=123)
|
506
|
+
"""
|
507
|
+
new_params: List[Tuple[str, str]] = []
|
508
|
+
if collection_formats is None:
|
509
|
+
collection_formats = {}
|
510
|
+
for k, v in params.items() if isinstance(params, dict) else params:
|
511
|
+
if isinstance(v, bool):
|
512
|
+
v = str(v).lower()
|
513
|
+
if isinstance(v, (int, float)):
|
514
|
+
v = str(v)
|
515
|
+
if isinstance(v, dict):
|
516
|
+
v = json.dumps(v)
|
517
|
+
|
518
|
+
if k in collection_formats:
|
519
|
+
collection_format = collection_formats[k]
|
520
|
+
if collection_format == 'multi':
|
521
|
+
new_params.extend((k, str(value)) for value in v)
|
522
|
+
else:
|
523
|
+
if collection_format == 'ssv':
|
524
|
+
delimiter = ' '
|
525
|
+
elif collection_format == 'tsv':
|
526
|
+
delimiter = '\t'
|
527
|
+
elif collection_format == 'pipes':
|
528
|
+
delimiter = '|'
|
529
|
+
else: # csv is the default
|
530
|
+
delimiter = ','
|
531
|
+
new_params.append(
|
532
|
+
(k, delimiter.join(quote(str(value)) for value in v))
|
533
|
+
)
|
534
|
+
else:
|
535
|
+
new_params.append((k, quote(str(v))))
|
536
|
+
|
537
|
+
return "&".join(["=".join(map(str, item)) for item in new_params])
|
538
|
+
|
539
|
+
def files_parameters(self, files: Dict[str, Union[str, bytes]]):
|
540
|
+
"""Builds form parameters.
|
541
|
+
|
542
|
+
:param files: File parameters.
|
543
|
+
:return: Form parameters with files.
|
544
|
+
"""
|
545
|
+
params = []
|
546
|
+
for k, v in files.items():
|
547
|
+
if isinstance(v, str):
|
548
|
+
with open(v, 'rb') as f:
|
549
|
+
filename = os.path.basename(f.name)
|
550
|
+
filedata = f.read()
|
551
|
+
elif isinstance(v, bytes):
|
552
|
+
filename = k
|
553
|
+
filedata = v
|
554
|
+
else:
|
555
|
+
raise ValueError("Unsupported file value")
|
556
|
+
mimetype = (
|
557
|
+
mimetypes.guess_type(filename)[0]
|
558
|
+
or 'application/octet-stream'
|
559
|
+
)
|
560
|
+
params.append(
|
561
|
+
tuple([k, tuple([filename, filedata, mimetype])])
|
562
|
+
)
|
563
|
+
return params
|
564
|
+
|
565
|
+
def select_header_accept(self, accepts: List[str]) -> Optional[str]:
|
566
|
+
"""Returns `Accept` based on an array of accepts provided.
|
567
|
+
|
568
|
+
:param accepts: List of headers.
|
569
|
+
:return: Accept (e.g. application/json).
|
570
|
+
"""
|
571
|
+
if not accepts:
|
572
|
+
return None
|
573
|
+
|
574
|
+
for accept in accepts:
|
575
|
+
if re.search('json', accept, re.IGNORECASE):
|
576
|
+
return accept
|
577
|
+
|
578
|
+
return accepts[0]
|
579
|
+
|
580
|
+
def select_header_content_type(self, content_types):
|
581
|
+
"""Returns `Content-Type` based on an array of content_types provided.
|
582
|
+
|
583
|
+
:param content_types: List of content-types.
|
584
|
+
:return: Content-Type (e.g. application/json).
|
585
|
+
"""
|
586
|
+
if not content_types:
|
587
|
+
return None
|
588
|
+
|
589
|
+
for content_type in content_types:
|
590
|
+
if re.search('json', content_type, re.IGNORECASE):
|
591
|
+
return content_type
|
592
|
+
|
593
|
+
return content_types[0]
|
594
|
+
|
595
|
+
def update_params_for_auth(
|
596
|
+
self,
|
597
|
+
headers,
|
598
|
+
queries,
|
599
|
+
auth_settings,
|
600
|
+
resource_path,
|
601
|
+
method,
|
602
|
+
body,
|
603
|
+
request_auth=None
|
604
|
+
) -> None:
|
605
|
+
"""Updates header and query params based on authentication setting.
|
606
|
+
|
607
|
+
:param headers: Header parameters dict to be updated.
|
608
|
+
:param queries: Query parameters tuple list to be updated.
|
609
|
+
:param auth_settings: Authentication setting identifiers list.
|
610
|
+
:resource_path: A string representation of the HTTP request resource path.
|
611
|
+
:method: A string representation of the HTTP request method.
|
612
|
+
:body: A object representing the body of the HTTP request.
|
613
|
+
The object type is the return value of sanitize_for_serialization().
|
614
|
+
:param request_auth: if set, the provided settings will
|
615
|
+
override the token in the configuration.
|
616
|
+
"""
|
617
|
+
if not auth_settings:
|
618
|
+
return
|
619
|
+
|
620
|
+
if request_auth:
|
621
|
+
self._apply_auth_params(
|
622
|
+
headers,
|
623
|
+
queries,
|
624
|
+
resource_path,
|
625
|
+
method,
|
626
|
+
body,
|
627
|
+
request_auth
|
628
|
+
)
|
629
|
+
else:
|
630
|
+
for auth in auth_settings:
|
631
|
+
auth_setting = self.configuration.auth_settings().get(auth)
|
632
|
+
if auth_setting:
|
633
|
+
self._apply_auth_params(
|
634
|
+
headers,
|
635
|
+
queries,
|
636
|
+
resource_path,
|
637
|
+
method,
|
638
|
+
body,
|
639
|
+
auth_setting
|
640
|
+
)
|
641
|
+
|
642
|
+
def _apply_auth_params(
|
643
|
+
self,
|
644
|
+
headers,
|
645
|
+
queries,
|
646
|
+
resource_path,
|
647
|
+
method,
|
648
|
+
body,
|
649
|
+
auth_setting
|
650
|
+
) -> None:
|
651
|
+
"""Updates the request parameters based on a single auth_setting
|
652
|
+
|
653
|
+
:param headers: Header parameters dict to be updated.
|
654
|
+
:param queries: Query parameters tuple list to be updated.
|
655
|
+
:resource_path: A string representation of the HTTP request resource path.
|
656
|
+
:method: A string representation of the HTTP request method.
|
657
|
+
:body: A object representing the body of the HTTP request.
|
658
|
+
The object type is the return value of sanitize_for_serialization().
|
659
|
+
:param auth_setting: auth settings for the endpoint
|
660
|
+
"""
|
661
|
+
if auth_setting['in'] == 'cookie':
|
662
|
+
headers['Cookie'] = auth_setting['value']
|
663
|
+
elif auth_setting['in'] == 'header':
|
664
|
+
if auth_setting['type'] != 'http-signature':
|
665
|
+
headers[auth_setting['key']] = auth_setting['value']
|
666
|
+
elif auth_setting['in'] == 'query':
|
667
|
+
queries.append((auth_setting['key'], auth_setting['value']))
|
668
|
+
else:
|
669
|
+
raise ApiValueError(
|
670
|
+
'Authentication token must be in `query` or `header`'
|
671
|
+
)
|
672
|
+
|
673
|
+
def __deserialize_file(self, response):
|
674
|
+
"""Deserializes body to file
|
675
|
+
|
676
|
+
Saves response body into a file in a temporary folder,
|
677
|
+
using the filename from the `Content-Disposition` header if provided.
|
678
|
+
|
679
|
+
handle file downloading
|
680
|
+
save response body into a tmp file and return the instance
|
681
|
+
|
682
|
+
:param response: RESTResponse.
|
683
|
+
:return: file path.
|
684
|
+
"""
|
685
|
+
fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
|
686
|
+
os.close(fd)
|
687
|
+
os.remove(path)
|
688
|
+
|
689
|
+
content_disposition = response.getheader("Content-Disposition")
|
690
|
+
if content_disposition:
|
691
|
+
m = re.search(
|
692
|
+
r'filename=[\'"]?([^\'"\s]+)[\'"]?',
|
693
|
+
content_disposition
|
694
|
+
)
|
695
|
+
assert m is not None, "Unexpected 'content-disposition' header value"
|
696
|
+
filename = m.group(1)
|
697
|
+
path = os.path.join(os.path.dirname(path), filename)
|
698
|
+
|
699
|
+
with open(path, "wb") as f:
|
700
|
+
f.write(response.data)
|
701
|
+
|
702
|
+
return path
|
703
|
+
|
704
|
+
def __deserialize_primitive(self, data, klass):
|
705
|
+
"""Deserializes string to primitive type.
|
706
|
+
|
707
|
+
:param data: str.
|
708
|
+
:param klass: class literal.
|
709
|
+
|
710
|
+
:return: int, long, float, str, bool.
|
711
|
+
"""
|
712
|
+
try:
|
713
|
+
return klass(data)
|
714
|
+
except UnicodeEncodeError:
|
715
|
+
return str(data)
|
716
|
+
except TypeError:
|
717
|
+
return data
|
718
|
+
|
719
|
+
def __deserialize_object(self, value):
|
720
|
+
"""Return an original value.
|
721
|
+
|
722
|
+
:return: object.
|
723
|
+
"""
|
724
|
+
return value
|
725
|
+
|
726
|
+
def __deserialize_date(self, string):
|
727
|
+
"""Deserializes string to date.
|
728
|
+
|
729
|
+
:param string: str.
|
730
|
+
:return: date.
|
731
|
+
"""
|
732
|
+
try:
|
733
|
+
return parse(string).date()
|
734
|
+
except ImportError:
|
735
|
+
return string
|
736
|
+
except ValueError:
|
737
|
+
raise rest.ApiException(
|
738
|
+
status=0,
|
739
|
+
reason="Failed to parse `{0}` as date object".format(string)
|
740
|
+
)
|
741
|
+
|
742
|
+
def __deserialize_datetime(self, string):
|
743
|
+
"""Deserializes string to datetime.
|
744
|
+
|
745
|
+
The string should be in iso8601 datetime format.
|
746
|
+
|
747
|
+
:param string: str.
|
748
|
+
:return: datetime.
|
749
|
+
"""
|
750
|
+
try:
|
751
|
+
return parse(string)
|
752
|
+
except ImportError:
|
753
|
+
return string
|
754
|
+
except ValueError:
|
755
|
+
raise rest.ApiException(
|
756
|
+
status=0,
|
757
|
+
reason=(
|
758
|
+
"Failed to parse `{0}` as datetime object"
|
759
|
+
.format(string)
|
760
|
+
)
|
761
|
+
)
|
762
|
+
|
763
|
+
def __deserialize_enum(self, data, klass):
|
764
|
+
"""Deserializes primitive type to enum.
|
765
|
+
|
766
|
+
:param data: primitive type.
|
767
|
+
:param klass: class literal.
|
768
|
+
:return: enum value.
|
769
|
+
"""
|
770
|
+
try:
|
771
|
+
return klass(data)
|
772
|
+
except ValueError:
|
773
|
+
raise rest.ApiException(
|
774
|
+
status=0,
|
775
|
+
reason=(
|
776
|
+
"Failed to parse `{0}` as `{1}`"
|
777
|
+
.format(data, klass)
|
778
|
+
)
|
779
|
+
)
|
780
|
+
|
781
|
+
def __deserialize_model(self, data, klass):
|
782
|
+
"""Deserializes list or dict to model.
|
783
|
+
|
784
|
+
:param data: dict, list.
|
785
|
+
:param klass: class literal.
|
786
|
+
:return: model object.
|
787
|
+
"""
|
788
|
+
|
789
|
+
return klass.from_dict(data)
|