fds.sdk.FactSetProgrammaticEnvironment 0.21.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,928 @@
1
+ """
2
+ FPE API
3
+
4
+ FactSet Programmatic Environment (FPE) API is an API for users to interact with FPE programmatically, streamlining path from research to production. # noqa: E501
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Generated by: https://openapi-generator.tech
8
+ """
9
+
10
+
11
+ import json
12
+ import atexit
13
+ import mimetypes
14
+ from multiprocessing.pool import ThreadPool
15
+ import io
16
+ import os
17
+ import re
18
+ import typing
19
+ from typing import Tuple, Dict, Any, Callable, Optional
20
+ from urllib.parse import quote
21
+ from urllib3.fields import RequestField
22
+
23
+
24
+ from fds.sdk.FactSetProgrammaticEnvironment import rest
25
+ from fds.sdk.FactSetProgrammaticEnvironment.configuration import Configuration
26
+ from fds.sdk.FactSetProgrammaticEnvironment.exceptions import ApiTypeError, ApiValueError, ApiException
27
+ from fds.sdk.FactSetProgrammaticEnvironment.model_utils import (
28
+ ModelNormal,
29
+ ModelSimple,
30
+ ModelComposed,
31
+ check_allowed_values,
32
+ check_validations,
33
+ date,
34
+ datetime,
35
+ deserialize_file,
36
+ file_type,
37
+ model_to_dict,
38
+ none_type,
39
+ validate_and_convert_types
40
+ )
41
+
42
+ ResponseType = Tuple[Any]
43
+ """
44
+ Types to serialize the API response into.
45
+ A tuple containing:
46
+ * valid classes
47
+ * a list containing valid classes (for list schemas)
48
+ * a dict containing a tuple of valid classes as the value
49
+
50
+ Example values:
51
+ - (str,)
52
+ - (Pet,)
53
+ - (float, none_type)
54
+ - ([int, none_type],)
55
+ - ({str: (bool, str, int, float, date, datetime, str, none_type)},)
56
+ """
57
+
58
+ HttpStatusCode = int
59
+ ResponseTypeByStatusCode = Dict[HttpStatusCode, Optional[ResponseType]]
60
+ """
61
+ Map specifying return types per HTTP status code.
62
+
63
+ Examples value:
64
+ - { 200: (ModelA,), 201: (None,) }
65
+ """
66
+
67
+ ResponseWrapper = Callable[[HttpStatusCode, Any], Any]
68
+ ResponseTypeWithWrapper = Tuple[ResponseTypeByStatusCode, Optional[ResponseWrapper]]
69
+
70
+
71
+ class ApiClient(object):
72
+ """Generic API client for OpenAPI client library builds.
73
+
74
+ OpenAPI generic API client. This client handles the client-
75
+ server communication, and is invariant across implementations. Specifics of
76
+ the methods and models for each application are generated from the OpenAPI
77
+ templates.
78
+
79
+ NOTE: This class is auto generated by OpenAPI Generator.
80
+ Ref: https://openapi-generator.tech
81
+ Do not edit the class manually.
82
+
83
+ :param configuration: .Configuration object for this client
84
+ :param header_name: a header to pass when making calls to the API.
85
+ :param header_value: a header value to pass when making calls to
86
+ the API.
87
+ :param cookie: a cookie to include in the header when making calls
88
+ to the API
89
+ :param pool_threads: The number of threads to use for async requests
90
+ to the API. More threads means more concurrent API requests.
91
+ """
92
+
93
+ _pool = None
94
+
95
+ def __init__(self, configuration=None, header_name=None, header_value=None,
96
+ cookie=None, pool_threads=1):
97
+ if configuration is None:
98
+ configuration = Configuration.get_default_copy()
99
+ self.configuration = configuration
100
+ self.pool_threads = pool_threads
101
+
102
+ self.rest_client = rest.RESTClientObject(configuration)
103
+ self.default_headers = {}
104
+ if header_name is not None:
105
+ self.default_headers[header_name] = header_value
106
+ self.cookie = cookie
107
+ # Set default User-Agent.
108
+ self.user_agent = 'fds-sdk/python/FactSetProgrammaticEnvironment/0.21.6'
109
+
110
+ def __enter__(self):
111
+ return self
112
+
113
+ def __exit__(self, exc_type, exc_value, traceback):
114
+ self.close()
115
+
116
+ def close(self):
117
+ if self._pool:
118
+ self._pool.close()
119
+ self._pool.join()
120
+ self._pool = None
121
+ if hasattr(atexit, 'unregister'):
122
+ atexit.unregister(self.close)
123
+
124
+ @property
125
+ def pool(self):
126
+ """Create thread pool on first request
127
+ avoids instantiating unused threadpool for blocking clients.
128
+ """
129
+ if self._pool is None:
130
+ atexit.register(self.close)
131
+ self._pool = ThreadPool(self.pool_threads)
132
+ return self._pool
133
+
134
+ @property
135
+ def user_agent(self):
136
+ """User agent for this API client"""
137
+ return self.default_headers['User-Agent']
138
+
139
+ @user_agent.setter
140
+ def user_agent(self, value):
141
+ self.default_headers['User-Agent'] = value
142
+
143
+ def set_default_header(self, header_name, header_value):
144
+ self.default_headers[header_name] = header_value
145
+
146
+ def __call_api(
147
+ self,
148
+ resource_path: str,
149
+ method: str,
150
+ path_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
151
+ query_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
152
+ header_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
153
+ body: typing.Optional[typing.Any] = None,
154
+ post_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
155
+ files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None,
156
+ response_type: typing.Optional[ResponseTypeWithWrapper] = None,
157
+ auth_settings: typing.Optional[typing.List[str]] = None,
158
+ _return_http_data_only: typing.Optional[bool] = None,
159
+ collection_formats: typing.Optional[typing.Dict[str, str]] = None,
160
+ _preload_content: bool = True,
161
+ _request_timeout: typing.Optional[typing.Union[int, float, typing.Tuple]] = None,
162
+ _host: typing.Optional[str] = None,
163
+ _check_type: typing.Optional[bool] = None,
164
+ _content_type: typing.Optional[str] = None
165
+ ):
166
+
167
+ config = self.configuration
168
+
169
+ # header parameters
170
+ header_params = header_params or {}
171
+ header_params.update(self.default_headers)
172
+ if self.cookie:
173
+ header_params['Cookie'] = self.cookie
174
+ if header_params:
175
+ header_params = self.sanitize_for_serialization(header_params)
176
+ header_params = dict(self.parameters_to_tuples(header_params,
177
+ collection_formats))
178
+
179
+ # path parameters
180
+ if path_params:
181
+ path_params = self.sanitize_for_serialization(path_params)
182
+ path_params = self.parameters_to_tuples(path_params,
183
+ collection_formats)
184
+ for k, v in path_params:
185
+ # specified safe chars, encode everything
186
+ resource_path = resource_path.replace(
187
+ '{%s}' % k,
188
+ quote(str(v), safe=config.safe_chars_for_path_param)
189
+ )
190
+
191
+ # query parameters
192
+ if query_params:
193
+ query_params = self.sanitize_for_serialization(query_params)
194
+ query_params = self.parameters_to_tuples(query_params,
195
+ collection_formats)
196
+
197
+ # post parameters
198
+ if post_params or files:
199
+ post_params = post_params if post_params else []
200
+ post_params = self.sanitize_for_serialization(post_params)
201
+ post_params = self.parameters_to_tuples(post_params,
202
+ collection_formats)
203
+ post_params.extend(self.files_parameters(files))
204
+ if header_params['Content-Type'].startswith("multipart"):
205
+ post_params = self.parameters_to_multipart(post_params, dict)
206
+
207
+ # body
208
+ if body:
209
+ body = self.sanitize_for_serialization(body)
210
+
211
+ # auth setting
212
+ self.update_params_for_auth(header_params, query_params,
213
+ auth_settings, resource_path, method, body)
214
+
215
+ # request url
216
+ if _host is None:
217
+ url = self.configuration.host + resource_path
218
+ else:
219
+ # use server/host defined in path or operation instead
220
+ url = _host + resource_path
221
+
222
+ try:
223
+ # perform request and return response
224
+ response_data = self.request(
225
+ method, url, query_params=query_params, headers=header_params,
226
+ post_params=post_params, body=body,
227
+ _preload_content=_preload_content,
228
+ _request_timeout=_request_timeout)
229
+ except ApiException as e:
230
+ e.body = e.body.decode('utf-8')
231
+ raise e
232
+
233
+ self.last_response = response_data
234
+
235
+ return_data = response_data
236
+
237
+ if not _preload_content:
238
+ return (return_data)
239
+
240
+ # deserialize response data with response code to type serialization mapping
241
+ if response_type is not None:
242
+ (status_code_map, response_wrapper) = response_type
243
+ else:
244
+ status_code_map = {}
245
+ response_wrapper = None
246
+
247
+ if response_data.status in status_code_map:
248
+ response_type = status_code_map[response_data.status]
249
+
250
+ if response_type != (file_type,):
251
+ encoding = "utf-8"
252
+ content_type = response_data.getheader('content-type')
253
+ if content_type is not None:
254
+ match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type)
255
+ if match:
256
+ encoding = match.group(1)
257
+ response_data.data = response_data.data.decode(encoding)
258
+
259
+ return_data = self.deserialize(
260
+ response_data,
261
+ response_type,
262
+ _check_type
263
+ )
264
+
265
+ else:
266
+ return_data = None
267
+
268
+ if response_wrapper is not None:
269
+ return_data = response_wrapper(response_data.status, return_data)
270
+
271
+ if _return_http_data_only:
272
+ return return_data
273
+ else:
274
+ return return_data, response_data.status, response_data.getheaders()
275
+
276
+ def parameters_to_multipart(self, params, collection_types):
277
+ """Get parameters as list of tuples, formatting as json if value is collection_types
278
+
279
+ :param params: Parameters as list of two-tuples
280
+ :type params: list
281
+ :param collection_types: Parameter collection types
282
+ :type collection_types: Type(typing.Any)
283
+ :return: Parameters as list of tuple or urllib3.fields.RequestField
284
+ """
285
+ new_params = []
286
+ if collection_types is None:
287
+ collection_types = dict
288
+ for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
289
+ if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
290
+ v = json.dumps(v, ensure_ascii=False).encode("utf-8")
291
+ field = RequestField(k, v)
292
+ field.make_multipart(content_type="application/json; charset=utf-8")
293
+ new_params.append(field)
294
+ else:
295
+ new_params.append((k, v))
296
+ return new_params
297
+
298
+ @classmethod
299
+ def sanitize_for_serialization(cls, obj):
300
+ """Prepares data for transmission before it is sent with the rest client
301
+ If obj is None, return None.
302
+ If obj is str, int, long, float, bool, return directly.
303
+ If obj is datetime.datetime, datetime.date
304
+ convert to string in iso8601 format.
305
+ If obj is list, sanitize each element in the list.
306
+ If obj is dict, return the dict.
307
+ If obj is OpenAPI model, return the properties dict.
308
+ If obj is io.IOBase, return the bytes
309
+ :param obj: The data to serialize.
310
+ :type obj: Any
311
+ :raises ApiValueError: Unable to prepare type {} for serialization.
312
+ :return: The serialized form of data.
313
+ """
314
+ if isinstance(obj, (ModelNormal, ModelComposed)):
315
+ return {
316
+ key: cls.sanitize_for_serialization(val) for key, val in model_to_dict(obj, serialize=True).items()
317
+ }
318
+ elif isinstance(obj, io.IOBase):
319
+ return cls.get_file_data_and_close_file(obj)
320
+ elif isinstance(obj, (str, int, float, none_type, bool)):
321
+ return obj
322
+ elif isinstance(obj, (datetime, date)):
323
+ return obj.isoformat()
324
+ elif isinstance(obj, ModelSimple):
325
+ return cls.sanitize_for_serialization(obj.value)
326
+ elif isinstance(obj, (list, tuple)):
327
+ return [cls.sanitize_for_serialization(item) for item in obj]
328
+ if isinstance(obj, dict):
329
+ return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
330
+ raise ApiValueError('Unable to prepare type {} for serialization'.format(obj.__class__.__name__))
331
+
332
+ def deserialize(self, response, response_type, _check_type):
333
+ """Deserializes response into an object.
334
+
335
+ :param response: RESTResponse object to be deserialized.
336
+ :type response: Any
337
+ :param response_type: For the response, a tuple containing:
338
+ valid classes
339
+ a list containing valid classes (for list schemas)
340
+ a dict containing a tuple of valid classes as the value
341
+ Example values:
342
+ (str,)
343
+ (Pet,)
344
+ (float, none_type)
345
+ ([int, none_type],)
346
+ ({str: (bool, str, int, float, date, datetime, str, none_type)},)
347
+ :type response_type: Any
348
+ :raises ValueError: Unable to prepare type {} for serialization
349
+ :param _check_type: boolean, whether to check the types of the data
350
+ received from the server
351
+ :type _check_type: bool
352
+
353
+ :return: deserialized object.
354
+ """
355
+ # handle file downloading
356
+ # save response body into a tmp file and return the instance
357
+ if response_type == (file_type,):
358
+ content_disposition = response.getheader("Content-Disposition")
359
+ return deserialize_file(response.data, self.configuration,
360
+ content_disposition=content_disposition)
361
+
362
+ # fetch data from response object
363
+ try:
364
+ received_data = json.loads(response.data)
365
+ except ValueError:
366
+ received_data = response.data
367
+
368
+ # store our data under the key of 'received_data' so users have some
369
+ # context if they are deserializing a string and the data type is wrong
370
+ deserialized_data = validate_and_convert_types(
371
+ received_data,
372
+ response_type,
373
+ ['received_data'],
374
+ True,
375
+ _check_type,
376
+ configuration=self.configuration
377
+ )
378
+ return deserialized_data
379
+
380
+ def call_api(
381
+ self,
382
+ resource_path: str,
383
+ method: str,
384
+ path_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
385
+ query_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
386
+ header_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
387
+ body: typing.Optional[typing.Any] = None,
388
+ post_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
389
+ files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None,
390
+ response_type: typing.Optional[ResponseTypeWithWrapper] = None,
391
+ auth_settings: typing.Optional[typing.List[str]] = None,
392
+ async_req: typing.Optional[bool] = None,
393
+ _return_http_data_only: typing.Optional[bool] = None,
394
+ collection_formats: typing.Optional[typing.Dict[str, str]] = None,
395
+ _preload_content: bool = True,
396
+ _request_timeout: typing.Optional[typing.Union[int, float, typing.Tuple]] = None,
397
+ _host: typing.Optional[str] = None,
398
+ _check_type: typing.Optional[bool] = None
399
+ ):
400
+ """Makes the HTTP request (synchronous) and returns deserialized data.
401
+
402
+ To make an async_req request, set the async_req parameter.
403
+
404
+ :param resource_path: Path to method endpoint.
405
+ :type resource_path: str
406
+ :param method: Method to call.
407
+ :type method: str
408
+ :param path_params: Path parameters in the url.
409
+ :param query_params: Query parameters in the url.
410
+ :param header_params: Header parameters to be
411
+ placed in the request header.
412
+ :param body: Request body.
413
+ :param post_params: Request post form parameters,
414
+ for `application/x-www-form-urlencoded`, `multipart/form-data`.
415
+ :type post_params: dict
416
+ :param auth_settings: Auth Settings names for the request.
417
+ :type auth_settings: list
418
+ :param response_type: Determines the type of the deserialized response.
419
+ A tuple containing a map of response types per status code and an optional wrapper function.
420
+ Example values:
421
+ ({200: ModelA, 201: None, 202: ModelB}, None)
422
+ ({200: ModelA, 201: None, 202: ModelB}, MyWrapper)
423
+ :type response_type: ResponseTypeWithWrapper, optional
424
+ :raises ApiValueError: Unable to prepare type.
425
+ :param files: key -> field name, value -> a list of open file
426
+ objects for `multipart/form-data`.
427
+ :type files: dict
428
+ :param async_req: execute request asynchronously
429
+ :type async_req: bool, optional
430
+ :param _return_http_data_only: response data without head status code
431
+ and headers
432
+ :type _return_http_data_only: bool, optional
433
+ :param collection_formats: dict of collection formats for path, query,
434
+ header, and post parameters.
435
+ :type collection_formats: dict, optional
436
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
437
+ be returned without reading/decoding response
438
+ data. Default is True.
439
+ :type _preload_content: bool, optional
440
+ :param _request_timeout: timeout setting for this request. If one
441
+ number provided, it will be total request
442
+ timeout. It can also be a pair (tuple) of
443
+ (connection, read) timeouts.
444
+ :param _host: host
445
+ :type _host: str, optional
446
+ :param _check_type: boolean describing if the data back from the server
447
+ should have its type checked.
448
+ :type _check_type: bool, optional
449
+ :return:
450
+ If async_req parameter is True,
451
+ the request will be called asynchronously.
452
+ The method will return the request thread.
453
+ If parameter async_req is False or missing,
454
+ then the method will return the response directly.
455
+ """
456
+ if not async_req:
457
+ return self.__call_api(resource_path, method,
458
+ path_params, query_params, header_params,
459
+ body, post_params, files,
460
+ response_type, auth_settings,
461
+ _return_http_data_only, collection_formats,
462
+ _preload_content, _request_timeout, _host,
463
+ _check_type)
464
+
465
+ return self.pool.apply_async(self.__call_api, (resource_path,
466
+ method, path_params,
467
+ query_params,
468
+ header_params, body,
469
+ post_params, files,
470
+ response_type,
471
+ auth_settings,
472
+ _return_http_data_only,
473
+ collection_formats,
474
+ _preload_content,
475
+ _request_timeout,
476
+ _host, _check_type))
477
+
478
+ def request(self, method, url, query_params=None, headers=None,
479
+ post_params=None, body=None, _preload_content=True,
480
+ _request_timeout=None):
481
+ """Makes the HTTP request using RESTClient."""
482
+ if method == "GET":
483
+ return self.rest_client.GET(url,
484
+ query_params=query_params,
485
+ _preload_content=_preload_content,
486
+ _request_timeout=_request_timeout,
487
+ headers=headers)
488
+ elif method == "HEAD":
489
+ return self.rest_client.HEAD(url,
490
+ query_params=query_params,
491
+ _preload_content=_preload_content,
492
+ _request_timeout=_request_timeout,
493
+ headers=headers)
494
+ elif method == "OPTIONS":
495
+ return self.rest_client.OPTIONS(url,
496
+ query_params=query_params,
497
+ headers=headers,
498
+ post_params=post_params,
499
+ _preload_content=_preload_content,
500
+ _request_timeout=_request_timeout,
501
+ body=body)
502
+ elif method == "POST":
503
+ return self.rest_client.POST(url,
504
+ query_params=query_params,
505
+ headers=headers,
506
+ post_params=post_params,
507
+ _preload_content=_preload_content,
508
+ _request_timeout=_request_timeout,
509
+ body=body)
510
+ elif method == "PUT":
511
+ return self.rest_client.PUT(url,
512
+ query_params=query_params,
513
+ headers=headers,
514
+ post_params=post_params,
515
+ _preload_content=_preload_content,
516
+ _request_timeout=_request_timeout,
517
+ body=body)
518
+ elif method == "PATCH":
519
+ return self.rest_client.PATCH(url,
520
+ query_params=query_params,
521
+ headers=headers,
522
+ post_params=post_params,
523
+ _preload_content=_preload_content,
524
+ _request_timeout=_request_timeout,
525
+ body=body)
526
+ elif method == "DELETE":
527
+ return self.rest_client.DELETE(url,
528
+ query_params=query_params,
529
+ headers=headers,
530
+ _preload_content=_preload_content,
531
+ _request_timeout=_request_timeout,
532
+ body=body)
533
+ else:
534
+ raise ApiValueError(
535
+ "http method must be `GET`, `HEAD`, `OPTIONS`,"
536
+ " `POST`, `PATCH`, `PUT` or `DELETE`."
537
+ )
538
+
539
+ def parameters_to_tuples(self, params, collection_formats):
540
+ """Get parameters as list of tuples, formatting collections.
541
+
542
+ :param params: Parameters as dict or list of two-tuples
543
+ :type params: dict, list
544
+ :param collection_formats: Parameter collection formats
545
+ :type collection_formats: dict
546
+ :return: Parameters as list of tuples, collections formatted
547
+ """
548
+ new_params = []
549
+ if collection_formats is None:
550
+ collection_formats = {}
551
+ for k, v in params.items() if isinstance(params, dict) else params: # noqa: E501
552
+ if k in collection_formats:
553
+ collection_format = collection_formats[k]
554
+ if collection_format == 'multi':
555
+ new_params.extend((k, value) for value in v)
556
+ else:
557
+ if collection_format == 'ssv':
558
+ delimiter = ' '
559
+ elif collection_format == 'tsv':
560
+ delimiter = '\t'
561
+ elif collection_format == 'pipes':
562
+ delimiter = '|'
563
+ else: # csv is the default
564
+ delimiter = ','
565
+ new_params.append(
566
+ (k, delimiter.join(str(value) for value in v)))
567
+ else:
568
+ new_params.append((k, v))
569
+ return new_params
570
+
571
+ @staticmethod
572
+ def get_file_data_and_close_file(file_instance: io.IOBase) -> bytes:
573
+ file_data = file_instance.read()
574
+ file_instance.close()
575
+ return file_data
576
+
577
+ def files_parameters(self, files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None):
578
+ """Builds form parameters.
579
+
580
+ :param files: None or a dict with key=param_name and
581
+ value is a list of open file objects
582
+ :type files: dict, None
583
+ :raises ApiValueError: Cannot read a closed file. The passed in file_type.
584
+ :return: List of tuples of form parameters with file data
585
+ """
586
+ if files is None:
587
+ return []
588
+
589
+ params = []
590
+ for param_name, file_instances in files.items():
591
+ if file_instances is None:
592
+ # if the file field is nullable, skip None values
593
+ continue
594
+ for file_instance in file_instances:
595
+ if file_instance is None:
596
+ # if the file field is nullable, skip None values
597
+ continue
598
+ if file_instance.closed is True:
599
+ raise ApiValueError(
600
+ "Cannot read a closed file. The passed in file_type "
601
+ "for %s must be open." % param_name
602
+ )
603
+ filename = os.path.basename(file_instance.name)
604
+ filedata = self.get_file_data_and_close_file(file_instance)
605
+ mimetype = (mimetypes.guess_type(filename)[0] or
606
+ 'application/octet-stream')
607
+ params.append(
608
+ tuple([param_name, tuple([filename, filedata, mimetype])]))
609
+
610
+ return params
611
+
612
+ def select_header_accept(self, accepts):
613
+ """Returns `Accept` based on an array of accepts provided.
614
+
615
+ :param accepts: List of headers.
616
+ :type accepts: list
617
+ :return: Accept (e.g. application/json).
618
+ """
619
+ if not accepts:
620
+ return
621
+
622
+ accepts = [x.lower() for x in accepts]
623
+
624
+ if 'application/json' in accepts:
625
+ return 'application/json'
626
+ else:
627
+ return ', '.join(accepts)
628
+
629
+ def select_header_content_type(self, content_types, method=None, body=None):
630
+ """Returns `Content-Type` based on an array of content_types provided.
631
+
632
+ :param content_types: List of content-types.
633
+ :type content_types: list
634
+ :param method: http method (e.g. POST, PATCH).
635
+ :type method: str
636
+ :param body: http body to send.
637
+ :return: Content-Type (e.g. application/json).
638
+ """
639
+ if not content_types:
640
+ return 'application/json'
641
+
642
+ content_types = [x.lower() for x in content_types]
643
+
644
+ if (method == 'PATCH' and
645
+ 'application/json-patch+json' in content_types and
646
+ isinstance(body, list)):
647
+ return 'application/json-patch+json'
648
+
649
+ if 'application/json' in content_types or '*/*' in content_types:
650
+ return 'application/json'
651
+ else:
652
+ return content_types[0]
653
+
654
+ def update_params_for_auth(self, headers, queries, auth_settings,
655
+ resource_path, method, body):
656
+ """Updates header and query params based on authentication setting.
657
+
658
+ :param headers: Header parameters dict to be updated.
659
+ :type headers: dict
660
+ :param queries: Query parameters tuple list to be updated.
661
+ :type queries: list
662
+ :param auth_settings: Authentication setting identifiers list.
663
+ type auth_settings: list
664
+ :param resource_path: A string representation of the HTTP request resource path.
665
+ :type resource_path: str
666
+ :param method: A string representation of the HTTP request method.
667
+ :type method: str
668
+ :param body: A object representing the body of the HTTP request.
669
+ The object type is the return value of _encoder.default().
670
+ """
671
+ if not auth_settings:
672
+ return
673
+
674
+ auth_settings_dict = self.configuration.auth_settings()
675
+
676
+ for auth in auth_settings:
677
+ auth_setting = auth_settings_dict.get(auth)
678
+ if auth_setting:
679
+ if auth_setting['in'] == 'cookie':
680
+ headers['Cookie'] = auth_setting['value']
681
+ elif auth_setting['in'] == 'header':
682
+ if auth_setting['type'] != 'http-signature':
683
+ headers[auth_setting['key']] = auth_setting['value']
684
+ elif auth_setting['in'] == 'query':
685
+ queries.append((auth_setting['key'], auth_setting['value']))
686
+ else:
687
+ raise ApiValueError(
688
+ 'Authentication token must be in `query` or `header`'
689
+ )
690
+
691
+
692
+ class Endpoint(object):
693
+ def __init__(self, settings=None, params_map=None, root_map=None,
694
+ headers_map=None, api_client=None, callable=None):
695
+ """Creates an endpoint
696
+
697
+ Args:
698
+ settings (dict): see below key value pairs
699
+ 'response_type' (ResponseTypeWithWrapper/None): response type map and wrapper function
700
+ 'auth' (list): a list of auth type keys
701
+ 'endpoint_path' (str): the endpoint path
702
+ 'operation_id' (str): endpoint string identifier
703
+ 'http_method' (str): POST/PUT/PATCH/GET etc
704
+ 'servers' (list): list of str servers that this endpoint is at
705
+ params_map (dict): see below key value pairs
706
+ 'all' (list): list of str endpoint parameter names
707
+ 'required' (list): list of required parameter names
708
+ 'nullable' (list): list of nullable parameter names
709
+ 'enum' (list): list of parameters with enum values
710
+ 'validation' (list): list of parameters with validations
711
+ root_map
712
+ 'validations' (dict): the dict mapping endpoint parameter tuple
713
+ paths to their validation dictionaries
714
+ 'allowed_values' (dict): the dict mapping endpoint parameter
715
+ tuple paths to their allowed_values (enum) dictionaries
716
+ 'openapi_types' (dict): param_name to openapi type
717
+ 'attribute_map' (dict): param_name to camelCase name
718
+ 'location_map' (dict): param_name to 'body', 'file', 'form',
719
+ 'header', 'path', 'query'
720
+ 'collection_format_map' (dict): param_name to `csv` etc.
721
+ headers_map (dict): see below key value pairs
722
+ 'accept' (list): list of Accept header strings
723
+ 'content_type' (list): list of Content-Type header strings
724
+ api_client (ApiClient) api client instance
725
+ callable (function): the function which is invoked when the
726
+ Endpoint is called
727
+ """
728
+ self.settings = settings
729
+ self.params_map = params_map
730
+ self.params_map['all'].extend([
731
+ 'async_req',
732
+ '_host_index',
733
+ '_preload_content',
734
+ '_request_timeout',
735
+ '_return_http_data_only',
736
+ '_check_input_type',
737
+ '_check_return_type',
738
+ '_content_type',
739
+ '_spec_property_naming'
740
+ ])
741
+ self.params_map['nullable'].extend(['_request_timeout'])
742
+ self.validations = root_map['validations']
743
+ self.allowed_values = root_map['allowed_values']
744
+ self.openapi_types = root_map['openapi_types']
745
+ extra_types = {
746
+ 'async_req': (bool,),
747
+ '_host_index': (none_type, int),
748
+ '_preload_content': (bool,),
749
+ '_request_timeout': (none_type, float, (float,), [float], int, (int,), [int]),
750
+ '_return_http_data_only': (bool,),
751
+ '_check_input_type': (bool,),
752
+ '_check_return_type': (bool,),
753
+ '_spec_property_naming': (bool,),
754
+ '_content_type': (none_type, str)
755
+ }
756
+ self.openapi_types.update(extra_types)
757
+ self.attribute_map = root_map['attribute_map']
758
+ self.location_map = root_map['location_map']
759
+ self.collection_format_map = root_map['collection_format_map']
760
+ self.headers_map = headers_map
761
+ self.api_client = api_client
762
+ self.callable = callable
763
+
764
+ def __validate_inputs(self, kwargs):
765
+ for param in self.params_map['enum']:
766
+ if param in kwargs:
767
+ check_allowed_values(
768
+ self.allowed_values,
769
+ (param,),
770
+ kwargs[param]
771
+ )
772
+
773
+ for param in self.params_map['validation']:
774
+ if param in kwargs:
775
+ check_validations(
776
+ self.validations,
777
+ (param,),
778
+ kwargs[param],
779
+ configuration=self.api_client.configuration
780
+ )
781
+
782
+ if kwargs['_check_input_type'] is False:
783
+ return
784
+
785
+ for key, value in kwargs.items():
786
+ fixed_val = validate_and_convert_types(
787
+ value,
788
+ self.openapi_types[key],
789
+ [key],
790
+ kwargs['_spec_property_naming'],
791
+ kwargs['_check_input_type'],
792
+ configuration=self.api_client.configuration
793
+ )
794
+ kwargs[key] = fixed_val
795
+
796
+ def __gather_params(self, kwargs):
797
+ params = {
798
+ 'body': None,
799
+ 'collection_format': {},
800
+ 'file': {},
801
+ 'form': [],
802
+ 'header': {},
803
+ 'path': {},
804
+ 'query': []
805
+ }
806
+
807
+ for param_name, param_value in kwargs.items():
808
+ param_location = self.location_map.get(param_name)
809
+ if param_location is None:
810
+ continue
811
+ if param_location:
812
+ if param_location == 'body':
813
+ params['body'] = param_value
814
+ continue
815
+ base_name = self.attribute_map[param_name]
816
+ if (param_location == 'form' and
817
+ self.openapi_types[param_name] == (file_type,)):
818
+ params['file'][base_name] = [param_value]
819
+ elif (param_location == 'form' and
820
+ self.openapi_types[param_name] == ([file_type],)):
821
+ # param_value is already a list
822
+ params['file'][base_name] = param_value
823
+ elif param_location in {'form', 'query'}:
824
+ param_value_full = (base_name, param_value)
825
+ params[param_location].append(param_value_full)
826
+ if param_location not in {'form', 'query'}:
827
+ params[param_location][base_name] = param_value
828
+ collection_format = self.collection_format_map.get(param_name)
829
+ if collection_format:
830
+ params['collection_format'][base_name] = collection_format
831
+
832
+ return params
833
+
834
+ def __call__(self, *args, **kwargs):
835
+ """ This method is invoked when endpoints are called
836
+ Example:
837
+
838
+ api_instance = CalculationsApi()
839
+ api_instance.analytics_quant_fpe_v1_calculations_id_get # this is an instance of the class Endpoint
840
+ api_instance.analytics_quant_fpe_v1_calculations_id_get() # this invokes api_instance.analytics_quant_fpe_v1_calculations_id_get.__call__()
841
+ which then invokes the callable functions stored in that endpoint at
842
+ api_instance.analytics_quant_fpe_v1_calculations_id_get.callable or self.callable in this class
843
+
844
+ """
845
+ return self.callable(self, *args, **kwargs)
846
+
847
+ def call_with_http_info(self, **kwargs):
848
+
849
+ try:
850
+ index = self.api_client.configuration.server_operation_index.get(
851
+ self.settings['operation_id'], self.api_client.configuration.server_index
852
+ ) if kwargs['_host_index'] is None else kwargs['_host_index']
853
+ server_variables = self.api_client.configuration.server_operation_variables.get(
854
+ self.settings['operation_id'], self.api_client.configuration.server_variables
855
+ )
856
+ _host = self.api_client.configuration.get_host_from_settings(
857
+ index, variables=server_variables, servers=self.settings['servers']
858
+ )
859
+ except IndexError:
860
+ if self.settings['servers']:
861
+ raise ApiValueError(
862
+ "Invalid host index. Must be 0 <= index < %s" %
863
+ len(self.settings['servers'])
864
+ )
865
+ _host = None
866
+
867
+ for key, value in kwargs.items():
868
+ if key not in self.params_map['all']:
869
+ raise ApiTypeError(
870
+ "Got an unexpected parameter '%s'"
871
+ " to method `%s`" %
872
+ (key, self.settings['operation_id'])
873
+ )
874
+ # only throw this nullable ApiValueError if _check_input_type
875
+ # is False, if _check_input_type==True we catch this case
876
+ # in self.__validate_inputs
877
+ if (key not in self.params_map['nullable'] and value is None
878
+ and kwargs['_check_input_type'] is False):
879
+ raise ApiValueError(
880
+ "Value may not be None for non-nullable parameter `%s`"
881
+ " when calling `%s`" %
882
+ (key, self.settings['operation_id'])
883
+ )
884
+
885
+ for key in self.params_map['required']:
886
+ if key not in kwargs.keys():
887
+ raise ApiValueError(
888
+ "Missing the required parameter `%s` when calling "
889
+ "`%s`" % (key, self.settings['operation_id'])
890
+ )
891
+
892
+ self.__validate_inputs(kwargs)
893
+
894
+ params = self.__gather_params(kwargs)
895
+
896
+ accept_headers_list = self.headers_map['accept']
897
+ if accept_headers_list:
898
+ params['header']['Accept'] = self.api_client.select_header_accept(
899
+ accept_headers_list)
900
+
901
+ if kwargs.get('_content_type'):
902
+ params['header']['Content-Type'] = kwargs['_content_type']
903
+ else:
904
+ content_type_headers_list = self.headers_map['content_type']
905
+ if content_type_headers_list:
906
+ if params['body'] != "":
907
+ header_list = self.api_client.select_header_content_type(
908
+ content_type_headers_list, self.settings['http_method'],
909
+ params['body'])
910
+ params['header']['Content-Type'] = header_list
911
+
912
+ return self.api_client.call_api(
913
+ self.settings['endpoint_path'], self.settings['http_method'],
914
+ params['path'],
915
+ params['query'],
916
+ params['header'],
917
+ body=params['body'],
918
+ post_params=params['form'],
919
+ files=params['file'],
920
+ response_type=self.settings['response_type'],
921
+ auth_settings=self.settings['auth'],
922
+ async_req=kwargs['async_req'],
923
+ _check_type=kwargs['_check_return_type'],
924
+ _return_http_data_only=kwargs['_return_http_data_only'],
925
+ _preload_content=kwargs['_preload_content'],
926
+ _request_timeout=kwargs['_request_timeout'],
927
+ _host=_host,
928
+ collection_formats=params['collection_format'])