diff --git a/fbchat/__init__.py b/fbchat/__init__.py index ec17a54..b494748 100644 --- a/fbchat/__init__.py +++ b/fbchat/__init__.py @@ -17,6 +17,7 @@ from ._exception import ( HTTPError, ParseError, ExternalError, + GraphQLError, InvalidParameters, NotLoggedIn, PleaseRefresh, diff --git a/fbchat/_exception.py b/fbchat/_exception.py index aa37028..77fe044 100644 --- a/fbchat/_exception.py +++ b/fbchat/_exception.py @@ -118,15 +118,13 @@ def handle_graphql_errors(j): error = errors[0] # TODO: Handle multiple errors # TODO: Use `summary`, `severity` and `description` raise GraphQLError( - "GraphQL error: {} / {!r}".format( - error.get("message"), error.get("debug_info") - ), + "{} / {!r}".format(error.get("message"), error.get("debug_info")), code=error.get("code"), ) def handle_http_error(code): - msg = "Error when sending request: Got {} response.".format(code) + msg = "Error sending request: Got {} response.".format(code) if code == 404: raise HTTPError( msg + " This is either because you specified an invalid URL, or because" diff --git a/fbchat/_session.py b/fbchat/_session.py index d515623..dd3bd8b 100644 --- a/fbchat/_session.py +++ b/fbchat/_session.py @@ -205,9 +205,6 @@ class Session: """Safely log out the user. The session object must not be used after this action has been performed! - - Raises: - FBchatException: On failed logout """ logout_h = self._logout_h if not logout_h: @@ -218,9 +215,7 @@ class Session: url = _util.prefix_url("/logout.php") r = self._session.get(url, params={"ref": "mb", "h": logout_h}) if not r.ok: - raise exception.FBchatException( - "Failed logging out: {}".format(r.status_code) - ) + raise exception.HTTPError("Failed logging out", status_code=r.status_code) @classmethod def _from_session(cls, session): @@ -268,9 +263,6 @@ class Session: Args: cookies (dict): A dictionary containing session cookies - - Raises: - FBchatException: If given invalid cookies """ session = session_factory() session.cookies = requests.cookies.merge_cookies(session.cookies, cookies) diff --git a/tests/test_base.py b/tests/test_base.py index fd23ab3..717b78a 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -3,7 +3,7 @@ import py_compile from glob import glob from os import path, environ -from fbchat import FBchatException, Message, Client +from fbchat import FacebookError, Message, Client def test_examples(): @@ -23,7 +23,7 @@ def test_login(client1): assert not client1.is_logged_in() - with pytest.raises(FBchatException): + with pytest.raises(FacebookError): client1.login("", "", max_tries=1) client1.login(email, password) diff --git a/tests/test_exception.py b/tests/test_exception.py new file mode 100644 index 0000000..d440b8f --- /dev/null +++ b/tests/test_exception.py @@ -0,0 +1,125 @@ +import pytest +from fbchat import ( + FacebookError, + HTTPError, + ParseError, + ExternalError, + GraphQLError, + InvalidParameters, + NotLoggedIn, + PleaseRefresh, +) +from fbchat._exception import ( + handle_payload_error, + handle_graphql_errors, + handle_http_error, +) + + +ERROR_DATA = [ + (NotLoggedIn, 1357001, "Not logged in", "Please log in to continue."), + ( + PleaseRefresh, + 1357004, + "Sorry, something went wrong", + "Please try closing and re-opening your browser window.", + ), + ( + InvalidParameters, + 1357031, + "This content is no longer available", + ( + "The content you requested cannot be displayed at the moment. It may be" + " temporarily unavailable, the link you clicked on may have expired or you" + " may not have permission to view this page." + ), + ), + ( + InvalidParameters, + 1545010, + "Messages Unavailable", + ( + "Sorry, messages are temporarily unavailable." + " Please try again in a few minutes." + ), + ), + ( + ExternalError, + 1545026, + "Unable to Attach File", + ( + "The type of file you're trying to attach isn't allowed." + " Please try again with a different format." + ), + ), + (InvalidParameters, 1545003, "Invalid action", "You cannot perform that action."), + ( + ExternalError, + 1545012, + "Temporary Failure", + "There was a temporary error, please try again.", + ), +] + + +@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"): + handle_payload_error(data) + + +def test_handle_payload_error_no_error(): + assert handle_payload_error({}) is None + assert handle_payload_error({"payload": {"abc": ["Something", "else"]}}) is None + + +def test_handle_graphql_errors(): + error = { + "allow_user_retry": False, + "api_error_code": -1, + "code": 1675030, + "debug_info": None, + "description": "Error performing query.", + "fbtrace_id": "CLkuLR752sB", + "is_silent": False, + "is_transient": False, + "message": ( + 'Errors while executing operation "MessengerThreadSharedLinks":' + " At Query.message_thread: Field implementation threw an exception." + " Check your server logs for more information." + ), + "path": ["message_thread"], + "query_path": None, + "requires_reauth": False, + "severity": "CRITICAL", + "summary": "Query error", + } + with pytest.raises(GraphQLError, match="#1675030: Errors while executing"): + handle_graphql_errors({"data": {"message_thread": None}, "errors": [error]}) + + +def test_handle_graphql_errors_singular_error_key(): + with pytest.raises(GraphQLError, match="#123"): + handle_graphql_errors({"error": {"code": 123}}) + + +def test_handle_graphql_errors_no_error(): + assert handle_graphql_errors({"data": {"message_thread": None}}) is None + + +def test_handle_http_error(): + with pytest.raises(HTTPError): + handle_http_error(400) + with pytest.raises(HTTPError): + handle_http_error(500) + + +def test_handle_http_error_404_handling(): + with pytest.raises(HTTPError, match="invalid id"): + handle_http_error(404) + + +def test_handle_http_error_no_error(): + assert handle_http_error(200) is None + assert handle_http_error(302) is None diff --git a/tests/test_plans.py b/tests/test_plans.py index b93bf7d..e3669ee 100644 --- a/tests/test_plans.py +++ b/tests/test_plans.py @@ -1,6 +1,6 @@ import pytest -from fbchat import PlanData, FBchatFacebookError +from fbchat import PlanData from utils import random_hex, subset from time import time diff --git a/tests/test_send.py b/tests/test_send.py index 0542c18..aff62db 100644 --- a/tests/test_send.py +++ b/tests/test_send.py @@ -1,7 +1,7 @@ import pytest from os import path -from fbchat import FBchatFacebookError, Message, Mention +from fbchat import Message, Mention from utils import subset, STICKER_LIST, EMOJI_LIST, TEXT_LIST pytestmark = pytest.mark.online diff --git a/tests/test_thread_interraction.py b/tests/test_thread_interraction.py index babd376..92b5035 100644 --- a/tests/test_thread_interraction.py +++ b/tests/test_thread_interraction.py @@ -1,6 +1,6 @@ import pytest -from fbchat import Message, FBchatFacebookError +from fbchat import Message, FacebookError from utils import random_hex, subset from os import path @@ -60,10 +60,8 @@ def test_change_nickname(client, client_all, catch_event, compare): "😂", "😕", "😍", - pytest.param("🙃", marks=[pytest.mark.xfail(raises=FBchatFacebookError)]), - pytest.param( - "not an emoji", marks=[pytest.mark.xfail(raises=FBchatFacebookError)] - ), + pytest.param("🙃", marks=[pytest.mark.xfail(raises=FacebookError)]), + pytest.param("not an emoji", marks=[pytest.mark.xfail(raises=FacebookError)]), ], ) def test_change_emoji(client, catch_event, compare, emoji): @@ -97,7 +95,7 @@ def test_change_color(client, catch_event, compare): assert compare(x, new_color="#44bec7") -@pytest.mark.xfail(raises=FBchatFacebookError, reason="Should fail, but doesn't") +@pytest.mark.xfail(raises=FacebookError, reason="Should fail, but doesn't") def test_change_color_invalid(client): class InvalidColor: value = "#0077ff" diff --git a/tests/test_util.py b/tests/test_util.py index 8268c4a..e6c7ca3 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -7,9 +7,6 @@ from fbchat._util import ( str_base, generate_message_id, get_signature_id, - handle_payload_error, - handle_graphql_errors, - check_http_code, get_jsmods_require, require_list, mimetype_to_key, @@ -33,7 +30,7 @@ def test_strip_json_cruft(): def test_strip_json_cruft_invalid(): with pytest.raises(AttributeError): strip_json_cruft(None) - with pytest.raises(fbchat.FBchatException, match="No JSON object found"): + with pytest.raises(fbchat.ParseError, match="No JSON object found"): strip_json_cruft("No JSON object here!") @@ -42,7 +39,7 @@ def test_parse_json(): def test_parse_json_invalid(): - with pytest.raises(fbchat.FBchatFacebookError, match="Error while parsing JSON"): + with pytest.raises(fbchat.ParseError, match="Error while parsing JSON"): parse_json("No JSON object here!") @@ -71,125 +68,6 @@ def test_get_signature_id(): get_signature_id() -ERROR_DATA = [ - ( - fbchat._exception.FBchatNotLoggedIn, - 1357001, - "Not logged in", - "Please log in to continue.", - ), - ( - fbchat._exception.FBchatPleaseRefresh, - 1357004, - "Sorry, something went wrong", - "Please try closing and re-opening your browser window.", - ), - ( - fbchat._exception.FBchatInvalidParameters, - 1357031, - "This content is no longer available", - ( - "The content you requested cannot be displayed at the moment. It may be" - " temporarily unavailable, the link you clicked on may have expired or you" - " may not have permission to view this page." - ), - ), - ( - fbchat._exception.FBchatInvalidParameters, - 1545010, - "Messages Unavailable", - ( - "Sorry, messages are temporarily unavailable." - " Please try again in a few minutes." - ), - ), - ( - fbchat.FBchatFacebookError, - 1545026, - "Unable to Attach File", - ( - "The type of file you're trying to attach isn't allowed." - " Please try again with a different format." - ), - ), - ( - fbchat._exception.FBchatInvalidParameters, - 1545003, - "Invalid action", - "You cannot perform that action.", - ), - ( - fbchat.FBchatFacebookError, - 1545012, - "Temporary Failure", - "There was a temporary error, please try again.", - ), -] - - -@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"Error #\d+ when sending request"): - handle_payload_error(data) - - -def test_handle_payload_error_no_error(): - assert handle_payload_error({}) is None - assert handle_payload_error({"payload": {"abc": ["Something", "else"]}}) is None - - -def test_handle_graphql_errors(): - error = { - "allow_user_retry": False, - "api_error_code": -1, - "code": 1675030, - "debug_info": None, - "description": "Error performing query.", - "fbtrace_id": "CLkuLR752sB", - "is_silent": False, - "is_transient": False, - "message": ( - 'Errors while executing operation "MessengerThreadSharedLinks":' - " At Query.message_thread: Field implementation threw an exception." - " Check your server logs for more information." - ), - "path": ["message_thread"], - "query_path": None, - "requires_reauth": False, - "severity": "CRITICAL", - "summary": "Query error", - } - with pytest.raises(fbchat.FBchatFacebookError, match="GraphQL error"): - handle_graphql_errors({"data": {"message_thread": None}, "errors": [error]}) - - -def test_handle_graphql_errors_singular_error_key(): - with pytest.raises(fbchat.FBchatFacebookError, match="GraphQL error #123"): - handle_graphql_errors({"error": {"code": 123}}) - - -def test_handle_graphql_errors_no_error(): - assert handle_graphql_errors({"data": {"message_thread": None}}) is None - - -def test_check_http_code(): - with pytest.raises(fbchat.FBchatFacebookError): - check_http_code(400) - with pytest.raises(fbchat.FBchatFacebookError): - check_http_code(500) - - -def test_check_http_code_404_handling(): - with pytest.raises(fbchat.FBchatFacebookError, match="invalid id"): - check_http_code(404) - - -def test_check_http_code_no_error(): - assert check_http_code(200) is None - assert check_http_code(302) is None - - def test_get_jsmods_require_get_image_url(): data = { "__ar": 1, diff --git a/tests/utils.py b/tests/utils.py index bf5f9a4..b55848b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,7 +5,7 @@ import pytest from os import environ from random import randrange from contextlib import contextmanager -from fbchat import EmojiSize, FBchatFacebookError, Sticker, Client +from fbchat import EmojiSize, FacebookError, Sticker, Client log = logging.getLogger("fbchat.tests").addHandler(logging.NullHandler()) @@ -23,12 +23,8 @@ EMOJI_LIST = [ STICKER_LIST = [ Sticker(id="767334476626295"), - pytest.param( - Sticker(id="0"), marks=[pytest.mark.xfail(raises=FBchatFacebookError)] - ), - pytest.param( - Sticker(id=None), marks=[pytest.mark.xfail(raises=FBchatFacebookError)] - ), + pytest.param(Sticker(id="0"), marks=[pytest.mark.xfail(raises=FacebookError)]), + pytest.param(Sticker(id=None), marks=[pytest.mark.xfail(raises=FacebookError)]), ] TEXT_LIST = [ @@ -37,8 +33,8 @@ TEXT_LIST = [ "\\\n\t%?&'\"", "ˁҭʚ¹Ʋջوװ՞ޱɣࠚԹБɑȑңКએ֭ʗыԈٌʼőԈ×௴nચϚࠖణٔє܅Ԇޑط", "a" * 20000, # Maximum amount of characters you can send - pytest.param("a" * 20001, marks=[pytest.mark.xfail(raises=FBchatFacebookError)]), - pytest.param(None, marks=[pytest.mark.xfail(raises=FBchatFacebookError)]), + pytest.param("a" * 20001, marks=[pytest.mark.xfail(raises=FacebookError)]), + pytest.param(None, marks=[pytest.mark.xfail(raises=FacebookError)]), ]