Add ExternalError.description and GraphQLError.debug_info

This commit is contained in:
Mads Marquart
2020-01-15 14:03:35 +01:00
parent e25f53d9a9
commit 28791b2118
6 changed files with 36 additions and 26 deletions

View File

@@ -12,6 +12,7 @@ class FacebookError(Exception):
All exceptions in the module inherit this. All exceptions in the module inherit this.
""" """
#: A message describing the error
message = attr.ib(type=str) message = attr.ib(type=str)
@@ -19,8 +20,14 @@ class FacebookError(Exception):
class HTTPError(FacebookError): class HTTPError(FacebookError):
"""Base class for errors with the HTTP(s) connection to Facebook.""" """Base class for errors with the HTTP(s) connection to Facebook."""
#: The returned HTTP status code, if relevant
status_code = attr.ib(None, type=int) status_code = attr.ib(None, type=int)
def __str__(self):
if not self.status_code:
return self.message
return "#{}: {}".format(self.status_code, self.message)
@attrs_exception @attrs_exception
class ParseError(FacebookError): class ParseError(FacebookError):
@@ -44,24 +51,31 @@ class ParseError(FacebookError):
class ExternalError(FacebookError): class ExternalError(FacebookError):
"""Base class for errors that Facebook return.""" """Base class for errors that Facebook return."""
#: The error message that Facebook returned (In the user's own language) #: The error message that Facebook returned (Possibly in the user's own language)
message = attr.ib(type=str) description = attr.ib(type=str)
#: The error code that Facebook returned #: The error code that Facebook returned
code = attr.ib(None, type=int) code = attr.ib(None, type=int)
def __str__(self): def __str__(self):
if self.code: if self.code:
return "#{}: {}".format(self.code, self.message) return "{}: #{}, {}".format(self.message, self.code, self.description)
return self.message return "{}: {}".format(self.message, self.description)
@attrs_exception @attrs_exception
class GraphQLError(ExternalError): class GraphQLError(ExternalError):
"""Raised by Facebook if there was an error in the GraphQL query.""" """Raised by Facebook if there was an error in the GraphQL query."""
# TODO: Add `summary`, `severity` and `description`
# TODO: Handle multiple errors # TODO: Handle multiple errors
#: Query debug information
debug_info = attr.ib(None, type=str)
def __str__(self):
if self.debug_info:
return "{}, {}".format(super().__str__(), self.debug_info)
return super().__str__()
@attrs_exception @attrs_exception
class InvalidParameters(ExternalError): class InvalidParameters(ExternalError):
@@ -103,10 +117,7 @@ def handle_payload_error(j):
else: else:
error_cls = ExternalError error_cls = ExternalError
# TODO: Use j["errorSummary"] # TODO: Use j["errorSummary"]
# "errorDescription" is in the users own language! raise error_cls("Error sending request", j["errorDescription"], code=code)
raise error_cls(
"Error sending request: {}".format(j["errorDescription"]), code=code
)
def handle_graphql_errors(j): def handle_graphql_errors(j):
@@ -117,10 +128,13 @@ def handle_graphql_errors(j):
errors = j["errors"] errors = j["errors"]
if errors: if errors:
error = errors[0] # TODO: Handle multiple errors error = errors[0] # TODO: Handle multiple errors
# TODO: Use `summary`, `severity` and `description` # TODO: Use `severity` and `description`
raise GraphQLError( raise GraphQLError(
"{} / {!r}".format(error.get("message"), error.get("debug_info")), # TODO: What data is always available?
error.get("summary", "Unknown error"),
error.get("message", ""),
code=error.get("code"), code=error.get("code"),
debug_info=error.get("debug_info"),
) )

View File

@@ -53,9 +53,7 @@ class Plan:
} }
j = thread.session._payload_post("/ajax/eventreminder/create", data) j = thread.session._payload_post("/ajax/eventreminder/create", data)
if "error" in j: if "error" in j:
raise _exception.ExternalError( raise _exception.ExternalError("Failed creating plan", j["error"])
"Failed creating plan: {}".format(j["error"])
)
def edit( def edit(
self, self,

View File

@@ -102,7 +102,6 @@ class Poll:
) )
if j.get("status") != "success": if j.get("status") != "success":
raise _exception.ExternalError( raise _exception.ExternalError(
"Failed updating poll vote: {}: {}".format( "Failed updating poll vote: {}".format(j.get("errorTitle")),
j.get("errorTitle"), j.get("errorMessage") j.get("errorMessage"),
)
) )

View File

@@ -202,7 +202,7 @@ class Session:
else: else:
code, msg = get_error_data(r.text, r.url) code, msg = get_error_data(r.text, r.url)
raise _exception.ExternalError( raise _exception.ExternalError(
"Login failed. {}, url: {}".format(msg, r.url), code=code "Login failed at url {}".format(r.url), msg, code=code
) )
def is_logged_in(self): def is_logged_in(self):

View File

@@ -479,9 +479,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
} }
j = self.session._payload_post("/mercury/attachments/forward/", data) j = self.session._payload_post("/mercury/attachments/forward/", data)
if not j.get("success"): if not j.get("success"):
raise _exception.ExternalError( raise _exception.ExternalError("Failed forwarding attachment", j["error"])
"Failed forwarding attachment: {}".format(j["error"])
)
def _set_typing(self, typing): def _set_typing(self, typing):
data = { data = {
@@ -545,9 +543,8 @@ class ThreadABC(metaclass=abc.ABCMeta):
) )
if j.get("status") != "success": if j.get("status") != "success":
raise _exception.ExternalError( raise _exception.ExternalError(
"Failed creating poll: {}, {}".format( "Failed creating poll: {}".format(j.get("errorTitle")),
j.get("errorTitle"), j.get("errorMessage") j.get("errorMessage"),
)
) )
def mute(self, duration: datetime.timedelta = None): def mute(self, duration: datetime.timedelta = None):

View File

@@ -67,7 +67,7 @@ ERROR_DATA = [
@pytest.mark.parametrize("exception,code,description,summary", ERROR_DATA) @pytest.mark.parametrize("exception,code,description,summary", ERROR_DATA)
def test_handle_payload_error(exception, code, summary, description): def test_handle_payload_error(exception, code, summary, description):
data = {"error": code, "errorSummary": summary, "errorDescription": description} data = {"error": code, "errorSummary": summary, "errorDescription": description}
with pytest.raises(exception, match=r"#\d+: Error sending request"): with pytest.raises(exception, match=r"Error sending request: #\d+"):
handle_payload_error(data) handle_payload_error(data)
@@ -97,7 +97,9 @@ def test_handle_graphql_errors():
"severity": "CRITICAL", "severity": "CRITICAL",
"summary": "Query error", "summary": "Query error",
} }
with pytest.raises(GraphQLError, match="#1675030: Errors while executing"): with pytest.raises(
GraphQLError, match="Query error: #1675030, Errors while executing"
):
handle_graphql_errors({"data": {"message_thread": None}, "errors": [error]}) handle_graphql_errors({"data": {"message_thread": None}, "errors": [error]})