def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not hasattr(e, 'code') and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) headers = {} if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[0] if supported_mediatypes else "text/plain" resp = self.make_response( data, code, headers, fallback_mediatype = fallback_mediatype ) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp
def test_error_data(self): self.assertEquals(error_data(400), { 'status': 400, 'message': 'Bad Request', })
def handle_error(self, e): """Error handler for the API transforms a raised exception into a Flask response, with the appropriate HTTP status code and body. :param e: the raised Exception object :type e: Exception """ got_request_exception.send(current_app._get_current_object(), exception=e) if not isinstance(e, HTTPException) and current_app.propagate_exceptions: exc_type, exc_value, tb = sys.exc_info() if exc_value is e: raise else: raise e code = getattr(e, 'code', 500) data = getattr(e, 'data', error_data(code)) headers = {} if code >= 500: # There's currently a bug in Python3 that disallows calling # logging.exception() when an exception hasn't actually be raised if sys.exc_info() == (None, None, None): current_app.logger.error("Internal Error") else: current_app.logger.exception("Internal Error") help_on_404 = current_app.config.get("ERROR_404_HELP", True) if code == 404 and help_on_404 and ('message' not in data or data['message'] == HTTP_STATUS_CODES[404]): rules = dict([(re.sub('(<.*>)', '', rule.rule), rule.rule) for rule in current_app.url_map.iter_rules()]) close_matches = difflib.get_close_matches(request.path, rules.keys()) if close_matches: # If we already have a message, add punctuation and continue it. if "message" in data: data["message"] += ". " else: data["message"] = "" data['message'] += 'You have requested this URI [' + request.path + \ '] but did you mean ' + \ ' or '.join(( rules[match] for match in close_matches) ) + ' ?' if code == 405: headers['Allow'] = e.valid_methods error_cls_name = type(e).__name__ if error_cls_name in self.errors: custom_data = self.errors.get(error_cls_name, {}) code = custom_data.get('status', 500) data.update(custom_data) if code == 406 and self.default_mediatype is None: # if we are handling NotAcceptable (406), make sure that # make_response uses a representation we support as the # default mediatype (so that make_response doesn't throw # another NotAcceptable error). supported_mediatypes = list(self.representations.keys()) fallback_mediatype = supported_mediatypes[ 0] if supported_mediatypes else "text/plain" resp = self.make_response(data, code, headers, fallback_mediatype=fallback_mediatype) else: resp = self.make_response(data, code, headers) if code == 401: resp = self.unauthorized(resp) return resp