docusign_esign.client.api_client
Docusign eSignature REST API
The Docusign eSignature REST API provides you with a powerful, convenient, and simple Web services API for interacting with Docusign. # noqa: E501
OpenAPI spec version: v2.1 Contact: devcenter@docusign.com Generated by: https://github.com/swagger-api/swagger-codegen.git
1# coding: utf-8 2 3""" 4 Docusign eSignature REST API 5 6 The Docusign eSignature REST API provides you with a powerful, convenient, and simple Web services API for interacting with Docusign. # noqa: E501 7 8 OpenAPI spec version: v2.1 9 Contact: devcenter@docusign.com 10 Generated by: https://github.com/swagger-api/swagger-codegen.git 11""" 12 13 14from __future__ import absolute_import 15 16import os 17import re 18import json 19import mimetypes 20import threading 21import base64 22import math 23import jwt 24 25from datetime import date, datetime 26from time import time 27 28# python 2 and python 3 compatibility library 29from six import PY3, integer_types, iteritems, text_type 30from six.moves.urllib.parse import quote 31 32from docusign_esign import client 33from docusign_esign import models 34 35from .configuration import Configuration 36from .api_exception import ApiException, ArgumentException 37from .api_response import RESTClientObject, RESTResponse 38from .auth.oauth import OAuthUserInfo, OAuthToken, OAuth, Account, Organization, Link 39 40class ApiClient(object): 41 """ 42 Generic API client for Swagger client library builds. 43 44 Swagger generic API client. This client handles the client- 45 server communication, and is invariant across implementations. Specifics of 46 the methods and models for each application are generated from the Swagger 47 templates. 48 49 NOTE: This class is auto generated by the swagger code generator program. 50 Ref: https://github.com/swagger-api/swagger-codegen 51 Do not edit the class manually. 52 53 :param host: The base path for the server to call. 54 :param header_name: a header to pass when making calls to the API. 55 :param header_value: a header value to pass when making calls to the API. 56 """ 57 58 PRIMITIVE_TYPES = (float, bool, bytes, text_type) + integer_types 59 NATIVE_TYPES_MAPPING = { 60 'int': int, 61 'long': int if PY3 else long, 62 'float': float, 63 'str': str, 64 'bool': bool, 65 'date': date, 66 'datetime': datetime, 67 'object': object, 68 } 69 70 OAUTH_TYPES = (OAuthToken.__name__, OAuthUserInfo.__name__, Account.__name__, Organization.__name__, Link.__name__) 71 72 def __init__(self, host=None, header_name=None, header_value=None, cookie=None, oauth_host_name=None, base_path=None): 73 """ 74 Constructor of the class. 75 """ 76 77 config = Configuration() 78 self.rest_client = RESTClientObject(configuration=config) 79 self.default_headers = {'X-DocuSign-SDK': 'Python'} 80 if header_name is not None: 81 self.default_headers[header_name] = header_value 82 if host is None: 83 self.host = config.host 84 elif host == "": 85 raise ArgumentException("basePath cannot be empty") 86 else: 87 self.host = host 88 89 self.cookie = cookie 90 self.base_path = base_path 91 self.set_oauth_host_name(oauth_host_name) 92 93 # Set default User-Agent. 94 self.user_agent = config.user_agent 95 96 @property 97 def user_agent(self): 98 """ 99 Gets user agent. 100 """ 101 return self.default_headers['User-Agent'] 102 103 @user_agent.setter 104 def user_agent(self, value): 105 """ 106 Sets user agent. 107 """ 108 self.default_headers['User-Agent'] = value 109 110 def set_default_header(self, header_name, header_value): 111 self.default_headers[header_name] = header_value 112 113 def __call_api(self, resource_path, method, 114 path_params=None, query_params=None, header_params=None, 115 body=None, post_params=None, files=None, 116 response_type=None, auth_settings=None, callback=None, 117 _return_http_data_only=None, collection_formats=None, _preload_content=True, 118 _request_timeout=None): 119 """ 120 :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without 121 reading/decoding response data. Default is True. 122 :return: 123 """ 124 125 # header parameters 126 header_params = header_params or {} 127 header_params.update(self.default_headers) 128 if self.cookie: 129 header_params['Cookie'] = self.cookie 130 if header_params: 131 header_params = self.sanitize_for_serialization(header_params) 132 header_params = dict(self.parameters_to_tuples(header_params, 133 collection_formats)) 134 135 # path parameters 136 if path_params: 137 path_params = self.sanitize_for_serialization(path_params) 138 path_params = self.parameters_to_tuples(path_params, 139 collection_formats) 140 for k, v in path_params: 141 resource_path = resource_path.replace( 142 '{%s}' % k, quote(str(v), safe="")) 143 144 # query parameters 145 if query_params: 146 query_params = self.sanitize_for_serialization(query_params) 147 query_params = self.parameters_to_tuples(query_params, 148 collection_formats) 149 150 # post parameters 151 if post_params or files: 152 post_params = self.prepare_post_parameters(post_params, files) 153 post_params = self.sanitize_for_serialization(post_params) 154 post_params = self.parameters_to_tuples(post_params, 155 collection_formats) 156 157 # auth setting 158 self.update_params_for_auth(header_params, query_params, auth_settings) 159 160 # body 161 if body: 162 body = self.sanitize_for_serialization(body) 163 164 # request url 165 url = self.host + resource_path 166 167 # perform request and return response 168 response_data = self.request(method, url, 169 query_params=query_params, 170 headers=header_params, 171 post_params=post_params, body=body, 172 _preload_content=_preload_content, 173 _request_timeout=_request_timeout) 174 175 self.last_response = response_data 176 177 return_data = response_data 178 if _preload_content: 179 r = RESTResponse(response_data) 180 181 # deserialize response data 182 if response_type: 183 # In the python 3, the response.data is bytes. 184 # we need to decode it to string. 185 if PY3 and response_type != "file": 186 try: 187 r.data = r.data.decode('utf8', 'replace') 188 except (UnicodeDecodeError, AttributeError): 189 pass 190 191 if response_type == "file": 192 return_data = r.data 193 else: 194 return_data = self.deserialize(r, response_type) 195 else: 196 return_data = None 197 198 if callback: 199 if _return_http_data_only: 200 callback(return_data) 201 else: 202 callback((return_data, response_data.status, response_data.getheaders())) 203 elif _return_http_data_only: 204 return (return_data) 205 else: 206 return (return_data, response_data.status, response_data.getheaders()) 207 208 def sanitize_for_serialization(self, obj): 209 """ 210 Builds a JSON POST object. 211 212 If obj is None, return None. 213 If obj is str, int, long, float, bool, return directly. 214 If obj is datetime.datetime, datetime.date 215 convert to string in iso8601 format. 216 If obj is list, sanitize each element in the list. 217 If obj is dict, return the dict. 218 If obj is swagger model, return the properties dict. 219 220 :param obj: The data to serialize. 221 :return: The serialized form of data. 222 """ 223 if obj is None: 224 return None 225 elif isinstance(obj, self.PRIMITIVE_TYPES): 226 return obj 227 elif isinstance(obj, list): 228 return [self.sanitize_for_serialization(sub_obj) 229 for sub_obj in obj] 230 elif isinstance(obj, tuple): 231 return tuple(self.sanitize_for_serialization(sub_obj) 232 for sub_obj in obj) 233 elif isinstance(obj, (datetime, date)): 234 return obj.isoformat() 235 236 if isinstance(obj, dict): 237 obj_dict = obj 238 else: 239 # Convert model obj to dict except 240 # attributes `swagger_types`, `attribute_map` 241 # and attributes which value is not None. 242 # Convert attribute name to json key in 243 # model definition for request. 244 obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) 245 for attr, _ in iteritems(obj.swagger_types) 246 if getattr(obj, attr) is not None} 247 248 return {key: self.sanitize_for_serialization(val) 249 for key, val in iteritems(obj_dict)} 250 251 def deserialize(self, response, response_type): 252 """ 253 Deserializes response into an object. 254 255 :param response: RESTResponse object to be deserialized. 256 :param response_type: class literal for 257 deserialized object, or string of class name. 258 259 :return: deserialized object. 260 """ 261 # handle file type response 262 if response_type == "file": 263 return response.data 264 265 # fetch data from response object 266 try: 267 data = json.loads(response.data) 268 except ValueError: 269 data = response.data 270 271 return self.__deserialize(data, response_type) 272 273 def __deserialize(self, data, klass): 274 """ 275 Deserializes dict, list, str into an object. 276 277 :param data: dict, list or str. 278 :param klass: class literal, or string of class name. 279 280 :return: object. 281 """ 282 if data is None: 283 return None 284 285 if type(klass) == str: 286 if klass.startswith('list['): 287 sub_kls = re.match(r'list\[(.*)\]', klass).group(1) 288 return [self.__deserialize(sub_data, sub_kls) 289 for sub_data in data] 290 291 if klass.startswith('dict('): 292 sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2) 293 return {k: self.__deserialize(v, sub_kls) 294 for k, v in iteritems(data)} 295 296 # convert str to class 297 if klass in self.NATIVE_TYPES_MAPPING: 298 klass = self.NATIVE_TYPES_MAPPING[klass] 299 else: 300 if klass in self.OAUTH_TYPES: 301 klass = getattr(client, klass) 302 else: 303 klass = getattr(models, klass) 304 305 if klass in self.PRIMITIVE_TYPES: 306 return self.__deserialize_primitive(data, klass) 307 elif klass == object: 308 return self.__deserialize_object(data) 309 elif klass == date: 310 return self.__deserialize_date(data) 311 elif klass == datetime: 312 return self.__deserialize_datatime(data) 313 else: 314 return self.__deserialize_model(data, klass) 315 316 def call_api(self, resource_path, method, 317 path_params=None, query_params=None, header_params=None, 318 body=None, post_params=None, files=None, 319 response_type=None, auth_settings=None, callback=None, 320 _return_http_data_only=None, collection_formats=None, _preload_content=True, 321 _request_timeout=None): 322 """ 323 Makes the HTTP request (synchronous) and return the deserialized data. 324 To make an async request, define a function for callback. 325 326 :param resource_path: Path to method endpoint. 327 :param method: Method to call. 328 :param path_params: Path parameters in the url. 329 :param query_params: Query parameters in the url. 330 :param header_params: Header parameters to be 331 placed in the request header. 332 :param body: Request body. 333 :param post_params dict: Request post form parameters, 334 for `application/x-www-form-urlencoded`, `multipart/form-data`. 335 :param auth_settings list: Auth Settings names for the request. 336 :param response: Response data type. 337 :param files dict: key -> filename, value -> filepath, 338 for `multipart/form-data`. 339 :param callback function: Callback function for asynchronous request. 340 If provide this parameter, 341 the request will be called asynchronously. 342 :param _return_http_data_only: response data without head status code and headers 343 :param collection_formats: dict of collection formats for path, query, 344 header, and post parameters. 345 :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without 346 reading/decoding response data. Default is True. 347 :param _request_timeout: timeout setting for this request. If one number provided, it will be total request 348 timeout. It can also be a pair (tuple) of (connection, read) timeouts. 349 :return: 350 If provide parameter callback, 351 the request will be called asynchronously. 352 The method will return the request thread. 353 If parameter callback is None, 354 then the method will return the response directly. 355 """ 356 if callback is None: 357 return self.__call_api(resource_path, method, 358 path_params, query_params, header_params, 359 body, post_params, files, 360 response_type, auth_settings, callback, 361 _return_http_data_only, collection_formats, _preload_content, _request_timeout) 362 else: 363 thread = threading.Thread(target=self.__call_api, 364 args=(resource_path, method, 365 path_params, query_params, 366 header_params, body, 367 post_params, files, 368 response_type, auth_settings, 369 callback, _return_http_data_only, 370 collection_formats, _preload_content, _request_timeout)) 371 thread.start() 372 return thread 373 374 def request(self, method, url, query_params=None, headers=None, 375 post_params=None, body=None, _preload_content=True, _request_timeout=None): 376 """ 377 Makes the HTTP request using RESTClient. 378 """ 379 if method == "GET": 380 return self.rest_client.GET(url, 381 query_params=query_params, 382 _preload_content=_preload_content, 383 _request_timeout=_request_timeout, 384 headers=headers) 385 elif method == "HEAD": 386 return self.rest_client.HEAD(url, 387 query_params=query_params, 388 _preload_content=_preload_content, 389 _request_timeout=_request_timeout, 390 headers=headers) 391 elif method == "OPTIONS": 392 return self.rest_client.OPTIONS(url, 393 query_params=query_params, 394 headers=headers, 395 post_params=post_params, 396 _preload_content=_preload_content, 397 _request_timeout=_request_timeout, 398 body=body) 399 elif method == "POST": 400 return self.rest_client.POST(url, 401 query_params=query_params, 402 headers=headers, 403 post_params=post_params, 404 _preload_content=_preload_content, 405 _request_timeout=_request_timeout, 406 body=body) 407 elif method == "PUT": 408 return self.rest_client.PUT(url, 409 query_params=query_params, 410 headers=headers, 411 post_params=post_params, 412 _preload_content=_preload_content, 413 _request_timeout=_request_timeout, 414 body=body) 415 elif method == "PATCH": 416 return self.rest_client.PATCH(url, 417 query_params=query_params, 418 headers=headers, 419 post_params=post_params, 420 _preload_content=_preload_content, 421 _request_timeout=_request_timeout, 422 body=body) 423 elif method == "DELETE": 424 return self.rest_client.DELETE(url, 425 query_params=query_params, 426 headers=headers, 427 _preload_content=_preload_content, 428 _request_timeout=_request_timeout, 429 body=body) 430 else: 431 raise ValueError( 432 "http method must be `GET`, `HEAD`, `OPTIONS`," 433 " `POST`, `PATCH`, `PUT` or `DELETE`." 434 ) 435 436 def parameters_to_tuples(self, params, collection_formats): 437 """ 438 Get parameters as list of tuples, formatting collections. 439 440 :param params: Parameters as dict or list of two-tuples 441 :param dict collection_formats: Parameter collection formats 442 :return: Parameters as list of tuples, collections formatted 443 """ 444 new_params = [] 445 if collection_formats is None: 446 collection_formats = {} 447 for k, v in iteritems(params) if isinstance(params, dict) else params: 448 if k in collection_formats: 449 collection_format = collection_formats[k] 450 if collection_format == 'multi': 451 new_params.extend((k, value) for value in v) 452 else: 453 if collection_format == 'ssv': 454 delimiter = ' ' 455 elif collection_format == 'tsv': 456 delimiter = '\t' 457 elif collection_format == 'pipes': 458 delimiter = '|' 459 else: # csv is the default 460 delimiter = ',' 461 new_params.append( 462 (k, delimiter.join(str(value) for value in v))) 463 else: 464 new_params.append((k, v)) 465 return new_params 466 467 def prepare_post_parameters(self, post_params=None, files=None): 468 """ 469 Builds form parameters. 470 471 :param post_params: Normal form parameters. 472 :param files: File parameters. 473 :return: Form parameters with files. 474 """ 475 params = [] 476 477 if post_params: 478 params = post_params 479 480 if files: 481 for k, v in iteritems(files): 482 if not v: 483 continue 484 file_names = v if type(v) is list else [v] 485 for n in file_names: 486 with open(n, 'rb') as f: 487 filename = os.path.basename(f.name) 488 filedata = f.read() 489 mimetype = mimetypes.\ 490 guess_type(filename)[0] or 'application/octet-stream' 491 params.append(tuple([k, tuple([filename, filedata, mimetype])])) 492 493 return params 494 495 def select_header_accept(self, accepts): 496 """ 497 Returns `Accept` based on an array of accepts provided. 498 499 :param accepts: List of headers. 500 :return: Accept (e.g. application/json). 501 """ 502 if not accepts: 503 return 504 505 accepts = [x.lower() for x in accepts] 506 507 if 'application/json' in accepts: 508 return 'application/json' 509 else: 510 return ', '.join(accepts) 511 512 def select_header_content_type(self, content_types): 513 """ 514 Returns `Content-Type` based on an array of content_types provided. 515 516 :param content_types: List of content-types. 517 :return: Content-Type (e.g. application/json). 518 """ 519 if not content_types: 520 return 'application/json' 521 522 content_types = [x.lower() for x in content_types] 523 524 if 'application/json' in content_types or '*/*' in content_types: 525 return 'application/json' 526 else: 527 return content_types[0] 528 529 def update_params_for_auth(self, headers, querys, auth_settings): 530 """ 531 Updates header and query params based on authentication setting. 532 533 :param headers: Header parameters dict to be updated. 534 :param querys: Query parameters tuple list to be updated. 535 :param auth_settings: Authentication setting identifiers list. 536 """ 537 config = Configuration() 538 539 if not auth_settings: 540 return 541 542 for auth in auth_settings: 543 auth_setting = config.auth_settings().get(auth) 544 if auth_setting: 545 if not auth_setting['value']: 546 continue 547 elif auth_setting['in'] == 'header': 548 headers[auth_setting['key']] = auth_setting['value'] 549 elif auth_setting['in'] == 'query': 550 querys.append((auth_setting['key'], auth_setting['value'])) 551 else: 552 raise ValueError( 553 'Authentication token must be in `query` or `header`' 554 ) 555 556 def __deserialize_primitive(self, data, klass): 557 """ 558 Deserializes string to primitive type. 559 560 :param data: str. 561 :param klass: class literal. 562 563 :return: int, long, float, str, bool. 564 """ 565 try: 566 return klass(data) 567 except UnicodeEncodeError: 568 return unicode(data) 569 except TypeError: 570 return data 571 572 def __deserialize_object(self, value): 573 """ 574 Return a original value. 575 576 :return: object. 577 """ 578 return value 579 580 def __deserialize_date(self, string): 581 """ 582 Deserializes string to date. 583 584 :param string: str. 585 :return: date. 586 """ 587 try: 588 from dateutil.parser import parse 589 return parse(string).date() 590 except ImportError: 591 return string 592 except ValueError: 593 raise ApiException( 594 status=0, 595 reason="Failed to parse `{0}` into a date object".format(string) 596 ) 597 598 def __deserialize_datatime(self, string): 599 """ 600 Deserializes string to datetime. 601 602 The string should be in iso8601 datetime format. 603 604 :param string: str. 605 :return: datetime. 606 """ 607 try: 608 from dateutil.parser import parse 609 return parse(string) 610 except ImportError: 611 return string 612 except ValueError: 613 raise ApiException( 614 status=0, 615 reason=( 616 "Failed to parse `{0}` into a datetime object" 617 .format(string) 618 ) 619 ) 620 621 def __deserialize_model(self, data, klass): 622 """ 623 Deserializes list or dict to model. 624 625 :param data: dict, list. 626 :param klass: class literal. 627 :return: model object. 628 """ 629 instance = klass() 630 631 if not instance.swagger_types: 632 return data 633 634 for attr, attr_type in iteritems(instance.swagger_types): 635 if data is not None \ 636 and instance.attribute_map[attr] in data \ 637 and isinstance(data, (list, dict)): 638 value = data[instance.attribute_map[attr]] 639 setattr(instance, attr, self.__deserialize(value, attr_type)) 640 641 return instance 642 643 def request_jwt_user_token(self, client_id, user_id, oauth_host_name, private_key_bytes, expires_in, 644 scopes=(OAuth.SCOPE_SIGNATURE,)): 645 """ 646 Request JWT User Token 647 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 648 :param user_id: Docusign user Id to be impersonated 649 :param oauth_host_name: Docusign OAuth host name 650 :param private_key_bytes: the byte contents of the RSA private key 651 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 652 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 653 advanced scope. 654 :return: OAuthToken object 655 """ 656 if not private_key_bytes: 657 raise ArgumentException("Private key not supplied or is invalid!") 658 if not user_id: 659 raise ArgumentException("User Id not supplied or is invalid!") 660 if not oauth_host_name: 661 raise ArgumentException("oAuthBasePath cannot be empty") 662 663 now = math.floor(time()) 664 later = now + (expires_in * 1) 665 claim = {"iss": client_id, "sub": user_id, "aud": oauth_host_name, "iat": now, "exp": later, 666 "scope": " ".join(scopes)} 667 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 668 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 669 headers=self.sanitize_for_serialization( 670 {"Content-Type": "application/x-www-form-urlencoded"}), 671 post_params=self.sanitize_for_serialization( 672 {"assertion": token, "grant_type": OAuth.GRANT_TYPE_JWT})) 673 674 response_data = json.loads(response.data) 675 676 if 'token_type' in response_data and 'access_token' in response_data: 677 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 678 else: 679 raise ApiException(status=response.status, 680 reason="Error while requesting server, received a non successful HTTP code {}" 681 " with response Body: {}".format(response.status, response.data) 682 ) 683 684 return self.deserialize(response=response, response_type=OAuthToken) 685 686 def request_jwt_application_token(self, client_id, oauth_host_name, private_key_bytes, expires_in, 687 scopes=(OAuth.SCOPE_SIGNATURE,)): 688 """ 689 Request JWT Application Token 690 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 691 :param oauth_host_name: Docusign OAuth host name 692 :param private_key_bytes: the byte contents of the RSA private key 693 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 694 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 695 advanced scope. 696 :return: OAuthToken object 697 """ 698 699 if not private_key_bytes: 700 raise ArgumentException("Private key not supplied or is invalid!") 701 if not oauth_host_name: 702 raise ArgumentException("oAuthBasePath cannot be empty") 703 704 now = math.floor(time()) 705 later = now + (expires_in * 1) 706 claim = {"iss": client_id, "aud": oauth_host_name, "iat": now, "exp": later, 707 "scope": " ".join(scopes)} 708 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 709 710 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 711 headers=self.sanitize_for_serialization( 712 {"Content-Type": "application/x-www-form-urlencoded"}), 713 post_params=self.sanitize_for_serialization( 714 {"assertion": token, "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"})) 715 response_data = json.loads(response.data) 716 717 if 'token_type' in response_data and 'access_token' in response_data: 718 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 719 else: 720 ApiException(status=response.status, 721 reason="Error while requesting server, received a non successful HTTP code {}" 722 " with response Body: {}".format(response.status, response.data) 723 ) 724 725 return self.deserialize(response=response, response_type=OAuthToken) 726 727 def get_user_info(self, access_token): 728 """ 729 Get User Info method takes the accessToken to retrieve User Account Data. 730 :param access_token: 731 :return: The User Info model. 732 """ 733 if not access_token: 734 raise ArgumentException("Cannot find a valid access token." 735 " Make sure OAuth is configured before you try again.") 736 if not self.oauth_host_name: 737 raise ArgumentException("oAuthBasePath cannot be empty") 738 739 resource_path = '/oauth/userinfo' 740 headers = {"Authorization": "Bearer " + access_token} 741 742 response = self.request("GET", "https://" + self.oauth_host_name + resource_path, headers=headers) 743 return self.deserialize(response=response, response_type=OAuthUserInfo) 744 745 def generate_access_token(self, client_id, client_secret, code): 746 """ 747 GenerateAccessToken will exchange the authorization code for an access token and refresh tokens. 748 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 749 :param client_secret: The secret key you generated when you set up the integration in Docusign Admin console. 750 :param code: The authorization code 751 :return: OAuthToken object 752 """ 753 if not client_id or not client_secret or not code: 754 raise ArgumentException 755 url = "https://{0}/oauth/token".format(self.oauth_host_name) 756 integrator_and_secret_key = b"Basic " + base64.b64encode(str.encode("{}:{}".format(client_id, client_secret))) 757 headers = { 758 "Authorization": integrator_and_secret_key.decode("utf-8"), 759 "Content-Type": "application/x-www-form-urlencoded", 760 } 761 post_params = self.sanitize_for_serialization({ 762 "grant_type": "authorization_code", 763 "code": code 764 }) 765 response = self.rest_client.POST(url, headers=headers, post_params=post_params) 766 767 return self.deserialize(response=response, response_type=OAuthToken) 768 769 def set_base_path(self, base_path): 770 """ 771 :param base_path: 772 :return: 773 """ 774 self.base_path = base_path 775 776 def set_oauth_host_name(self, oauth_host_name=None): 777 """ 778 :param oauth_host_name: 779 :return: 780 """ 781 if oauth_host_name: 782 self.oauth_host_name = oauth_host_name 783 return 784 785 # Derive OAuth Base Path if not given 786 if self.base_path is None or self.base_path.startswith("https://demo") or self.base_path.startswith("http://demo") or self.base_path.startswith("https://apps-d") or self.base_path.startswith("http://apps-d"): 787 self.oauth_host_name = OAuth.DEMO_OAUTH_BASE_PATH 788 elif self.base_path.startswith("https://stage") or self.base_path.startswith("http://stage") or self.base_path.startswith("https://apps-s") or self.base_path.startswith("http://apps-s"): 789 self.oauth_host_name = OAuth.STAGE_OAUTH_BASE_PATH 790 else: 791 self.oauth_host_name = OAuth.PRODUCTION_OAUTH_BASE_PATH 792 793 def set_access_token(self, token_obj): 794 """ 795 796 :param token_obj: 797 :return: 798 """ 799 self.default_headers['Authorization'] = token_obj.access_token 800 801 def get_authorization_uri(self, client_id, scopes, redirect_uri, response_type, state=None): 802 """ 803 Helper method to configure the OAuth accessCode/implicit flow parameters 804 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 805 :param scopes: The list of requested scopes. Client applications may be scoped to a limited set of system access. 806 :param redirect_uri: This determines where to deliver the response containing the authorization code 807 :param response_type: Determines the response type of the authorization request, NOTE: these response types are 808 mutually exclusive for a client application. A public/native client application may only request a response type 809 of "token". A private/trusted client application may only request a response type of "code". 810 :param state: Allows for arbitrary state that may be useful to your application. The value in this parameter 811 will be round-tripped along with the response so you can make sure it didn't change. 812 :return: string 813 """ 814 if not self.oauth_host_name: 815 self.oauth_host_name = self.get_oauth_host_name() 816 scopes = " ".join(scopes) if scopes else "" 817 uri = "https://{}/oauth/auth?response_type={}&scope={}&client_id={}&redirect_uri={}" 818 if state: 819 uri += "&state={}" 820 return uri.format(self.oauth_host_name, response_type, quote(scopes), client_id, redirect_uri, state) 821 822 def get_oauth_host_name(self): 823 """ 824 :return: string 825 """ 826 if not self.oauth_host_name: 827 self.set_oauth_host_name() 828 829 return self.oauth_host_name
41class ApiClient(object): 42 """ 43 Generic API client for Swagger client library builds. 44 45 Swagger generic API client. This client handles the client- 46 server communication, and is invariant across implementations. Specifics of 47 the methods and models for each application are generated from the Swagger 48 templates. 49 50 NOTE: This class is auto generated by the swagger code generator program. 51 Ref: https://github.com/swagger-api/swagger-codegen 52 Do not edit the class manually. 53 54 :param host: The base path for the server to call. 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 the API. 57 """ 58 59 PRIMITIVE_TYPES = (float, bool, bytes, text_type) + integer_types 60 NATIVE_TYPES_MAPPING = { 61 'int': int, 62 'long': int if PY3 else long, 63 'float': float, 64 'str': str, 65 'bool': bool, 66 'date': date, 67 'datetime': datetime, 68 'object': object, 69 } 70 71 OAUTH_TYPES = (OAuthToken.__name__, OAuthUserInfo.__name__, Account.__name__, Organization.__name__, Link.__name__) 72 73 def __init__(self, host=None, header_name=None, header_value=None, cookie=None, oauth_host_name=None, base_path=None): 74 """ 75 Constructor of the class. 76 """ 77 78 config = Configuration() 79 self.rest_client = RESTClientObject(configuration=config) 80 self.default_headers = {'X-DocuSign-SDK': 'Python'} 81 if header_name is not None: 82 self.default_headers[header_name] = header_value 83 if host is None: 84 self.host = config.host 85 elif host == "": 86 raise ArgumentException("basePath cannot be empty") 87 else: 88 self.host = host 89 90 self.cookie = cookie 91 self.base_path = base_path 92 self.set_oauth_host_name(oauth_host_name) 93 94 # Set default User-Agent. 95 self.user_agent = config.user_agent 96 97 @property 98 def user_agent(self): 99 """ 100 Gets user agent. 101 """ 102 return self.default_headers['User-Agent'] 103 104 @user_agent.setter 105 def user_agent(self, value): 106 """ 107 Sets user agent. 108 """ 109 self.default_headers['User-Agent'] = value 110 111 def set_default_header(self, header_name, header_value): 112 self.default_headers[header_name] = header_value 113 114 def __call_api(self, resource_path, method, 115 path_params=None, query_params=None, header_params=None, 116 body=None, post_params=None, files=None, 117 response_type=None, auth_settings=None, callback=None, 118 _return_http_data_only=None, collection_formats=None, _preload_content=True, 119 _request_timeout=None): 120 """ 121 :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without 122 reading/decoding response data. Default is True. 123 :return: 124 """ 125 126 # header parameters 127 header_params = header_params or {} 128 header_params.update(self.default_headers) 129 if self.cookie: 130 header_params['Cookie'] = self.cookie 131 if header_params: 132 header_params = self.sanitize_for_serialization(header_params) 133 header_params = dict(self.parameters_to_tuples(header_params, 134 collection_formats)) 135 136 # path parameters 137 if path_params: 138 path_params = self.sanitize_for_serialization(path_params) 139 path_params = self.parameters_to_tuples(path_params, 140 collection_formats) 141 for k, v in path_params: 142 resource_path = resource_path.replace( 143 '{%s}' % k, quote(str(v), safe="")) 144 145 # query parameters 146 if query_params: 147 query_params = self.sanitize_for_serialization(query_params) 148 query_params = self.parameters_to_tuples(query_params, 149 collection_formats) 150 151 # post parameters 152 if post_params or files: 153 post_params = self.prepare_post_parameters(post_params, files) 154 post_params = self.sanitize_for_serialization(post_params) 155 post_params = self.parameters_to_tuples(post_params, 156 collection_formats) 157 158 # auth setting 159 self.update_params_for_auth(header_params, query_params, auth_settings) 160 161 # body 162 if body: 163 body = self.sanitize_for_serialization(body) 164 165 # request url 166 url = self.host + resource_path 167 168 # perform request and return response 169 response_data = self.request(method, url, 170 query_params=query_params, 171 headers=header_params, 172 post_params=post_params, body=body, 173 _preload_content=_preload_content, 174 _request_timeout=_request_timeout) 175 176 self.last_response = response_data 177 178 return_data = response_data 179 if _preload_content: 180 r = RESTResponse(response_data) 181 182 # deserialize response data 183 if response_type: 184 # In the python 3, the response.data is bytes. 185 # we need to decode it to string. 186 if PY3 and response_type != "file": 187 try: 188 r.data = r.data.decode('utf8', 'replace') 189 except (UnicodeDecodeError, AttributeError): 190 pass 191 192 if response_type == "file": 193 return_data = r.data 194 else: 195 return_data = self.deserialize(r, response_type) 196 else: 197 return_data = None 198 199 if callback: 200 if _return_http_data_only: 201 callback(return_data) 202 else: 203 callback((return_data, response_data.status, response_data.getheaders())) 204 elif _return_http_data_only: 205 return (return_data) 206 else: 207 return (return_data, response_data.status, response_data.getheaders()) 208 209 def sanitize_for_serialization(self, obj): 210 """ 211 Builds a JSON POST object. 212 213 If obj is None, return None. 214 If obj is str, int, long, float, bool, return directly. 215 If obj is datetime.datetime, datetime.date 216 convert to string in iso8601 format. 217 If obj is list, sanitize each element in the list. 218 If obj is dict, return the dict. 219 If obj is swagger model, return the properties dict. 220 221 :param obj: The data to serialize. 222 :return: The serialized form of data. 223 """ 224 if obj is None: 225 return None 226 elif isinstance(obj, self.PRIMITIVE_TYPES): 227 return obj 228 elif isinstance(obj, list): 229 return [self.sanitize_for_serialization(sub_obj) 230 for sub_obj in obj] 231 elif isinstance(obj, tuple): 232 return tuple(self.sanitize_for_serialization(sub_obj) 233 for sub_obj in obj) 234 elif isinstance(obj, (datetime, date)): 235 return obj.isoformat() 236 237 if isinstance(obj, dict): 238 obj_dict = obj 239 else: 240 # Convert model obj to dict except 241 # attributes `swagger_types`, `attribute_map` 242 # and attributes which value is not None. 243 # Convert attribute name to json key in 244 # model definition for request. 245 obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) 246 for attr, _ in iteritems(obj.swagger_types) 247 if getattr(obj, attr) is not None} 248 249 return {key: self.sanitize_for_serialization(val) 250 for key, val in iteritems(obj_dict)} 251 252 def deserialize(self, response, response_type): 253 """ 254 Deserializes response into an object. 255 256 :param response: RESTResponse object to be deserialized. 257 :param response_type: class literal for 258 deserialized object, or string of class name. 259 260 :return: deserialized object. 261 """ 262 # handle file type response 263 if response_type == "file": 264 return response.data 265 266 # fetch data from response object 267 try: 268 data = json.loads(response.data) 269 except ValueError: 270 data = response.data 271 272 return self.__deserialize(data, response_type) 273 274 def __deserialize(self, data, klass): 275 """ 276 Deserializes dict, list, str into an object. 277 278 :param data: dict, list or str. 279 :param klass: class literal, or string of class name. 280 281 :return: object. 282 """ 283 if data is None: 284 return None 285 286 if type(klass) == str: 287 if klass.startswith('list['): 288 sub_kls = re.match(r'list\[(.*)\]', klass).group(1) 289 return [self.__deserialize(sub_data, sub_kls) 290 for sub_data in data] 291 292 if klass.startswith('dict('): 293 sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2) 294 return {k: self.__deserialize(v, sub_kls) 295 for k, v in iteritems(data)} 296 297 # convert str to class 298 if klass in self.NATIVE_TYPES_MAPPING: 299 klass = self.NATIVE_TYPES_MAPPING[klass] 300 else: 301 if klass in self.OAUTH_TYPES: 302 klass = getattr(client, klass) 303 else: 304 klass = getattr(models, klass) 305 306 if klass in self.PRIMITIVE_TYPES: 307 return self.__deserialize_primitive(data, klass) 308 elif klass == object: 309 return self.__deserialize_object(data) 310 elif klass == date: 311 return self.__deserialize_date(data) 312 elif klass == datetime: 313 return self.__deserialize_datatime(data) 314 else: 315 return self.__deserialize_model(data, klass) 316 317 def call_api(self, resource_path, method, 318 path_params=None, query_params=None, header_params=None, 319 body=None, post_params=None, files=None, 320 response_type=None, auth_settings=None, callback=None, 321 _return_http_data_only=None, collection_formats=None, _preload_content=True, 322 _request_timeout=None): 323 """ 324 Makes the HTTP request (synchronous) and return the deserialized data. 325 To make an async request, define a function for callback. 326 327 :param resource_path: Path to method endpoint. 328 :param method: Method to call. 329 :param path_params: Path parameters in the url. 330 :param query_params: Query parameters in the url. 331 :param header_params: Header parameters to be 332 placed in the request header. 333 :param body: Request body. 334 :param post_params dict: Request post form parameters, 335 for `application/x-www-form-urlencoded`, `multipart/form-data`. 336 :param auth_settings list: Auth Settings names for the request. 337 :param response: Response data type. 338 :param files dict: key -> filename, value -> filepath, 339 for `multipart/form-data`. 340 :param callback function: Callback function for asynchronous request. 341 If provide this parameter, 342 the request will be called asynchronously. 343 :param _return_http_data_only: response data without head status code and headers 344 :param collection_formats: dict of collection formats for path, query, 345 header, and post parameters. 346 :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without 347 reading/decoding response data. Default is True. 348 :param _request_timeout: timeout setting for this request. If one number provided, it will be total request 349 timeout. It can also be a pair (tuple) of (connection, read) timeouts. 350 :return: 351 If provide parameter callback, 352 the request will be called asynchronously. 353 The method will return the request thread. 354 If parameter callback is None, 355 then the method will return the response directly. 356 """ 357 if callback is None: 358 return self.__call_api(resource_path, method, 359 path_params, query_params, header_params, 360 body, post_params, files, 361 response_type, auth_settings, callback, 362 _return_http_data_only, collection_formats, _preload_content, _request_timeout) 363 else: 364 thread = threading.Thread(target=self.__call_api, 365 args=(resource_path, method, 366 path_params, query_params, 367 header_params, body, 368 post_params, files, 369 response_type, auth_settings, 370 callback, _return_http_data_only, 371 collection_formats, _preload_content, _request_timeout)) 372 thread.start() 373 return thread 374 375 def request(self, method, url, query_params=None, headers=None, 376 post_params=None, body=None, _preload_content=True, _request_timeout=None): 377 """ 378 Makes the HTTP request using RESTClient. 379 """ 380 if method == "GET": 381 return self.rest_client.GET(url, 382 query_params=query_params, 383 _preload_content=_preload_content, 384 _request_timeout=_request_timeout, 385 headers=headers) 386 elif method == "HEAD": 387 return self.rest_client.HEAD(url, 388 query_params=query_params, 389 _preload_content=_preload_content, 390 _request_timeout=_request_timeout, 391 headers=headers) 392 elif method == "OPTIONS": 393 return self.rest_client.OPTIONS(url, 394 query_params=query_params, 395 headers=headers, 396 post_params=post_params, 397 _preload_content=_preload_content, 398 _request_timeout=_request_timeout, 399 body=body) 400 elif method == "POST": 401 return self.rest_client.POST(url, 402 query_params=query_params, 403 headers=headers, 404 post_params=post_params, 405 _preload_content=_preload_content, 406 _request_timeout=_request_timeout, 407 body=body) 408 elif method == "PUT": 409 return self.rest_client.PUT(url, 410 query_params=query_params, 411 headers=headers, 412 post_params=post_params, 413 _preload_content=_preload_content, 414 _request_timeout=_request_timeout, 415 body=body) 416 elif method == "PATCH": 417 return self.rest_client.PATCH(url, 418 query_params=query_params, 419 headers=headers, 420 post_params=post_params, 421 _preload_content=_preload_content, 422 _request_timeout=_request_timeout, 423 body=body) 424 elif method == "DELETE": 425 return self.rest_client.DELETE(url, 426 query_params=query_params, 427 headers=headers, 428 _preload_content=_preload_content, 429 _request_timeout=_request_timeout, 430 body=body) 431 else: 432 raise ValueError( 433 "http method must be `GET`, `HEAD`, `OPTIONS`," 434 " `POST`, `PATCH`, `PUT` or `DELETE`." 435 ) 436 437 def parameters_to_tuples(self, params, collection_formats): 438 """ 439 Get parameters as list of tuples, formatting collections. 440 441 :param params: Parameters as dict or list of two-tuples 442 :param dict collection_formats: Parameter collection formats 443 :return: Parameters as list of tuples, collections formatted 444 """ 445 new_params = [] 446 if collection_formats is None: 447 collection_formats = {} 448 for k, v in iteritems(params) if isinstance(params, dict) else params: 449 if k in collection_formats: 450 collection_format = collection_formats[k] 451 if collection_format == 'multi': 452 new_params.extend((k, value) for value in v) 453 else: 454 if collection_format == 'ssv': 455 delimiter = ' ' 456 elif collection_format == 'tsv': 457 delimiter = '\t' 458 elif collection_format == 'pipes': 459 delimiter = '|' 460 else: # csv is the default 461 delimiter = ',' 462 new_params.append( 463 (k, delimiter.join(str(value) for value in v))) 464 else: 465 new_params.append((k, v)) 466 return new_params 467 468 def prepare_post_parameters(self, post_params=None, files=None): 469 """ 470 Builds form parameters. 471 472 :param post_params: Normal form parameters. 473 :param files: File parameters. 474 :return: Form parameters with files. 475 """ 476 params = [] 477 478 if post_params: 479 params = post_params 480 481 if files: 482 for k, v in iteritems(files): 483 if not v: 484 continue 485 file_names = v if type(v) is list else [v] 486 for n in file_names: 487 with open(n, 'rb') as f: 488 filename = os.path.basename(f.name) 489 filedata = f.read() 490 mimetype = mimetypes.\ 491 guess_type(filename)[0] or 'application/octet-stream' 492 params.append(tuple([k, tuple([filename, filedata, mimetype])])) 493 494 return params 495 496 def select_header_accept(self, accepts): 497 """ 498 Returns `Accept` based on an array of accepts provided. 499 500 :param accepts: List of headers. 501 :return: Accept (e.g. application/json). 502 """ 503 if not accepts: 504 return 505 506 accepts = [x.lower() for x in accepts] 507 508 if 'application/json' in accepts: 509 return 'application/json' 510 else: 511 return ', '.join(accepts) 512 513 def select_header_content_type(self, content_types): 514 """ 515 Returns `Content-Type` based on an array of content_types provided. 516 517 :param content_types: List of content-types. 518 :return: Content-Type (e.g. application/json). 519 """ 520 if not content_types: 521 return 'application/json' 522 523 content_types = [x.lower() for x in content_types] 524 525 if 'application/json' in content_types or '*/*' in content_types: 526 return 'application/json' 527 else: 528 return content_types[0] 529 530 def update_params_for_auth(self, headers, querys, auth_settings): 531 """ 532 Updates header and query params based on authentication setting. 533 534 :param headers: Header parameters dict to be updated. 535 :param querys: Query parameters tuple list to be updated. 536 :param auth_settings: Authentication setting identifiers list. 537 """ 538 config = Configuration() 539 540 if not auth_settings: 541 return 542 543 for auth in auth_settings: 544 auth_setting = config.auth_settings().get(auth) 545 if auth_setting: 546 if not auth_setting['value']: 547 continue 548 elif auth_setting['in'] == 'header': 549 headers[auth_setting['key']] = auth_setting['value'] 550 elif auth_setting['in'] == 'query': 551 querys.append((auth_setting['key'], auth_setting['value'])) 552 else: 553 raise ValueError( 554 'Authentication token must be in `query` or `header`' 555 ) 556 557 def __deserialize_primitive(self, data, klass): 558 """ 559 Deserializes string to primitive type. 560 561 :param data: str. 562 :param klass: class literal. 563 564 :return: int, long, float, str, bool. 565 """ 566 try: 567 return klass(data) 568 except UnicodeEncodeError: 569 return unicode(data) 570 except TypeError: 571 return data 572 573 def __deserialize_object(self, value): 574 """ 575 Return a original value. 576 577 :return: object. 578 """ 579 return value 580 581 def __deserialize_date(self, string): 582 """ 583 Deserializes string to date. 584 585 :param string: str. 586 :return: date. 587 """ 588 try: 589 from dateutil.parser import parse 590 return parse(string).date() 591 except ImportError: 592 return string 593 except ValueError: 594 raise ApiException( 595 status=0, 596 reason="Failed to parse `{0}` into a date object".format(string) 597 ) 598 599 def __deserialize_datatime(self, string): 600 """ 601 Deserializes string to datetime. 602 603 The string should be in iso8601 datetime format. 604 605 :param string: str. 606 :return: datetime. 607 """ 608 try: 609 from dateutil.parser import parse 610 return parse(string) 611 except ImportError: 612 return string 613 except ValueError: 614 raise ApiException( 615 status=0, 616 reason=( 617 "Failed to parse `{0}` into a datetime object" 618 .format(string) 619 ) 620 ) 621 622 def __deserialize_model(self, data, klass): 623 """ 624 Deserializes list or dict to model. 625 626 :param data: dict, list. 627 :param klass: class literal. 628 :return: model object. 629 """ 630 instance = klass() 631 632 if not instance.swagger_types: 633 return data 634 635 for attr, attr_type in iteritems(instance.swagger_types): 636 if data is not None \ 637 and instance.attribute_map[attr] in data \ 638 and isinstance(data, (list, dict)): 639 value = data[instance.attribute_map[attr]] 640 setattr(instance, attr, self.__deserialize(value, attr_type)) 641 642 return instance 643 644 def request_jwt_user_token(self, client_id, user_id, oauth_host_name, private_key_bytes, expires_in, 645 scopes=(OAuth.SCOPE_SIGNATURE,)): 646 """ 647 Request JWT User Token 648 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 649 :param user_id: Docusign user Id to be impersonated 650 :param oauth_host_name: Docusign OAuth host name 651 :param private_key_bytes: the byte contents of the RSA private key 652 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 653 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 654 advanced scope. 655 :return: OAuthToken object 656 """ 657 if not private_key_bytes: 658 raise ArgumentException("Private key not supplied or is invalid!") 659 if not user_id: 660 raise ArgumentException("User Id not supplied or is invalid!") 661 if not oauth_host_name: 662 raise ArgumentException("oAuthBasePath cannot be empty") 663 664 now = math.floor(time()) 665 later = now + (expires_in * 1) 666 claim = {"iss": client_id, "sub": user_id, "aud": oauth_host_name, "iat": now, "exp": later, 667 "scope": " ".join(scopes)} 668 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 669 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 670 headers=self.sanitize_for_serialization( 671 {"Content-Type": "application/x-www-form-urlencoded"}), 672 post_params=self.sanitize_for_serialization( 673 {"assertion": token, "grant_type": OAuth.GRANT_TYPE_JWT})) 674 675 response_data = json.loads(response.data) 676 677 if 'token_type' in response_data and 'access_token' in response_data: 678 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 679 else: 680 raise ApiException(status=response.status, 681 reason="Error while requesting server, received a non successful HTTP code {}" 682 " with response Body: {}".format(response.status, response.data) 683 ) 684 685 return self.deserialize(response=response, response_type=OAuthToken) 686 687 def request_jwt_application_token(self, client_id, oauth_host_name, private_key_bytes, expires_in, 688 scopes=(OAuth.SCOPE_SIGNATURE,)): 689 """ 690 Request JWT Application Token 691 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 692 :param oauth_host_name: Docusign OAuth host name 693 :param private_key_bytes: the byte contents of the RSA private key 694 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 695 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 696 advanced scope. 697 :return: OAuthToken object 698 """ 699 700 if not private_key_bytes: 701 raise ArgumentException("Private key not supplied or is invalid!") 702 if not oauth_host_name: 703 raise ArgumentException("oAuthBasePath cannot be empty") 704 705 now = math.floor(time()) 706 later = now + (expires_in * 1) 707 claim = {"iss": client_id, "aud": oauth_host_name, "iat": now, "exp": later, 708 "scope": " ".join(scopes)} 709 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 710 711 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 712 headers=self.sanitize_for_serialization( 713 {"Content-Type": "application/x-www-form-urlencoded"}), 714 post_params=self.sanitize_for_serialization( 715 {"assertion": token, "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"})) 716 response_data = json.loads(response.data) 717 718 if 'token_type' in response_data and 'access_token' in response_data: 719 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 720 else: 721 ApiException(status=response.status, 722 reason="Error while requesting server, received a non successful HTTP code {}" 723 " with response Body: {}".format(response.status, response.data) 724 ) 725 726 return self.deserialize(response=response, response_type=OAuthToken) 727 728 def get_user_info(self, access_token): 729 """ 730 Get User Info method takes the accessToken to retrieve User Account Data. 731 :param access_token: 732 :return: The User Info model. 733 """ 734 if not access_token: 735 raise ArgumentException("Cannot find a valid access token." 736 " Make sure OAuth is configured before you try again.") 737 if not self.oauth_host_name: 738 raise ArgumentException("oAuthBasePath cannot be empty") 739 740 resource_path = '/oauth/userinfo' 741 headers = {"Authorization": "Bearer " + access_token} 742 743 response = self.request("GET", "https://" + self.oauth_host_name + resource_path, headers=headers) 744 return self.deserialize(response=response, response_type=OAuthUserInfo) 745 746 def generate_access_token(self, client_id, client_secret, code): 747 """ 748 GenerateAccessToken will exchange the authorization code for an access token and refresh tokens. 749 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 750 :param client_secret: The secret key you generated when you set up the integration in Docusign Admin console. 751 :param code: The authorization code 752 :return: OAuthToken object 753 """ 754 if not client_id or not client_secret or not code: 755 raise ArgumentException 756 url = "https://{0}/oauth/token".format(self.oauth_host_name) 757 integrator_and_secret_key = b"Basic " + base64.b64encode(str.encode("{}:{}".format(client_id, client_secret))) 758 headers = { 759 "Authorization": integrator_and_secret_key.decode("utf-8"), 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 post_params = self.sanitize_for_serialization({ 763 "grant_type": "authorization_code", 764 "code": code 765 }) 766 response = self.rest_client.POST(url, headers=headers, post_params=post_params) 767 768 return self.deserialize(response=response, response_type=OAuthToken) 769 770 def set_base_path(self, base_path): 771 """ 772 :param base_path: 773 :return: 774 """ 775 self.base_path = base_path 776 777 def set_oauth_host_name(self, oauth_host_name=None): 778 """ 779 :param oauth_host_name: 780 :return: 781 """ 782 if oauth_host_name: 783 self.oauth_host_name = oauth_host_name 784 return 785 786 # Derive OAuth Base Path if not given 787 if self.base_path is None or self.base_path.startswith("https://demo") or self.base_path.startswith("http://demo") or self.base_path.startswith("https://apps-d") or self.base_path.startswith("http://apps-d"): 788 self.oauth_host_name = OAuth.DEMO_OAUTH_BASE_PATH 789 elif self.base_path.startswith("https://stage") or self.base_path.startswith("http://stage") or self.base_path.startswith("https://apps-s") or self.base_path.startswith("http://apps-s"): 790 self.oauth_host_name = OAuth.STAGE_OAUTH_BASE_PATH 791 else: 792 self.oauth_host_name = OAuth.PRODUCTION_OAUTH_BASE_PATH 793 794 def set_access_token(self, token_obj): 795 """ 796 797 :param token_obj: 798 :return: 799 """ 800 self.default_headers['Authorization'] = token_obj.access_token 801 802 def get_authorization_uri(self, client_id, scopes, redirect_uri, response_type, state=None): 803 """ 804 Helper method to configure the OAuth accessCode/implicit flow parameters 805 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 806 :param scopes: The list of requested scopes. Client applications may be scoped to a limited set of system access. 807 :param redirect_uri: This determines where to deliver the response containing the authorization code 808 :param response_type: Determines the response type of the authorization request, NOTE: these response types are 809 mutually exclusive for a client application. A public/native client application may only request a response type 810 of "token". A private/trusted client application may only request a response type of "code". 811 :param state: Allows for arbitrary state that may be useful to your application. The value in this parameter 812 will be round-tripped along with the response so you can make sure it didn't change. 813 :return: string 814 """ 815 if not self.oauth_host_name: 816 self.oauth_host_name = self.get_oauth_host_name() 817 scopes = " ".join(scopes) if scopes else "" 818 uri = "https://{}/oauth/auth?response_type={}&scope={}&client_id={}&redirect_uri={}" 819 if state: 820 uri += "&state={}" 821 return uri.format(self.oauth_host_name, response_type, quote(scopes), client_id, redirect_uri, state) 822 823 def get_oauth_host_name(self): 824 """ 825 :return: string 826 """ 827 if not self.oauth_host_name: 828 self.set_oauth_host_name() 829 830 return self.oauth_host_name
Generic API client for Swagger client library builds.
Swagger generic API client. This client handles the client- server communication, and is invariant across implementations. Specifics of the methods and models for each application are generated from the Swagger templates.
NOTE: This class is auto generated by the swagger code generator program. Ref: https://github.com/swagger-api/swagger-codegen Do not edit the class manually.
Parameters
- host: The base path for the server to call.
- header_name: a header to pass when making calls to the API.
- header_value: a header value to pass when making calls to the API.
73 def __init__(self, host=None, header_name=None, header_value=None, cookie=None, oauth_host_name=None, base_path=None): 74 """ 75 Constructor of the class. 76 """ 77 78 config = Configuration() 79 self.rest_client = RESTClientObject(configuration=config) 80 self.default_headers = {'X-DocuSign-SDK': 'Python'} 81 if header_name is not None: 82 self.default_headers[header_name] = header_value 83 if host is None: 84 self.host = config.host 85 elif host == "": 86 raise ArgumentException("basePath cannot be empty") 87 else: 88 self.host = host 89 90 self.cookie = cookie 91 self.base_path = base_path 92 self.set_oauth_host_name(oauth_host_name) 93 94 # Set default User-Agent. 95 self.user_agent = config.user_agent
Constructor of the class.
209 def sanitize_for_serialization(self, obj): 210 """ 211 Builds a JSON POST object. 212 213 If obj is None, return None. 214 If obj is str, int, long, float, bool, return directly. 215 If obj is datetime.datetime, datetime.date 216 convert to string in iso8601 format. 217 If obj is list, sanitize each element in the list. 218 If obj is dict, return the dict. 219 If obj is swagger model, return the properties dict. 220 221 :param obj: The data to serialize. 222 :return: The serialized form of data. 223 """ 224 if obj is None: 225 return None 226 elif isinstance(obj, self.PRIMITIVE_TYPES): 227 return obj 228 elif isinstance(obj, list): 229 return [self.sanitize_for_serialization(sub_obj) 230 for sub_obj in obj] 231 elif isinstance(obj, tuple): 232 return tuple(self.sanitize_for_serialization(sub_obj) 233 for sub_obj in obj) 234 elif isinstance(obj, (datetime, date)): 235 return obj.isoformat() 236 237 if isinstance(obj, dict): 238 obj_dict = obj 239 else: 240 # Convert model obj to dict except 241 # attributes `swagger_types`, `attribute_map` 242 # and attributes which value is not None. 243 # Convert attribute name to json key in 244 # model definition for request. 245 obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) 246 for attr, _ in iteritems(obj.swagger_types) 247 if getattr(obj, attr) is not None} 248 249 return {key: self.sanitize_for_serialization(val) 250 for key, val in iteritems(obj_dict)}
Builds a JSON POST object.
If obj is None, return None. If obj is str, int, long, float, bool, return directly. If obj is datetime.datetime, datetime.date convert to string in iso8601 format. If obj is list, sanitize each element in the list. If obj is dict, return the dict. If obj is swagger model, return the properties dict.
Parameters
- obj: The data to serialize.
Returns
The serialized form of data.
252 def deserialize(self, response, response_type): 253 """ 254 Deserializes response into an object. 255 256 :param response: RESTResponse object to be deserialized. 257 :param response_type: class literal for 258 deserialized object, or string of class name. 259 260 :return: deserialized object. 261 """ 262 # handle file type response 263 if response_type == "file": 264 return response.data 265 266 # fetch data from response object 267 try: 268 data = json.loads(response.data) 269 except ValueError: 270 data = response.data 271 272 return self.__deserialize(data, response_type)
Deserializes response into an object.
Parameters
- response: RESTResponse object to be deserialized.
- response_type: class literal for deserialized object, or string of class name.
Returns
deserialized object.
317 def call_api(self, resource_path, method, 318 path_params=None, query_params=None, header_params=None, 319 body=None, post_params=None, files=None, 320 response_type=None, auth_settings=None, callback=None, 321 _return_http_data_only=None, collection_formats=None, _preload_content=True, 322 _request_timeout=None): 323 """ 324 Makes the HTTP request (synchronous) and return the deserialized data. 325 To make an async request, define a function for callback. 326 327 :param resource_path: Path to method endpoint. 328 :param method: Method to call. 329 :param path_params: Path parameters in the url. 330 :param query_params: Query parameters in the url. 331 :param header_params: Header parameters to be 332 placed in the request header. 333 :param body: Request body. 334 :param post_params dict: Request post form parameters, 335 for `application/x-www-form-urlencoded`, `multipart/form-data`. 336 :param auth_settings list: Auth Settings names for the request. 337 :param response: Response data type. 338 :param files dict: key -> filename, value -> filepath, 339 for `multipart/form-data`. 340 :param callback function: Callback function for asynchronous request. 341 If provide this parameter, 342 the request will be called asynchronously. 343 :param _return_http_data_only: response data without head status code and headers 344 :param collection_formats: dict of collection formats for path, query, 345 header, and post parameters. 346 :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without 347 reading/decoding response data. Default is True. 348 :param _request_timeout: timeout setting for this request. If one number provided, it will be total request 349 timeout. It can also be a pair (tuple) of (connection, read) timeouts. 350 :return: 351 If provide parameter callback, 352 the request will be called asynchronously. 353 The method will return the request thread. 354 If parameter callback is None, 355 then the method will return the response directly. 356 """ 357 if callback is None: 358 return self.__call_api(resource_path, method, 359 path_params, query_params, header_params, 360 body, post_params, files, 361 response_type, auth_settings, callback, 362 _return_http_data_only, collection_formats, _preload_content, _request_timeout) 363 else: 364 thread = threading.Thread(target=self.__call_api, 365 args=(resource_path, method, 366 path_params, query_params, 367 header_params, body, 368 post_params, files, 369 response_type, auth_settings, 370 callback, _return_http_data_only, 371 collection_formats, _preload_content, _request_timeout)) 372 thread.start() 373 return thread
Makes the HTTP request (synchronous) and return the deserialized data. To make an async request, define a function for callback.
Parameters
- resource_path: Path to method endpoint.
- method: Method to call.
- path_params: Path parameters in the url.
- query_params: Query parameters in the url.
- header_params: Header parameters to be placed in the request header.
- body: Request body.
- post_params dict: Request post form parameters,
for
application/x-www-form-urlencoded
,multipart/form-data
. - auth_settings list: Auth Settings names for the request.
- response: Response data type.
- files dict: key -> filename, value -> filepath,
for
multipart/form-data
. - callback function: Callback function for asynchronous request. If provide this parameter, the request will be called asynchronously.
- _return_http_data_only: response data without head status code and headers
- collection_formats: dict of collection formats for path, query, header, and post parameters.
- _preload_content: if False, the urllib3.HTTPResponse object will be returned without reading/decoding response data. Default is True.
- _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of (connection, read) timeouts.
Returns
If provide parameter callback, the request will be called asynchronously. The method will return the request thread. If parameter callback is None, then the method will return the response directly.
375 def request(self, method, url, query_params=None, headers=None, 376 post_params=None, body=None, _preload_content=True, _request_timeout=None): 377 """ 378 Makes the HTTP request using RESTClient. 379 """ 380 if method == "GET": 381 return self.rest_client.GET(url, 382 query_params=query_params, 383 _preload_content=_preload_content, 384 _request_timeout=_request_timeout, 385 headers=headers) 386 elif method == "HEAD": 387 return self.rest_client.HEAD(url, 388 query_params=query_params, 389 _preload_content=_preload_content, 390 _request_timeout=_request_timeout, 391 headers=headers) 392 elif method == "OPTIONS": 393 return self.rest_client.OPTIONS(url, 394 query_params=query_params, 395 headers=headers, 396 post_params=post_params, 397 _preload_content=_preload_content, 398 _request_timeout=_request_timeout, 399 body=body) 400 elif method == "POST": 401 return self.rest_client.POST(url, 402 query_params=query_params, 403 headers=headers, 404 post_params=post_params, 405 _preload_content=_preload_content, 406 _request_timeout=_request_timeout, 407 body=body) 408 elif method == "PUT": 409 return self.rest_client.PUT(url, 410 query_params=query_params, 411 headers=headers, 412 post_params=post_params, 413 _preload_content=_preload_content, 414 _request_timeout=_request_timeout, 415 body=body) 416 elif method == "PATCH": 417 return self.rest_client.PATCH(url, 418 query_params=query_params, 419 headers=headers, 420 post_params=post_params, 421 _preload_content=_preload_content, 422 _request_timeout=_request_timeout, 423 body=body) 424 elif method == "DELETE": 425 return self.rest_client.DELETE(url, 426 query_params=query_params, 427 headers=headers, 428 _preload_content=_preload_content, 429 _request_timeout=_request_timeout, 430 body=body) 431 else: 432 raise ValueError( 433 "http method must be `GET`, `HEAD`, `OPTIONS`," 434 " `POST`, `PATCH`, `PUT` or `DELETE`." 435 )
Makes the HTTP request using RESTClient.
437 def parameters_to_tuples(self, params, collection_formats): 438 """ 439 Get parameters as list of tuples, formatting collections. 440 441 :param params: Parameters as dict or list of two-tuples 442 :param dict collection_formats: Parameter collection formats 443 :return: Parameters as list of tuples, collections formatted 444 """ 445 new_params = [] 446 if collection_formats is None: 447 collection_formats = {} 448 for k, v in iteritems(params) if isinstance(params, dict) else params: 449 if k in collection_formats: 450 collection_format = collection_formats[k] 451 if collection_format == 'multi': 452 new_params.extend((k, value) for value in v) 453 else: 454 if collection_format == 'ssv': 455 delimiter = ' ' 456 elif collection_format == 'tsv': 457 delimiter = '\t' 458 elif collection_format == 'pipes': 459 delimiter = '|' 460 else: # csv is the default 461 delimiter = ',' 462 new_params.append( 463 (k, delimiter.join(str(value) for value in v))) 464 else: 465 new_params.append((k, v)) 466 return new_params
Get parameters as list of tuples, formatting collections.
Parameters
- params: Parameters as dict or list of two-tuples
- dict collection_formats: Parameter collection formats
Returns
Parameters as list of tuples, collections formatted
468 def prepare_post_parameters(self, post_params=None, files=None): 469 """ 470 Builds form parameters. 471 472 :param post_params: Normal form parameters. 473 :param files: File parameters. 474 :return: Form parameters with files. 475 """ 476 params = [] 477 478 if post_params: 479 params = post_params 480 481 if files: 482 for k, v in iteritems(files): 483 if not v: 484 continue 485 file_names = v if type(v) is list else [v] 486 for n in file_names: 487 with open(n, 'rb') as f: 488 filename = os.path.basename(f.name) 489 filedata = f.read() 490 mimetype = mimetypes.\ 491 guess_type(filename)[0] or 'application/octet-stream' 492 params.append(tuple([k, tuple([filename, filedata, mimetype])])) 493 494 return params
Builds form parameters.
Parameters
- post_params: Normal form parameters.
- files: File parameters.
Returns
Form parameters with files.
496 def select_header_accept(self, accepts): 497 """ 498 Returns `Accept` based on an array of accepts provided. 499 500 :param accepts: List of headers. 501 :return: Accept (e.g. application/json). 502 """ 503 if not accepts: 504 return 505 506 accepts = [x.lower() for x in accepts] 507 508 if 'application/json' in accepts: 509 return 'application/json' 510 else: 511 return ', '.join(accepts)
Returns Accept
based on an array of accepts provided.
Parameters
- accepts: List of headers.
Returns
Accept (e.g. application/json).
513 def select_header_content_type(self, content_types): 514 """ 515 Returns `Content-Type` based on an array of content_types provided. 516 517 :param content_types: List of content-types. 518 :return: Content-Type (e.g. application/json). 519 """ 520 if not content_types: 521 return 'application/json' 522 523 content_types = [x.lower() for x in content_types] 524 525 if 'application/json' in content_types or '*/*' in content_types: 526 return 'application/json' 527 else: 528 return content_types[0]
Returns Content-Type
based on an array of content_types provided.
Parameters
- content_types: List of content-types.
Returns
Content-Type (e.g. application/json).
530 def update_params_for_auth(self, headers, querys, auth_settings): 531 """ 532 Updates header and query params based on authentication setting. 533 534 :param headers: Header parameters dict to be updated. 535 :param querys: Query parameters tuple list to be updated. 536 :param auth_settings: Authentication setting identifiers list. 537 """ 538 config = Configuration() 539 540 if not auth_settings: 541 return 542 543 for auth in auth_settings: 544 auth_setting = config.auth_settings().get(auth) 545 if auth_setting: 546 if not auth_setting['value']: 547 continue 548 elif auth_setting['in'] == 'header': 549 headers[auth_setting['key']] = auth_setting['value'] 550 elif auth_setting['in'] == 'query': 551 querys.append((auth_setting['key'], auth_setting['value'])) 552 else: 553 raise ValueError( 554 'Authentication token must be in `query` or `header`' 555 )
Updates header and query params based on authentication setting.
Parameters
- headers: Header parameters dict to be updated.
- querys: Query parameters tuple list to be updated.
- auth_settings: Authentication setting identifiers list.
644 def request_jwt_user_token(self, client_id, user_id, oauth_host_name, private_key_bytes, expires_in, 645 scopes=(OAuth.SCOPE_SIGNATURE,)): 646 """ 647 Request JWT User Token 648 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 649 :param user_id: Docusign user Id to be impersonated 650 :param oauth_host_name: Docusign OAuth host name 651 :param private_key_bytes: the byte contents of the RSA private key 652 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 653 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 654 advanced scope. 655 :return: OAuthToken object 656 """ 657 if not private_key_bytes: 658 raise ArgumentException("Private key not supplied or is invalid!") 659 if not user_id: 660 raise ArgumentException("User Id not supplied or is invalid!") 661 if not oauth_host_name: 662 raise ArgumentException("oAuthBasePath cannot be empty") 663 664 now = math.floor(time()) 665 later = now + (expires_in * 1) 666 claim = {"iss": client_id, "sub": user_id, "aud": oauth_host_name, "iat": now, "exp": later, 667 "scope": " ".join(scopes)} 668 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 669 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 670 headers=self.sanitize_for_serialization( 671 {"Content-Type": "application/x-www-form-urlencoded"}), 672 post_params=self.sanitize_for_serialization( 673 {"assertion": token, "grant_type": OAuth.GRANT_TYPE_JWT})) 674 675 response_data = json.loads(response.data) 676 677 if 'token_type' in response_data and 'access_token' in response_data: 678 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 679 else: 680 raise ApiException(status=response.status, 681 reason="Error while requesting server, received a non successful HTTP code {}" 682 " with response Body: {}".format(response.status, response.data) 683 ) 684 685 return self.deserialize(response=response, response_type=OAuthToken)
Request JWT User Token
Parameters
- client_id: Docusign OAuth Client Id(AKA Integrator Key)
- user_id: Docusign user Id to be impersonated
- oauth_host_name: Docusign OAuth host name
- private_key_bytes: the byte contents of the RSA private key
- expires_in: number of seconds remaining before the JWT assertion is considered as invalid
- scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any advanced scope.
Returns
OAuthToken object
687 def request_jwt_application_token(self, client_id, oauth_host_name, private_key_bytes, expires_in, 688 scopes=(OAuth.SCOPE_SIGNATURE,)): 689 """ 690 Request JWT Application Token 691 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 692 :param oauth_host_name: Docusign OAuth host name 693 :param private_key_bytes: the byte contents of the RSA private key 694 :param expires_in: number of seconds remaining before the JWT assertion is considered as invalid 695 :param scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any 696 advanced scope. 697 :return: OAuthToken object 698 """ 699 700 if not private_key_bytes: 701 raise ArgumentException("Private key not supplied or is invalid!") 702 if not oauth_host_name: 703 raise ArgumentException("oAuthBasePath cannot be empty") 704 705 now = math.floor(time()) 706 later = now + (expires_in * 1) 707 claim = {"iss": client_id, "aud": oauth_host_name, "iat": now, "exp": later, 708 "scope": " ".join(scopes)} 709 token = jwt.encode(payload=claim, key=private_key_bytes, algorithm='RS256') 710 711 response = self.request("POST", "https://" + oauth_host_name + "/oauth/token", 712 headers=self.sanitize_for_serialization( 713 {"Content-Type": "application/x-www-form-urlencoded"}), 714 post_params=self.sanitize_for_serialization( 715 {"assertion": token, "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"})) 716 response_data = json.loads(response.data) 717 718 if 'token_type' in response_data and 'access_token' in response_data: 719 self.set_default_header("Authorization", response_data['token_type'] + " " + response_data['access_token']) 720 else: 721 ApiException(status=response.status, 722 reason="Error while requesting server, received a non successful HTTP code {}" 723 " with response Body: {}".format(response.status, response.data) 724 ) 725 726 return self.deserialize(response=response, response_type=OAuthToken)
Request JWT Application Token
Parameters
- client_id: Docusign OAuth Client Id(AKA Integrator Key)
- oauth_host_name: Docusign OAuth host name
- private_key_bytes: the byte contents of the RSA private key
- expires_in: number of seconds remaining before the JWT assertion is considered as invalid
- scopes: Optional. The list of requested scopes may include (but not limited to) You can also pass any advanced scope.
Returns
OAuthToken object
728 def get_user_info(self, access_token): 729 """ 730 Get User Info method takes the accessToken to retrieve User Account Data. 731 :param access_token: 732 :return: The User Info model. 733 """ 734 if not access_token: 735 raise ArgumentException("Cannot find a valid access token." 736 " Make sure OAuth is configured before you try again.") 737 if not self.oauth_host_name: 738 raise ArgumentException("oAuthBasePath cannot be empty") 739 740 resource_path = '/oauth/userinfo' 741 headers = {"Authorization": "Bearer " + access_token} 742 743 response = self.request("GET", "https://" + self.oauth_host_name + resource_path, headers=headers) 744 return self.deserialize(response=response, response_type=OAuthUserInfo)
Get User Info method takes the accessToken to retrieve User Account Data.
Parameters
- access_token:
Returns
The User Info model.
746 def generate_access_token(self, client_id, client_secret, code): 747 """ 748 GenerateAccessToken will exchange the authorization code for an access token and refresh tokens. 749 :param client_id: Docusign OAuth Client Id(AKA Integrator Key) 750 :param client_secret: The secret key you generated when you set up the integration in Docusign Admin console. 751 :param code: The authorization code 752 :return: OAuthToken object 753 """ 754 if not client_id or not client_secret or not code: 755 raise ArgumentException 756 url = "https://{0}/oauth/token".format(self.oauth_host_name) 757 integrator_and_secret_key = b"Basic " + base64.b64encode(str.encode("{}:{}".format(client_id, client_secret))) 758 headers = { 759 "Authorization": integrator_and_secret_key.decode("utf-8"), 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 post_params = self.sanitize_for_serialization({ 763 "grant_type": "authorization_code", 764 "code": code 765 }) 766 response = self.rest_client.POST(url, headers=headers, post_params=post_params) 767 768 return self.deserialize(response=response, response_type=OAuthToken)
GenerateAccessToken will exchange the authorization code for an access token and refresh tokens.
Parameters
- client_id: Docusign OAuth Client Id(AKA Integrator Key)
- client_secret: The secret key you generated when you set up the integration in Docusign Admin console.
- code: The authorization code
Returns
OAuthToken object
770 def set_base_path(self, base_path): 771 """ 772 :param base_path: 773 :return: 774 """ 775 self.base_path = base_path
Parameters
- base_path:
Returns
777 def set_oauth_host_name(self, oauth_host_name=None): 778 """ 779 :param oauth_host_name: 780 :return: 781 """ 782 if oauth_host_name: 783 self.oauth_host_name = oauth_host_name 784 return 785 786 # Derive OAuth Base Path if not given 787 if self.base_path is None or self.base_path.startswith("https://demo") or self.base_path.startswith("http://demo") or self.base_path.startswith("https://apps-d") or self.base_path.startswith("http://apps-d"): 788 self.oauth_host_name = OAuth.DEMO_OAUTH_BASE_PATH 789 elif self.base_path.startswith("https://stage") or self.base_path.startswith("http://stage") or self.base_path.startswith("https://apps-s") or self.base_path.startswith("http://apps-s"): 790 self.oauth_host_name = OAuth.STAGE_OAUTH_BASE_PATH 791 else: 792 self.oauth_host_name = OAuth.PRODUCTION_OAUTH_BASE_PATH
Parameters
- oauth_host_name: