diff --git a/fbchat/_exception.py b/fbchat/_exception.py index b3b1621..49437d1 100644 --- a/fbchat/_exception.py +++ b/fbchat/_exception.py @@ -12,6 +12,7 @@ class FacebookError(Exception): All exceptions in the module inherit this. """ + #: A message describing the error message = attr.ib(type=str) @@ -19,8 +20,14 @@ class FacebookError(Exception): class HTTPError(FacebookError): """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) + def __str__(self): + if not self.status_code: + return self.message + return "#{}: {}".format(self.status_code, self.message) + @attrs_exception class ParseError(FacebookError): @@ -44,24 +51,31 @@ class ParseError(FacebookError): class ExternalError(FacebookError): """Base class for errors that Facebook return.""" - #: The error message that Facebook returned (In the user's own language) - message = attr.ib(type=str) + #: The error message that Facebook returned (Possibly in the user's own language) + description = attr.ib(type=str) #: The error code that Facebook returned code = attr.ib(None, type=int) def __str__(self): if self.code: - return "#{}: {}".format(self.code, self.message) - return self.message + return "{}: #{}, {}".format(self.message, self.code, self.description) + return "{}: {}".format(self.message, self.description) @attrs_exception class GraphQLError(ExternalError): """Raised by Facebook if there was an error in the GraphQL query.""" - # TODO: Add `summary`, `severity` and `description` # 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 class InvalidParameters(ExternalError): @@ -103,10 +117,7 @@ def handle_payload_error(j): else: error_cls = ExternalError # TODO: Use j["errorSummary"] - # "errorDescription" is in the users own language! - raise error_cls( - "Error sending request: {}".format(j["errorDescription"]), code=code - ) + raise error_cls("Error sending request", j["errorDescription"], code=code) def handle_graphql_errors(j): @@ -117,10 +128,13 @@ def handle_graphql_errors(j): errors = j["errors"] if errors: error = errors[0] # TODO: Handle multiple errors - # TODO: Use `summary`, `severity` and `description` + # TODO: Use `severity` and `description` 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"), + debug_info=error.get("debug_info"), ) diff --git a/fbchat/_plan.py b/fbchat/_plan.py index a8f33d3..9f78ecd 100644 --- a/fbchat/_plan.py +++ b/fbchat/_plan.py @@ -53,9 +53,7 @@ class Plan: } j = thread.session._payload_post("/ajax/eventreminder/create", data) if "error" in j: - raise _exception.ExternalError( - "Failed creating plan: {}".format(j["error"]) - ) + raise _exception.ExternalError("Failed creating plan", j["error"]) def edit( self, diff --git a/fbchat/_poll.py b/fbchat/_poll.py index f7680e3..32a3af5 100644 --- a/fbchat/_poll.py +++ b/fbchat/_poll.py @@ -102,7 +102,6 @@ class Poll: ) if j.get("status") != "success": raise _exception.ExternalError( - "Failed updating poll vote: {}: {}".format( - j.get("errorTitle"), j.get("errorMessage") - ) + "Failed updating poll vote: {}".format(j.get("errorTitle")), + j.get("errorMessage"), ) diff --git a/fbchat/_session.py b/fbchat/_session.py index f895549..e76ae18 100644 --- a/fbchat/_session.py +++ b/fbchat/_session.py @@ -202,7 +202,7 @@ class Session: else: code, msg = get_error_data(r.text, r.url) 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): diff --git a/fbchat/_thread.py b/fbchat/_thread.py index a080a82..5ba8378 100644 --- a/fbchat/_thread.py +++ b/fbchat/_thread.py @@ -479,9 +479,7 @@ class ThreadABC(metaclass=abc.ABCMeta): } j = self.session._payload_post("/mercury/attachments/forward/", data) if not j.get("success"): - raise _exception.ExternalError( - "Failed forwarding attachment: {}".format(j["error"]) - ) + raise _exception.ExternalError("Failed forwarding attachment", j["error"]) def _set_typing(self, typing): data = { @@ -545,9 +543,8 @@ class ThreadABC(metaclass=abc.ABCMeta): ) if j.get("status") != "success": raise _exception.ExternalError( - "Failed creating poll: {}, {}".format( - j.get("errorTitle"), j.get("errorMessage") - ) + "Failed creating poll: {}".format(j.get("errorTitle")), + j.get("errorMessage"), ) def mute(self, duration: datetime.timedelta = None): diff --git a/tests/test_exception.py b/tests/test_exception.py index dae970e..c9d3d74 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -67,7 +67,7 @@ ERROR_DATA = [ @pytest.mark.parametrize("exception,code,description,summary", ERROR_DATA) def test_handle_payload_error(exception, code, summary, 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) @@ -97,7 +97,9 @@ def test_handle_graphql_errors(): "severity": "CRITICAL", "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]})