Source code for fbchat._exception

import attr
import requests

from typing import Any, Optional

# Not frozen, since that doesn't work in PyPy
[docs]@attr.s(slots=True, auto_exc=True) class FacebookError(Exception): """Base class for all custom exceptions raised by ``fbchat``. All exceptions in the module inherit this. """ #: A message describing the error message = attr.ib(type=str)
[docs]@attr.s(slots=True, auto_exc=True) 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=Optional[int]) def __str__(self): if not self.status_code: return self.message return "Got {} response: {}".format(self.status_code, self.message)
[docs]@attr.s(slots=True, auto_exc=True) class ParseError(FacebookError): """Raised when we fail parsing a response from Facebook. This may contain sensitive data, so should not be logged to file. """ data = attr.ib(type=Any) """The data that triggered the error. The format of this cannot be relied on, it's only for debugging purposes. """ def __str__(self): msg = "{}. Please report this, along with the data below!\n{}" return msg.format(self.message, self.data)
[docs]@attr.s(slots=True, auto_exc=True) class NotLoggedIn(FacebookError): """Raised by Facebook if the client has been logged out."""
[docs]@attr.s(slots=True, auto_exc=True) class ExternalError(FacebookError): """Base class for errors that Facebook return.""" #: 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=Optional[int]) def __str__(self): if self.code: return "#{} {}: {}".format(self.code, self.message, self.description) return "{}: {}".format(self.message, self.description)
[docs]@attr.s(slots=True, auto_exc=True) class GraphQLError(ExternalError): """Raised by Facebook if there was an error in the GraphQL query.""" # TODO: Handle multiple errors #: Query debug information debug_info = attr.ib(None, type=Optional[str]) def __str__(self): if self.debug_info: return "{}, {}".format(super().__str__(), self.debug_info) return super().__str__()
[docs]@attr.s(slots=True, auto_exc=True) class InvalidParameters(ExternalError): """Raised by Facebook if: - Some function supplied invalid parameters. - Some content is not found. - Some content is no longer available. """
[docs]@attr.s(slots=True, auto_exc=True) class PleaseRefresh(ExternalError): """Raised by Facebook if the client has been inactive for too long. This error usually happens after 1-2 days of inactivity. """ code = attr.ib(1357004)
def handle_payload_error(j): if "error" not in j: return code = j["error"] if code == 1357001: raise NotLoggedIn(j["errorSummary"]) elif code == 1357004: error_cls = PleaseRefresh elif code in (1357031, 1545010, 1545003): error_cls = InvalidParameters else: error_cls = ExternalError raise error_cls(j["errorSummary"], description=j["errorDescription"], code=code) def handle_graphql_errors(j): errors = [] if j.get("error"): errors = [j["error"]] if "errors" in j: errors = j["errors"] if errors: error = errors[0] # TODO: Handle multiple errors # TODO: Use `severity` and `description` raise GraphQLError( # TODO: What data is always available? message=error.get("summary", "Unknown error"), description=error.get("message", ""), code=error.get("code"), debug_info=error.get("debug_info"), ) def handle_http_error(code): if code == 404: raise HTTPError( "This might be because you provided an invalid id" + " (Facebook usually require integer ids)", status_code=code, ) if code == 500: raise HTTPError( "There is probably an error on the endpoint, or it might be rate limited", status_code=code, ) if 400 <= code < 600: raise HTTPError("Failed sending request", status_code=code) def handle_requests_error(e): if isinstance(e, requests.ConnectionError): raise HTTPError("Connection error") from e if isinstance(e, requests.HTTPError): pass # Raised when using .raise_for_status, so should never happen if isinstance(e, requests.URLRequired): pass # Should never happen, we always prove valid URLs if isinstance(e, requests.TooManyRedirects): pass # TODO: Consider using allow_redirects=False to prevent this if isinstance(e, requests.Timeout): pass # Should never happen, we don't set timeouts raise HTTPError("Requests error") from e