def make_call(self, path, body=None, delete=False):
if body:<EOL><INDENT>request_body = json.dumps(body)<EOL>def call():<EOL><INDENT>return self.session.post(self.endpoint + path, auth=self.auth, data=request_body, timeout=self.timeout)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not delete:<EOL><INDENT>def call():<EOL><INDENT>return self.session.get(self.endpoint + path, auth=self.auth, timeout=self.timeout)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>def call():<EOL><INDENT>return self.session.delete(self.endpoint + path, auth=self.auth, timeout=self.timeout)<EOL><DEDENT><DEDENT><DEDENT>start_time = time()<EOL>result = None<EOL>for num_attempts in range(<NUM_LIT:1>, self.retry_max_attempts + <NUM_LIT:1>):<EOL><INDENT>try:<EOL><INDENT>result = call()<EOL>if result.status_code in [<NUM_LIT:200>,<NUM_LIT>,<NUM_LIT>]:<EOL><INDENT>return result<EOL><DEDENT>elif result.status_code in [<NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>]:<EOL><INDENT>if self.logger: self.logger.warning("<STR_LIT>",<EOL>result.status_code, num_attempts)<EOL>retry_wait = <NUM_LIT:0><EOL>if "<STR_LIT>" in result.headers:<EOL><INDENT>advice = result.headers["<STR_LIT>"]<EOL>advised_time = parsedate_tz(advice)<EOL>if advised_time is not None:<EOL><INDENT>retry_wait = int(mktime_tz(advised_time) - time())<EOL><DEDENT>else:<EOL><INDENT>retry_wait = int(advice)<EOL><DEDENT><DEDENT>if retry_wait <= <NUM_LIT:0>:<EOL><INDENT>delay = randint(<NUM_LIT:0>, self.retry_random_delay)<EOL>retry_wait = (int(pow(<NUM_LIT:2>, num_attempts - <NUM_LIT:1>)) * self.retry_first_delay) + delay<EOL><DEDENT><DEDENT>elif <NUM_LIT> <= result.status_code < <NUM_LIT>:<EOL><INDENT>raise ClientError("<STR_LIT>".format(result.status_code, result.text), result)<EOL><DEDENT>elif <NUM_LIT> <= result.status_code < <NUM_LIT>:<EOL><INDENT>raise RequestError(result)<EOL><DEDENT>else:<EOL><INDENT>raise ServerError(result)<EOL><DEDENT><DEDENT>except requests.Timeout:<EOL><INDENT>if self.logger: self.logger.warning("<STR_LIT>",<EOL>self.timeout, num_attempts)<EOL>retry_wait = <NUM_LIT:0><EOL>result = None<EOL><DEDENT>if num_attempts < self.retry_max_attempts:<EOL><INDENT>if retry_wait > <NUM_LIT:0>:<EOL><INDENT>if self.logger: self.logger.warning("<STR_LIT>", retry_wait)<EOL>sleep(retry_wait)<EOL><DEDENT>else:<EOL><INDENT>if self.logger: self.logger.warning("<STR_LIT>")<EOL><DEDENT><DEDENT><DEDENT>total_time = int(time() - start_time)<EOL>if self.logger: self.logger.error("<STR_LIT>",<EOL>self.retry_max_attempts, total_time)<EOL>raise UnavailableError(self.retry_max_attempts, total_time, result)<EOL>
Make a single UMAPI call with error handling and retry on temporary failure.
:param path: the string endpoint path for the call
:param body: (optional) list of dictionaries to be serialized into the request body
:return: the requests.result object (on 200 response), raise error otherwise