pumpwood_communication.microservice_abc.base
Module with base classes for requests on Pumpwood Server.
25class PumpWoodMicroServiceBase: 26 """Base class for Pumpwood MicroService. 27 28 Enviroment variables can be used to set MicroService parameters: 29 - **PUMPWOOD_COMUNICATION__DEFAULT_TIMEOUT:** Default requests timeout in 30 seconds. 31 - **PUMPWOOD_COMUNICATION__DEBUG:** If object will be initiated using 32 debug parameter. It will have more verbosity and login at each 33 request. Options 'TRUE', 'FALSE'. 34 - **PUMPWOOD_COMUNICATION__VERIFY_SSL:** If requests will validate SSL 35 certificate. 36 """ 37 38 __base_header = {'Content-Type': 'application/json'} 39 """Base header for the requests.""" 40 41 @staticmethod 42 def _adjust_server_url(server_url): 43 """Remove tralling / if present on server URL.""" 44 if server_url is None: 45 return None 46 if server_url[-1] != '/': 47 return server_url + '/' 48 else: 49 return server_url 50 51 def __init__(self, name: str = None, server_url: str = None, 52 username: str = None, password: str = None, 53 verify_ssl: bool = True, debug: bool = None, 54 default_timeout: int = None, **kwargs): 55 """Create new PumpWoodMicroService object. 56 57 Creates a new microservice object. If just name is passed, object must 58 be initiate after with init() method. 59 60 Args: 61 name: 62 Name of the microservice, helps when exceptions 63 are raised. 64 server_url: 65 URL of the server that will be connected. 66 username: 67 Username that will be logged on. 68 password: 69 Variable to be converted to JSON and posted along 70 with the request. 71 verify_ssl: 72 Set if microservice will verify SSL certificate. 73 debug: 74 If microservice will be used as debug mode. This will obrigate 75 auth token refresh for each call. 76 default_timeout: 77 Default timeout for Pumpwood calls. 78 **kwargs: 79 Other parameters used for compatibility between versions. 80 81 Returns: 82 PumpWoodMicroService: New PumpWoodMicroService object 83 84 Raises: 85 No particular Raises. 86 """ 87 # Create attributes to be set at init function 88 self.name = None 89 """Name of the microservice instance.""" 90 self.server_url = None 91 """Pumpwood server URL.""" 92 self._default_timeout: int = None 93 """Default timeout for Pumpwood requests.""" 94 self._debug: bool = None 95 """Name of the microservice instance.""" 96 self._verify_ssl: bool = None 97 """If microservice should check the certificate.""" 98 self._is_mfa_login: bool = None 99 """Set if is MFA login.""" 100 self.__headers: dict = None 101 """Headers to be used on the requests.""" 102 self.__user: dict = None 103 """Information of the logged user.""" 104 self.__auth_header: dict = None 105 """Authenticated auth header.""" 106 self.__token_expiry: pd.Timedelta = None 107 """Expirity datetime of the authetication token.""" 108 self.__username: str = None 109 """Username associated with microservice.""" 110 self.__password: str = None 111 """Password associated with microservice.""" 112 self.init( 113 name=name, server_url=server_url, 114 username=username, password=password, 115 verify_ssl=verify_ssl, debug=debug, 116 default_timeout=default_timeout) 117 118 def init(self, name: str = None, server_url: str = None, 119 username: str = None, password: str = None, 120 verify_ssl: bool = True, debug: bool = None, 121 default_timeout: int = None, **kwargs): 122 """Lazzy initialization of the MicroService of object. 123 124 This function might be usefull to use the object as a singleton at 125 the backends. Using this function it is possible to instanciate an 126 empty object and them set the attributes latter at the systems. 127 128 Args: 129 name: 130 Name of the microservice, helps when exceptions 131 are raised. 132 server_url: 133 URL of the server that will be connected. 134 username: 135 Username that will be logged on. 136 password: 137 Variable to be converted to JSON and posted along 138 with the request. 139 verify_ssl: 140 Set if microservice will verify SSL certificate. 141 debug: 142 If microservice will be used as debug mode. This will obrigate 143 auth token refresh for each call. 144 default_timeout: 145 Default timeout for Pumpwood calls. 146 **kwargs: 147 Other parameters used for compatibility between versions. 148 149 Returns: 150 No return 151 152 Raises: 153 No particular Raises 154 """ 155 self.name = name 156 """Name of the microservice instance.""" 157 self.server_url = self._adjust_server_url(server_url) 158 """Pumpwood server URL.""" 159 160 # Set parameter using arguments or enviroment variables 161 if default_timeout is None: 162 self._default_timeout = int(os.getenv( 163 'PUMPWOOD_COMUNICATION__DEFAULT_TIMEOUT', 60)) 164 else: 165 self._default_timeout = default_timeout 166 167 if debug is None: 168 self._debug = os.getenv( 169 'PUMPWOOD_COMUNICATION__DEBUG', 'FALSE') == 'TRUE' 170 else: 171 self._debug = debug 172 173 if verify_ssl is None: 174 self._verify_ssl = os.getenv( 175 'PUMPWOOD_COMUNICATION__VERIFY_SSL', 'TRUE') == 'TRUE' 176 else: 177 self._verify_ssl = verify_ssl 178 179 self._is_mfa_login = False 180 self.__headers = None 181 self.__user = None 182 self.__auth_header = None 183 self.__token_expiry = None 184 self.__username = username 185 self.__password = password 186 187 @staticmethod 188 def angular_json(request_result) -> Any: 189 r"""Convert text to Json removing any XSSI at the beging of JSON. 190 191 Some backends add `)]}',\n` at the beginning of the JSON data to 192 prevent injection of functions. This function remove this characters 193 if present. 194 195 Args: 196 request_result: 197 JSON request to be converted. 198 199 Returns: 200 No return 201 202 Raises: 203 PumpWoodJSONLoadError: 204 If it is not possible to load JSON from request data. 205 """ 206 if request_result.text == '': 207 return None 208 209 string_start = ")]}',\n" 210 try: 211 if request_result.text[:6] == string_start: 212 return (orjson.loads(request_result.text[6:])) 213 else: 214 return (orjson.loads(request_result.text)) 215 except Exception: 216 msg = "Can not decode to Json" 217 raise PumpWoodJSONLoadError( 218 message=msg, payload={"request_data": request_result.text}) 219 220 def time_to_expiry(self) -> pd.Timedelta: 221 """Return time to token expiry. 222 223 Args: 224 No Args. 225 226 Returns: 227 Return time until token expiration. 228 """ 229 if self.__token_expiry is None: 230 return None 231 232 now_datetime = pd.to_datetime( 233 datetime.datetime.now(datetime.UTC), utc=True) 234 time_to_expiry = self.__token_expiry - now_datetime 235 return time_to_expiry 236 237 def is_credential_set(self) -> bool: 238 """Check if username and password are set on object. 239 240 Args: 241 No Args. 242 243 Returns: 244 True if usename and password were set during object creation or 245 later with init function. 246 """ 247 is_username_not_none = self.__username is not None 248 is_password_not_none = self.__password is not None 249 return is_username_not_none and is_password_not_none 250 251 @classmethod 252 def is_invalid_token_response(cls, response: Response) -> bool: 253 """Check if reponse has invalid token error. 254 255 Args: 256 response: 257 Request reponse to check for invalid token. 258 259 Returns: 260 Return True if response has an invalid token status. 261 """ 262 if response.status_code == 401: 263 return True 264 return False 265 266 def _login_resquest(self) -> Response: 267 """Request login with object credentials. 268 269 Args: 270 No Args 271 272 Returns (Response): 273 Request object. 274 """ 275 login_url = urljoin( 276 self.server_url, 'rest/registration/login/') 277 278 # Make a retry loop for authentication 279 login_result = None 280 for i in range(5): 281 login_result = requests.post( 282 login_url, json={ 283 'username': self.__username, 284 'password': self.__password}, 285 verify=self._verify_ssl, timeout=self._default_timeout) 286 if login_result.ok: 287 try: 288 login_data = self.angular_json(login_result) 289 return login_data 290 except Exception: # NOQA 291 pass 292 293 # Handle Unauthorized responses 294 elif self.is_invalid_token_response(login_result): 295 error_data = self.angular_json(login_result) 296 raise PumpWoodUnauthorized( 297 message="Login is not possible", 298 payload=error_data) 299 300 # Handle Forbidden responses 301 elif login_result.status_code == 403: 302 error_data = self.angular_json(login_result) 303 raise PumpWoodForbidden( 304 message="Login resquest is forbidden", 305 payload=error_data) 306 time.sleep(0.2) 307 308 # If response is not returned then something is not ok 309 error_data = self.angular_json(login_result) 310 raise PumpWoodOtherException( 311 message="Login not possible, server is not responding correctly", 312 payload=error_data) 313 314 def confirm_mfa_code(self, mfa_login_data: dict) -> dict: 315 """Ask user to confirm MFA code to login. 316 317 Open an input interface at terminal for user to validate MFA token. 318 319 Args: 320 mfa_login_data: 321 Result from login request with 'mfa_token' 322 as key. 323 324 Returns: 325 Return login returned with MFA confimation. 326 327 Raise: 328 Raise error if reponse is not valid using error_handler. 329 """ 330 code = input("## Please enter MFA code: ") 331 url = urljoin( 332 self.server_url, 'rest/registration/mfa-validate-code/') 333 mfa_response = requests.post(url, headers={ 334 "X-PUMPWOOD-MFA-Autorization": mfa_login_data['mfa_token']}, 335 json={"mfa_code": code}, timeout=self._default_timeout) 336 self.error_handler(mfa_response) 337 338 # Set _is_mfa_login true to indicate that login required MFA 339 self._is_mfa_login = True 340 return self.angular_json(mfa_response) 341 342 def login(self, force_refresh: bool = False) -> None: 343 """Log microservice in using username and password provided. 344 345 Args: 346 force_refresh (bool): 347 Force token refresh despise still valid 348 according to self.__token_expiry. 349 350 Returns: 351 No return 352 353 Raises: 354 Exception: 355 If login response has status diferent from 200. 356 """ 357 if not self.is_credential_set(): 358 raise PumpWoodUnauthorized( 359 message="Microservice username or/and password not set") 360 361 # Check if expiry time is 1h from now 362 refresh_expiry = False 363 if self.__token_expiry is None: 364 refresh_expiry = True 365 else: 366 time_to_expiry = self.time_to_expiry() 367 if time_to_expiry < datetime.timedelta(hours=1): 368 refresh_expiry = True 369 370 # When if debug always refresh token 371 if refresh_expiry or force_refresh or self._debug: 372 login_data = self._login_resquest() 373 if 'mfa_token' in login_data.keys(): 374 login_data = self.confirm_mfa_code( 375 mfa_login_data=login_data) 376 377 self.__auth_header = { 378 'Authorization': 'Token ' + login_data['token']} 379 self.__user = login_data["user"] 380 self.__token_expiry = pd.to_datetime(login_data['expiry']) 381 else: 382 # Token is not expired or envicted, them keep same token 383 return None 384 385 def logout(self, auth_header: dict = None) -> bool: 386 """Logout token. 387 388 Args: 389 auth_header: 390 Authentication header. 391 392 Returns: 393 True if logout was ok. 394 """ 395 resp = self.request_post( 396 url='rest/registration/logout/', 397 data={}, auth_header=auth_header) 398 # Set expiry to None to envict the token 399 self.__token_expiry = None 400 return resp is None 401 402 def logout_all(self, auth_header: dict = None) -> bool: 403 """Logout all tokens from user. 404 405 Args: 406 auth_header (dict): 407 Authentication header. 408 409 Returns: 410 True if logout all was ok. 411 """ 412 resp = self.request_post( 413 url='rest/registration/logoutall/', 414 data={}, auth_header=auth_header) 415 # Set expiry to None to envict the token 416 self.__token_expiry = None 417 return resp is None 418 419 def get_auth_header(self) -> dict: 420 """Retrieve auth_header and token_expiry from object. 421 422 Args: 423 No Args. 424 425 Returns: 426 Return authorization header and token_expiry datetime from object. 427 """ 428 # Copy the dictonary to avoid updating the original one 429 return copy.deepcopy({ 430 "auth_header": self.__auth_header, 431 "token_expiry": self.__token_expiry}) 432 433 def _check_auth_header(self, auth_header: dict, 434 multipart: bool = False) -> dict: 435 """Check if auth_header is set or auth_header if provided. 436 437 Args: 438 auth_header (dict): 439 AuthHeader to substitute the microservice original 440 at the request (user impersonation). 441 multipart (dict): 442 Set if call should be made as a multipart instead of JSON. 443 444 Returns (dict): 445 Return a header dict to be used in requests. 446 447 Raises: 448 PumpWoodUnauthorized: 449 If microservice is not logged and a auth_header method 450 argument is not provided. 451 PumpWoodUnauthorized: 452 If microservice is logged and a auth_header method argument 453 is provided. 454 """ 455 if auth_header is None: 456 # Login will refresh token if it is 1h to expire, it will also 457 # check if credentials are set. 458 self.login() 459 auth_header_data = self.get_auth_header() 460 auth_header = auth_header_data['auth_header'] 461 if multipart: 462 return auth_header 463 else: 464 return self.__base_header | auth_header 465 else: 466 if self.is_credential_set(): 467 msg = ( 468 'Microservice [{object_name}] with credentials and ' 469 'auth_header was provided') 470 raise PumpWoodUnauthorized( 471 message=msg, payload={'object_name': self.name}) 472 473 # Set base header as JSON since unserialization is done using 474 # Pumpwood Communication serialization function 475 temp__auth_header = auth_header.copy() 476 if multipart: 477 return temp__auth_header 478 else: 479 return self.__base_header | temp__auth_header 480 481 @classmethod 482 def error_handler(cls, response): 483 """Handle request error. 484 485 Check if is a Json and propagate the error with 486 same type if possible. If not Json raises the content. 487 488 Args: 489 response: 490 response to be handled, it is a PumpWoodException 491 return it will raise the same exception at microservice 492 object. 493 494 Returns: 495 No return. 496 497 Raises: 498 PumpWoodOtherException: 499 If content-type is not application/json. 500 PumpWoodOtherException: 501 If content-type is application/json, but type not 502 present or not recognisable at `exceptions.exceptions_dict`. 503 Other PumpWoodException sub-types: 504 If content-type is application/json if type is present and 505 recognisable. 506 507 Example: 508 No example 509 """ 510 if not response.ok: 511 utcnow = datetime.datetime.now(datetime.UTC) 512 response_content_type = response.headers['content-type'] 513 514 # Request information 515 url = response.url 516 method = response.request.method 517 if 'application/json' not in response_content_type.lower(): 518 # Raise the exception as first in exception deep. 519 exception_dict = [{ 520 "exception_url": url, 521 "exception_method": method, 522 "exception_utcnow": utcnow.isoformat(), 523 "exception_deep": 1}] 524 raise PumpWoodOtherException( 525 message=response.text, payload={ 526 "!exception_stack!": exception_dict}) 527 528 # Build error stack 529 response_dict = cls.angular_json(response) 530 531 # Removing previous error stack 532 payload = copy.deepcopy( 533 response_dict.get("payload", {})) 534 exception_stack = copy.deepcopy( 535 payload.pop("!exception_stack!", [])) 536 537 exception_deep = len(exception_stack) 538 exception_dict = { 539 "exception_url": url, 540 "exception_method": method, 541 "exception_utcnow": utcnow.isoformat(), 542 "exception_deep": exception_deep + 1 543 } 544 exception_stack.insert(0, exception_dict) 545 payload["!exception_stack!"] = exception_stack 546 547 ################### 548 # Propagate error # 549 # get exception using 'type' key at response data and get the 550 # exception from exceptions_dict at exceptions 551 exception_message = response_dict.get("message", "") 552 exception_type = response_dict.get("type", None) 553 TempPumpwoodException = exceptions_dict.get(exception_type) 554 if TempPumpwoodException is not None: 555 raise TempPumpwoodException( 556 message=exception_message, 557 status_code=response.status_code, 558 payload=payload) 559 else: 560 # If token is invalid is at response, return a 561 # PumpWoodUnauthorized error 562 is_invalid_token = cls.is_invalid_token_response(response) 563 response_dict["!exception_stack!"] = exception_stack 564 if is_invalid_token: 565 raise PumpWoodUnauthorized( 566 message="Invalid token", payload=payload) 567 else: 568 # If the error is not mapped return a 569 # PumpWoodOtherException limiting the message size to 1k 570 # characters 571 raise PumpWoodOtherException( 572 message="Not mapped exception JSON", 573 payload=response_dict) 574 575 def _request_post_json(self, post_url: str, data: any, 576 auth_header: dict = None, 577 parameters: dict = {}) -> any: 578 """Make a POST a request to url with data as JSON payload. 579 580 Args: 581 post_url: 582 URL to make the request, already with server url. 583 data: 584 Data to be used as Json payload. 585 parameters: 586 URL parameters. 587 auth_header: 588 AuthHeader to substitute the microservice original 589 at the request (user impersonation). 590 591 Returns: 592 Return the post response data. 593 594 Raises: 595 PumpWoodException sub-types: 596 Response is passed to error_handler. 597 """ 598 response = None 599 request_header = self._check_auth_header(auth_header=auth_header) 600 dumped_data = pumpJsonDump(data) 601 response = requests.post( 602 url=post_url, data=dumped_data, 603 params=parameters, verify=self._verify_ssl, 604 headers=request_header, timeout=self._default_timeout) 605 606 # Retry request if token is not valid forcing token renew 607 retry_with_login = ( 608 self.is_invalid_token_response(response) and 609 auth_header is None) 610 if not retry_with_login: 611 return response 612 else: 613 # Force token refresh if Unauthorized 614 time.sleep(0.5) 615 self.login(force_refresh=True) 616 request_header = self._check_auth_header(auth_header=auth_header) 617 return requests.post( 618 url=post_url, data=dumped_data, 619 params=parameters, verify=self._verify_ssl, 620 headers=request_header, timeout=self._default_timeout) 621 622 def _request_post_multi(self, post_url: str, data: any, files: list = None, 623 auth_header: dict = None, 624 parameters: dict = {}) -> any: 625 """Make a POST a request to url with data as multipart payload. 626 627 Args: 628 post_url: 629 URL to make the request, already with server url. 630 data: 631 Data to be used as Json payload. 632 files: 633 A dictonary with file data, files will be set on field 634 corresponding.to dictonary key. 635 `{'file1': open('file1', 'rb'), {'file2': open('file2', 'rb')}` 636 parameters: 637 URL parameters. 638 auth_header: 639 AuthHeader to substitute the microservice original 640 at the request (user impersonation). 641 642 Returns: 643 Return the post response data. 644 645 Raises: 646 PumpWoodException sub-types: 647 Response is passed to error_handler. 648 """ 649 # Request with files are done using multipart serializing all fields 650 # as JSON 651 request_header = self._check_auth_header( 652 auth_header=auth_header, multipart=True) 653 temp_data = {'__json__': pumpJsonDump(data)} 654 655 response = requests.post( 656 url=post_url, data=temp_data, files=files, params=parameters, 657 verify=self._verify_ssl, headers=request_header, 658 timeout=self._default_timeout) 659 retry_with_login = ( 660 self.is_invalid_token_response(response) and 661 auth_header is None) 662 if not retry_with_login: 663 return response 664 else: 665 # Force token refresh if Unauthorized 666 time.sleep(0.5) 667 self.login(force_refresh=True) 668 request_header = self._check_auth_header( 669 auth_header=auth_header, multipart=True) 670 return requests.post( 671 url=post_url, data=temp_data, files=files, 672 params=parameters, verify=self._verify_ssl, 673 headers=request_header, timeout=self._default_timeout) 674 675 @classmethod 676 def _treat_response_for_file(cls, response: Response) -> dict: 677 """Return if response contain a file. 678 679 Args: 680 response (Response): 681 Response to be checked for a file content. 682 683 Returns (bool): 684 Returns if reponse has a file. 685 """ 686 headers = response.headers 687 content_disposition = headers.get('content-disposition') 688 if content_disposition is None: 689 return cls.angular_json(response) 690 else: 691 fname = re.findall("filename=(.+)", content_disposition)[0] 692 return { 693 "__file__": True, 694 "content": response.content, 695 "content-type": response.headers['content-type'], 696 "filename": fname} 697 698 @classmethod 699 def _dump_query_parameters(cls, parameters: dict) -> dict: 700 """Dump query parameters to javascript compatibility. 701 702 Args: 703 parameters (dict): 704 Parameters to be parsed to JSON. 705 706 Returns: 707 pass 708 """ 709 # If parameters are not none convert them to json before 710 # sending information on query string, 'True' is 'true' on javascript 711 # for example 712 if parameters is not None: 713 temp_parameters = copy.deepcopy(parameters) 714 for key in temp_parameters.keys(): 715 # Do not convert str to json, it put extra "" araound string 716 if type(temp_parameters[key]) is not str: 717 temp_parameters[key] = pumpJsonDump(parameters[key]) 718 return temp_parameters 719 else: 720 return None 721 722 def request_post(self, url: str, data: any, files: list = None, 723 auth_header: dict = None, 724 parameters: dict = {}) -> any: 725 """Make a POST a request to url with data as multipart/json payload. 726 727 Args: 728 url: 729 URL to make the request, already with server url. 730 data: 731 Data to be used as Json payload. 732 files: 733 A dictonary with file data, files will be set on field 734 corresponding.to dictonary key. 735 `{'file1': open('file1', 'rb'), {'file2': open('file2', 'rb')}` 736 parameters: 737 URL parameters. 738 auth_header: 739 AuthHeader to substitute the microservice original 740 at the request (user impersonation). 741 742 Returns: 743 Return the post response data. 744 745 Raises: 746 PumpWoodException sub-types: 747 Response is passed to error_handler. 748 """ 749 post_url = urljoin(self.server_url, url) 750 dumped_parameters = self._dump_query_parameters(parameters=parameters) 751 response = None 752 if files is None: 753 response = self._request_post_json( 754 post_url=post_url, data=data, auth_header=auth_header, 755 parameters=dumped_parameters) 756 else: 757 response = self._request_post_multi( 758 post_url=post_url, data=data, files=files, 759 auth_header=auth_header, parameters=dumped_parameters) 760 761 # Handle errors and re-raise if Pumpwood Exceptions 762 self.error_handler(response) 763 return self._treat_response_for_file(response=response) 764 765 def request_get(self, url: str, parameters: dict = {}, 766 auth_header: dict = None, 767 use_disk_cache: bool = False, 768 disk_cache_expire: int = None) -> Any: 769 """Make a GET a request to url with data as JSON payload. 770 771 Add the auth_header acording to login information and refresh token 772 if auth_header=None and object token is expired. 773 774 Args: 775 url (str): 776 URL to make the request. 777 parameters (dict): 778 URL parameters to make the request. 779 auth_header (dict): 780 Auth header to substitute the microservice original 781 at the request (user impersonation). 782 use_disk_cache (bool): 783 If set true, get request will use local cache to reduce 784 the requests to the backend. 785 disk_cache_expire (int): 786 Time in seconds to expire the cache, it None it will 787 use de default set be PumpwoodCache. 788 789 Returns: 790 Return the post reponse data. 791 792 Raises: 793 PumpWoodException sub-types: 794 Raise exception if reponse is not 2XX and if 'type' key on 795 JSON payload if found at exceptions_dict. Use the same 796 exception, message and payload. 797 PumpWoodOtherException: 798 If exception type is not found or return is not a json. 799 """ 800 request_header = self._check_auth_header(auth_header) 801 # If is set to use diskcache, it will create a hash cash using 802 # the query paramerers, url and user access token. The 803 # hash will be used as index, not exposing the token at cache 804 # database 805 hash_dict = {} 806 if use_disk_cache: 807 hash_dict['authorization'] = request_header['Authorization'] 808 hash_dict['parameters'] = parameters 809 hash_dict['url'] = url 810 cache_results = default_cache.get(hash_dict=hash_dict) 811 if cache_results is not None: 812 msg = "get from cache url[{url}]".format(url=url) 813 logger.info(msg) 814 return cache_results 815 816 dumped_parameters = self._dump_query_parameters(parameters=parameters) 817 get_url = urljoin(self.server_url, url) 818 response = requests.get( 819 get_url, verify=self._verify_ssl, headers=request_header, 820 params=dumped_parameters, timeout=self._default_timeout) 821 822 # If token is expired, refresh it 823 retry_with_login = ( 824 self.is_invalid_token_response(response) and 825 auth_header is None) 826 if retry_with_login: 827 time.sleep(0.5) 828 self.login(force_refresh=True) 829 request_header = self._check_auth_header(auth_header=auth_header) 830 response = requests.get( 831 get_url, verify=self._verify_ssl, headers=request_header, 832 params=dumped_parameters, timeout=self._default_timeout) 833 834 # Re-raise Pumpwood exceptions 835 self.error_handler(response=response) 836 results = self._treat_response_for_file(response=response) 837 838 # If is set to use cache for this calls, set the local cache 839 if use_disk_cache and not results.get('__file__', False): 840 default_cache.set( 841 hash_dict=hash_dict, value=results, 842 expire=disk_cache_expire) 843 return results 844 845 def request_delete(self, url, parameters: dict = None, 846 auth_header: dict = None): 847 """Make a DELETE a request to url with data as Json payload. 848 849 Args: 850 url: 851 Url to make the request. 852 parameters: 853 Dictionary with Urls parameters. 854 auth_header: 855 Auth header to substitute the microservice original 856 at the request (user impersonation). 857 858 Returns: 859 Return the delete reponse payload. 860 861 Raises: 862 PumpWoodException sub-types: 863 Raise exception if reponse is not 2XX and if 'type' key on 864 JSON payload if found at exceptions_dict. Use the same 865 exception, message and payload. 866 PumpWoodOtherException: 867 If exception type is not found or return is not a json. 868 """ 869 request_header = self._check_auth_header(auth_header) 870 dumped_parameters = self._dump_query_parameters(parameters=parameters) 871 872 post_url = self.server_url + url 873 response = requests.delete( 874 post_url, verify=self._verify_ssl, headers=request_header, 875 params=dumped_parameters, timeout=self._default_timeout) 876 877 # Retry request if token is not valid forcing token renew 878 retry_with_login = ( 879 self.is_invalid_token_response(response) and 880 auth_header is None) 881 if retry_with_login: 882 time.sleep(0.5) 883 self.login(force_refresh=True) 884 request_header = self._check_auth_header(auth_header=auth_header) 885 response = requests.delete( 886 post_url, verify=self._verify_ssl, headers=request_header, 887 params=dumped_parameters, timeout=self._default_timeout) 888 889 # Re-raise Pumpwood Exceptions 890 self.error_handler(response) 891 return self.angular_json(response)
Base class for Pumpwood MicroService.
Enviroment variables can be used to set MicroService parameters:
- PUMPWOOD_COMUNICATION__DEFAULT_TIMEOUT: Default requests timeout in seconds.
- PUMPWOOD_COMUNICATION__DEBUG: If object will be initiated using debug parameter. It will have more verbosity and login at each request. Options 'TRUE', 'FALSE'.
- PUMPWOOD_COMUNICATION__VERIFY_SSL: If requests will validate SSL certificate.
51 def __init__(self, name: str = None, server_url: str = None, 52 username: str = None, password: str = None, 53 verify_ssl: bool = True, debug: bool = None, 54 default_timeout: int = None, **kwargs): 55 """Create new PumpWoodMicroService object. 56 57 Creates a new microservice object. If just name is passed, object must 58 be initiate after with init() method. 59 60 Args: 61 name: 62 Name of the microservice, helps when exceptions 63 are raised. 64 server_url: 65 URL of the server that will be connected. 66 username: 67 Username that will be logged on. 68 password: 69 Variable to be converted to JSON and posted along 70 with the request. 71 verify_ssl: 72 Set if microservice will verify SSL certificate. 73 debug: 74 If microservice will be used as debug mode. This will obrigate 75 auth token refresh for each call. 76 default_timeout: 77 Default timeout for Pumpwood calls. 78 **kwargs: 79 Other parameters used for compatibility between versions. 80 81 Returns: 82 PumpWoodMicroService: New PumpWoodMicroService object 83 84 Raises: 85 No particular Raises. 86 """ 87 # Create attributes to be set at init function 88 self.name = None 89 """Name of the microservice instance.""" 90 self.server_url = None 91 """Pumpwood server URL.""" 92 self._default_timeout: int = None 93 """Default timeout for Pumpwood requests.""" 94 self._debug: bool = None 95 """Name of the microservice instance.""" 96 self._verify_ssl: bool = None 97 """If microservice should check the certificate.""" 98 self._is_mfa_login: bool = None 99 """Set if is MFA login.""" 100 self.__headers: dict = None 101 """Headers to be used on the requests.""" 102 self.__user: dict = None 103 """Information of the logged user.""" 104 self.__auth_header: dict = None 105 """Authenticated auth header.""" 106 self.__token_expiry: pd.Timedelta = None 107 """Expirity datetime of the authetication token.""" 108 self.__username: str = None 109 """Username associated with microservice.""" 110 self.__password: str = None 111 """Password associated with microservice.""" 112 self.init( 113 name=name, server_url=server_url, 114 username=username, password=password, 115 verify_ssl=verify_ssl, debug=debug, 116 default_timeout=default_timeout)
Create new PumpWoodMicroService object.
Creates a new microservice object. If just name is passed, object must be initiate after with init() method.
Arguments:
- name: Name of the microservice, helps when exceptions are raised.
- server_url: URL of the server that will be connected.
- username: Username that will be logged on.
- password: Variable to be converted to JSON and posted along with the request.
- verify_ssl: Set if microservice will verify SSL certificate.
- debug: If microservice will be used as debug mode. This will obrigate auth token refresh for each call.
- default_timeout: Default timeout for Pumpwood calls.
- **kwargs: Other parameters used for compatibility between versions.
Returns:
PumpWoodMicroService: New PumpWoodMicroService object
Raises:
- No particular Raises.
118 def init(self, name: str = None, server_url: str = None, 119 username: str = None, password: str = None, 120 verify_ssl: bool = True, debug: bool = None, 121 default_timeout: int = None, **kwargs): 122 """Lazzy initialization of the MicroService of object. 123 124 This function might be usefull to use the object as a singleton at 125 the backends. Using this function it is possible to instanciate an 126 empty object and them set the attributes latter at the systems. 127 128 Args: 129 name: 130 Name of the microservice, helps when exceptions 131 are raised. 132 server_url: 133 URL of the server that will be connected. 134 username: 135 Username that will be logged on. 136 password: 137 Variable to be converted to JSON and posted along 138 with the request. 139 verify_ssl: 140 Set if microservice will verify SSL certificate. 141 debug: 142 If microservice will be used as debug mode. This will obrigate 143 auth token refresh for each call. 144 default_timeout: 145 Default timeout for Pumpwood calls. 146 **kwargs: 147 Other parameters used for compatibility between versions. 148 149 Returns: 150 No return 151 152 Raises: 153 No particular Raises 154 """ 155 self.name = name 156 """Name of the microservice instance.""" 157 self.server_url = self._adjust_server_url(server_url) 158 """Pumpwood server URL.""" 159 160 # Set parameter using arguments or enviroment variables 161 if default_timeout is None: 162 self._default_timeout = int(os.getenv( 163 'PUMPWOOD_COMUNICATION__DEFAULT_TIMEOUT', 60)) 164 else: 165 self._default_timeout = default_timeout 166 167 if debug is None: 168 self._debug = os.getenv( 169 'PUMPWOOD_COMUNICATION__DEBUG', 'FALSE') == 'TRUE' 170 else: 171 self._debug = debug 172 173 if verify_ssl is None: 174 self._verify_ssl = os.getenv( 175 'PUMPWOOD_COMUNICATION__VERIFY_SSL', 'TRUE') == 'TRUE' 176 else: 177 self._verify_ssl = verify_ssl 178 179 self._is_mfa_login = False 180 self.__headers = None 181 self.__user = None 182 self.__auth_header = None 183 self.__token_expiry = None 184 self.__username = username 185 self.__password = password
Lazzy initialization of the MicroService of object.
This function might be usefull to use the object as a singleton at the backends. Using this function it is possible to instanciate an empty object and them set the attributes latter at the systems.
Arguments:
- name: Name of the microservice, helps when exceptions are raised.
- server_url: URL of the server that will be connected.
- username: Username that will be logged on.
- password: Variable to be converted to JSON and posted along with the request.
- verify_ssl: Set if microservice will verify SSL certificate.
- debug: If microservice will be used as debug mode. This will obrigate auth token refresh for each call.
- default_timeout: Default timeout for Pumpwood calls.
- **kwargs: Other parameters used for compatibility between versions.
Returns:
No return
Raises:
- No particular Raises
187 @staticmethod 188 def angular_json(request_result) -> Any: 189 r"""Convert text to Json removing any XSSI at the beging of JSON. 190 191 Some backends add `)]}',\n` at the beginning of the JSON data to 192 prevent injection of functions. This function remove this characters 193 if present. 194 195 Args: 196 request_result: 197 JSON request to be converted. 198 199 Returns: 200 No return 201 202 Raises: 203 PumpWoodJSONLoadError: 204 If it is not possible to load JSON from request data. 205 """ 206 if request_result.text == '': 207 return None 208 209 string_start = ")]}',\n" 210 try: 211 if request_result.text[:6] == string_start: 212 return (orjson.loads(request_result.text[6:])) 213 else: 214 return (orjson.loads(request_result.text)) 215 except Exception: 216 msg = "Can not decode to Json" 217 raise PumpWoodJSONLoadError( 218 message=msg, payload={"request_data": request_result.text})
Convert text to Json removing any XSSI at the beging of JSON.
Some backends add )]}',\n
at the beginning of the JSON data to
prevent injection of functions. This function remove this characters
if present.
Arguments:
- request_result: JSON request to be converted.
Returns:
No return
Raises:
- PumpWoodJSONLoadError: If it is not possible to load JSON from request data.
220 def time_to_expiry(self) -> pd.Timedelta: 221 """Return time to token expiry. 222 223 Args: 224 No Args. 225 226 Returns: 227 Return time until token expiration. 228 """ 229 if self.__token_expiry is None: 230 return None 231 232 now_datetime = pd.to_datetime( 233 datetime.datetime.now(datetime.UTC), utc=True) 234 time_to_expiry = self.__token_expiry - now_datetime 235 return time_to_expiry
Return time to token expiry.
Arguments:
- No Args.
Returns:
Return time until token expiration.
237 def is_credential_set(self) -> bool: 238 """Check if username and password are set on object. 239 240 Args: 241 No Args. 242 243 Returns: 244 True if usename and password were set during object creation or 245 later with init function. 246 """ 247 is_username_not_none = self.__username is not None 248 is_password_not_none = self.__password is not None 249 return is_username_not_none and is_password_not_none
Check if username and password are set on object.
Arguments:
- No Args.
Returns:
True if usename and password were set during object creation or later with init function.
251 @classmethod 252 def is_invalid_token_response(cls, response: Response) -> bool: 253 """Check if reponse has invalid token error. 254 255 Args: 256 response: 257 Request reponse to check for invalid token. 258 259 Returns: 260 Return True if response has an invalid token status. 261 """ 262 if response.status_code == 401: 263 return True 264 return False
Check if reponse has invalid token error.
Arguments:
- response: Request reponse to check for invalid token.
Returns:
Return True if response has an invalid token status.
314 def confirm_mfa_code(self, mfa_login_data: dict) -> dict: 315 """Ask user to confirm MFA code to login. 316 317 Open an input interface at terminal for user to validate MFA token. 318 319 Args: 320 mfa_login_data: 321 Result from login request with 'mfa_token' 322 as key. 323 324 Returns: 325 Return login returned with MFA confimation. 326 327 Raise: 328 Raise error if reponse is not valid using error_handler. 329 """ 330 code = input("## Please enter MFA code: ") 331 url = urljoin( 332 self.server_url, 'rest/registration/mfa-validate-code/') 333 mfa_response = requests.post(url, headers={ 334 "X-PUMPWOOD-MFA-Autorization": mfa_login_data['mfa_token']}, 335 json={"mfa_code": code}, timeout=self._default_timeout) 336 self.error_handler(mfa_response) 337 338 # Set _is_mfa_login true to indicate that login required MFA 339 self._is_mfa_login = True 340 return self.angular_json(mfa_response)
Ask user to confirm MFA code to login.
Open an input interface at terminal for user to validate MFA token.
Arguments:
- mfa_login_data: Result from login request with 'mfa_token' as key.
Returns:
Return login returned with MFA confimation.
Raise:
Raise error if reponse is not valid using error_handler.
342 def login(self, force_refresh: bool = False) -> None: 343 """Log microservice in using username and password provided. 344 345 Args: 346 force_refresh (bool): 347 Force token refresh despise still valid 348 according to self.__token_expiry. 349 350 Returns: 351 No return 352 353 Raises: 354 Exception: 355 If login response has status diferent from 200. 356 """ 357 if not self.is_credential_set(): 358 raise PumpWoodUnauthorized( 359 message="Microservice username or/and password not set") 360 361 # Check if expiry time is 1h from now 362 refresh_expiry = False 363 if self.__token_expiry is None: 364 refresh_expiry = True 365 else: 366 time_to_expiry = self.time_to_expiry() 367 if time_to_expiry < datetime.timedelta(hours=1): 368 refresh_expiry = True 369 370 # When if debug always refresh token 371 if refresh_expiry or force_refresh or self._debug: 372 login_data = self._login_resquest() 373 if 'mfa_token' in login_data.keys(): 374 login_data = self.confirm_mfa_code( 375 mfa_login_data=login_data) 376 377 self.__auth_header = { 378 'Authorization': 'Token ' + login_data['token']} 379 self.__user = login_data["user"] 380 self.__token_expiry = pd.to_datetime(login_data['expiry']) 381 else: 382 # Token is not expired or envicted, them keep same token 383 return None
Log microservice in using username and password provided.
Arguments:
- force_refresh (bool): Force token refresh despise still valid according to self.__token_expiry.
Returns:
No return
Raises:
- Exception: If login response has status diferent from 200.
385 def logout(self, auth_header: dict = None) -> bool: 386 """Logout token. 387 388 Args: 389 auth_header: 390 Authentication header. 391 392 Returns: 393 True if logout was ok. 394 """ 395 resp = self.request_post( 396 url='rest/registration/logout/', 397 data={}, auth_header=auth_header) 398 # Set expiry to None to envict the token 399 self.__token_expiry = None 400 return resp is None
Logout token.
Arguments:
- auth_header: Authentication header.
Returns:
True if logout was ok.
402 def logout_all(self, auth_header: dict = None) -> bool: 403 """Logout all tokens from user. 404 405 Args: 406 auth_header (dict): 407 Authentication header. 408 409 Returns: 410 True if logout all was ok. 411 """ 412 resp = self.request_post( 413 url='rest/registration/logoutall/', 414 data={}, auth_header=auth_header) 415 # Set expiry to None to envict the token 416 self.__token_expiry = None 417 return resp is None
Logout all tokens from user.
Arguments:
- auth_header (dict): Authentication header.
Returns:
True if logout all was ok.
419 def get_auth_header(self) -> dict: 420 """Retrieve auth_header and token_expiry from object. 421 422 Args: 423 No Args. 424 425 Returns: 426 Return authorization header and token_expiry datetime from object. 427 """ 428 # Copy the dictonary to avoid updating the original one 429 return copy.deepcopy({ 430 "auth_header": self.__auth_header, 431 "token_expiry": self.__token_expiry})
Retrieve auth_header and token_expiry from object.
Arguments:
- No Args.
Returns:
Return authorization header and token_expiry datetime from object.
481 @classmethod 482 def error_handler(cls, response): 483 """Handle request error. 484 485 Check if is a Json and propagate the error with 486 same type if possible. If not Json raises the content. 487 488 Args: 489 response: 490 response to be handled, it is a PumpWoodException 491 return it will raise the same exception at microservice 492 object. 493 494 Returns: 495 No return. 496 497 Raises: 498 PumpWoodOtherException: 499 If content-type is not application/json. 500 PumpWoodOtherException: 501 If content-type is application/json, but type not 502 present or not recognisable at `exceptions.exceptions_dict`. 503 Other PumpWoodException sub-types: 504 If content-type is application/json if type is present and 505 recognisable. 506 507 Example: 508 No example 509 """ 510 if not response.ok: 511 utcnow = datetime.datetime.now(datetime.UTC) 512 response_content_type = response.headers['content-type'] 513 514 # Request information 515 url = response.url 516 method = response.request.method 517 if 'application/json' not in response_content_type.lower(): 518 # Raise the exception as first in exception deep. 519 exception_dict = [{ 520 "exception_url": url, 521 "exception_method": method, 522 "exception_utcnow": utcnow.isoformat(), 523 "exception_deep": 1}] 524 raise PumpWoodOtherException( 525 message=response.text, payload={ 526 "!exception_stack!": exception_dict}) 527 528 # Build error stack 529 response_dict = cls.angular_json(response) 530 531 # Removing previous error stack 532 payload = copy.deepcopy( 533 response_dict.get("payload", {})) 534 exception_stack = copy.deepcopy( 535 payload.pop("!exception_stack!", [])) 536 537 exception_deep = len(exception_stack) 538 exception_dict = { 539 "exception_url": url, 540 "exception_method": method, 541 "exception_utcnow": utcnow.isoformat(), 542 "exception_deep": exception_deep + 1 543 } 544 exception_stack.insert(0, exception_dict) 545 payload["!exception_stack!"] = exception_stack 546 547 ################### 548 # Propagate error # 549 # get exception using 'type' key at response data and get the 550 # exception from exceptions_dict at exceptions 551 exception_message = response_dict.get("message", "") 552 exception_type = response_dict.get("type", None) 553 TempPumpwoodException = exceptions_dict.get(exception_type) 554 if TempPumpwoodException is not None: 555 raise TempPumpwoodException( 556 message=exception_message, 557 status_code=response.status_code, 558 payload=payload) 559 else: 560 # If token is invalid is at response, return a 561 # PumpWoodUnauthorized error 562 is_invalid_token = cls.is_invalid_token_response(response) 563 response_dict["!exception_stack!"] = exception_stack 564 if is_invalid_token: 565 raise PumpWoodUnauthorized( 566 message="Invalid token", payload=payload) 567 else: 568 # If the error is not mapped return a 569 # PumpWoodOtherException limiting the message size to 1k 570 # characters 571 raise PumpWoodOtherException( 572 message="Not mapped exception JSON", 573 payload=response_dict)
Handle request error.
Check if is a Json and propagate the error with same type if possible. If not Json raises the content.
Arguments:
- response: response to be handled, it is a PumpWoodException return it will raise the same exception at microservice object.
Returns:
No return.
Raises:
- PumpWoodOtherException: If content-type is not application/json.
- PumpWoodOtherException: If content-type is application/json, but type not
present or not recognisable at
exceptions.exceptions_dict
. - Other PumpWoodException sub-types: If content-type is application/json if type is present and recognisable.
Example:
No example
722 def request_post(self, url: str, data: any, files: list = None, 723 auth_header: dict = None, 724 parameters: dict = {}) -> any: 725 """Make a POST a request to url with data as multipart/json payload. 726 727 Args: 728 url: 729 URL to make the request, already with server url. 730 data: 731 Data to be used as Json payload. 732 files: 733 A dictonary with file data, files will be set on field 734 corresponding.to dictonary key. 735 `{'file1': open('file1', 'rb'), {'file2': open('file2', 'rb')}` 736 parameters: 737 URL parameters. 738 auth_header: 739 AuthHeader to substitute the microservice original 740 at the request (user impersonation). 741 742 Returns: 743 Return the post response data. 744 745 Raises: 746 PumpWoodException sub-types: 747 Response is passed to error_handler. 748 """ 749 post_url = urljoin(self.server_url, url) 750 dumped_parameters = self._dump_query_parameters(parameters=parameters) 751 response = None 752 if files is None: 753 response = self._request_post_json( 754 post_url=post_url, data=data, auth_header=auth_header, 755 parameters=dumped_parameters) 756 else: 757 response = self._request_post_multi( 758 post_url=post_url, data=data, files=files, 759 auth_header=auth_header, parameters=dumped_parameters) 760 761 # Handle errors and re-raise if Pumpwood Exceptions 762 self.error_handler(response) 763 return self._treat_response_for_file(response=response)
Make a POST a request to url with data as multipart/json payload.
Arguments:
- url: URL to make the request, already with server url.
- data: Data to be used as Json payload.
- files: A dictonary with file data, files will be set on field
corresponding.to dictonary key.
{'file1': open('file1', 'rb'), {'file2': open('file2', 'rb')}
- parameters: URL parameters.
- auth_header: AuthHeader to substitute the microservice original at the request (user impersonation).
Returns:
Return the post response data.
Raises:
- PumpWoodException sub-types: Response is passed to error_handler.
765 def request_get(self, url: str, parameters: dict = {}, 766 auth_header: dict = None, 767 use_disk_cache: bool = False, 768 disk_cache_expire: int = None) -> Any: 769 """Make a GET a request to url with data as JSON payload. 770 771 Add the auth_header acording to login information and refresh token 772 if auth_header=None and object token is expired. 773 774 Args: 775 url (str): 776 URL to make the request. 777 parameters (dict): 778 URL parameters to make the request. 779 auth_header (dict): 780 Auth header to substitute the microservice original 781 at the request (user impersonation). 782 use_disk_cache (bool): 783 If set true, get request will use local cache to reduce 784 the requests to the backend. 785 disk_cache_expire (int): 786 Time in seconds to expire the cache, it None it will 787 use de default set be PumpwoodCache. 788 789 Returns: 790 Return the post reponse data. 791 792 Raises: 793 PumpWoodException sub-types: 794 Raise exception if reponse is not 2XX and if 'type' key on 795 JSON payload if found at exceptions_dict. Use the same 796 exception, message and payload. 797 PumpWoodOtherException: 798 If exception type is not found or return is not a json. 799 """ 800 request_header = self._check_auth_header(auth_header) 801 # If is set to use diskcache, it will create a hash cash using 802 # the query paramerers, url and user access token. The 803 # hash will be used as index, not exposing the token at cache 804 # database 805 hash_dict = {} 806 if use_disk_cache: 807 hash_dict['authorization'] = request_header['Authorization'] 808 hash_dict['parameters'] = parameters 809 hash_dict['url'] = url 810 cache_results = default_cache.get(hash_dict=hash_dict) 811 if cache_results is not None: 812 msg = "get from cache url[{url}]".format(url=url) 813 logger.info(msg) 814 return cache_results 815 816 dumped_parameters = self._dump_query_parameters(parameters=parameters) 817 get_url = urljoin(self.server_url, url) 818 response = requests.get( 819 get_url, verify=self._verify_ssl, headers=request_header, 820 params=dumped_parameters, timeout=self._default_timeout) 821 822 # If token is expired, refresh it 823 retry_with_login = ( 824 self.is_invalid_token_response(response) and 825 auth_header is None) 826 if retry_with_login: 827 time.sleep(0.5) 828 self.login(force_refresh=True) 829 request_header = self._check_auth_header(auth_header=auth_header) 830 response = requests.get( 831 get_url, verify=self._verify_ssl, headers=request_header, 832 params=dumped_parameters, timeout=self._default_timeout) 833 834 # Re-raise Pumpwood exceptions 835 self.error_handler(response=response) 836 results = self._treat_response_for_file(response=response) 837 838 # If is set to use cache for this calls, set the local cache 839 if use_disk_cache and not results.get('__file__', False): 840 default_cache.set( 841 hash_dict=hash_dict, value=results, 842 expire=disk_cache_expire) 843 return results
Make a GET a request to url with data as JSON payload.
Add the auth_header acording to login information and refresh token if auth_header=None and object token is expired.
Arguments:
- url (str): URL to make the request.
- parameters (dict): URL parameters to make the request.
- auth_header (dict): Auth header to substitute the microservice original at the request (user impersonation).
- use_disk_cache (bool): If set true, get request will use local cache to reduce the requests to the backend.
- disk_cache_expire (int): Time in seconds to expire the cache, it None it will use de default set be PumpwoodCache.
Returns:
Return the post reponse data.
Raises:
- PumpWoodException sub-types: Raise exception if reponse is not 2XX and if 'type' key on JSON payload if found at exceptions_dict. Use the same exception, message and payload.
- PumpWoodOtherException: If exception type is not found or return is not a json.
845 def request_delete(self, url, parameters: dict = None, 846 auth_header: dict = None): 847 """Make a DELETE a request to url with data as Json payload. 848 849 Args: 850 url: 851 Url to make the request. 852 parameters: 853 Dictionary with Urls parameters. 854 auth_header: 855 Auth header to substitute the microservice original 856 at the request (user impersonation). 857 858 Returns: 859 Return the delete reponse payload. 860 861 Raises: 862 PumpWoodException sub-types: 863 Raise exception if reponse is not 2XX and if 'type' key on 864 JSON payload if found at exceptions_dict. Use the same 865 exception, message and payload. 866 PumpWoodOtherException: 867 If exception type is not found or return is not a json. 868 """ 869 request_header = self._check_auth_header(auth_header) 870 dumped_parameters = self._dump_query_parameters(parameters=parameters) 871 872 post_url = self.server_url + url 873 response = requests.delete( 874 post_url, verify=self._verify_ssl, headers=request_header, 875 params=dumped_parameters, timeout=self._default_timeout) 876 877 # Retry request if token is not valid forcing token renew 878 retry_with_login = ( 879 self.is_invalid_token_response(response) and 880 auth_header is None) 881 if retry_with_login: 882 time.sleep(0.5) 883 self.login(force_refresh=True) 884 request_header = self._check_auth_header(auth_header=auth_header) 885 response = requests.delete( 886 post_url, verify=self._verify_ssl, headers=request_header, 887 params=dumped_parameters, timeout=self._default_timeout) 888 889 # Re-raise Pumpwood Exceptions 890 self.error_handler(response) 891 return self.angular_json(response)
Make a DELETE a request to url with data as Json payload.
Arguments:
- url: Url to make the request.
- parameters: Dictionary with Urls parameters.
- auth_header: Auth header to substitute the microservice original at the request (user impersonation).
Returns:
Return the delete reponse payload.
Raises:
- PumpWoodException sub-types: Raise exception if reponse is not 2XX and if 'type' key on JSON payload if found at exceptions_dict. Use the same exception, message and payload.
- PumpWoodOtherException: If exception type is not found or return is not a json.