From c71c1d37c2483abeb0a6f4d0e2c4d28f34be1523 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 23 Jan 2020 14:56:28 +0100 Subject: [PATCH] Small cleanup of event parsing --- fbchat/_events/__init__.py | 32 ++++++++------------ fbchat/_events/_common.py | 28 +++++++++--------- fbchat/_events/_delta_class.py | 18 ++++++----- fbchat/_events/_delta_type.py | 2 +- tests/events/test_client_payload.py | 2 +- tests/events/test_common.py | 18 +++++------ tests/events/test_delta_class.py | 2 +- tests/events/test_delta_type.py | 46 +++++++++++++++-------------- tests/events/test_main.py | 2 +- 9 files changed, 74 insertions(+), 76 deletions(-) diff --git a/fbchat/_events/__init__.py b/fbchat/_events/__init__.py index e7bbed5..09da365 100644 --- a/fbchat/_events/__init__.py +++ b/fbchat/_events/__init__.py @@ -1,7 +1,6 @@ import attr import datetime from ._common import attrs_event, Event, UnknownEvent, ThreadEvent -from . import _client_payload, _delta_class, _delta_type from ._client_payload import * from ._delta_class import * from ._delta_type import * @@ -69,23 +68,6 @@ class Presence(Event): return cls(statuses=statuses, full=data["list_type"] == "full") -def parse_delta(session, data): - try: - class_ = data["class"] - if class_ == "ClientPayload": - yield from _client_payload.parse_client_payloads(session, data) - elif class_ == "AdminTextMessage": - yield _delta_type.parse_delta(session, data) - else: - event = _delta_class.parse_delta(session, data) - if event: # Skip `None` - yield event - except _exception.ParseError: - raise - except Exception as e: - raise _exception.ParseError("Error parsing delta", data=data) from e - - def parse_events(session, topic, data): # See Mqtt._configure_connect_options for information about these topics try: @@ -93,7 +75,19 @@ def parse_events(session, topic, data): # `deltas` will always be available, since we're filtering out the things # that don't have it earlier in the MQTT listener for delta in data["deltas"]: - yield from parse_delta(session, delta) + if delta["class"] == "ClientPayload": + yield from parse_client_payloads(session, delta) + continue + try: + event = parse_delta(session, delta) + if event: # Skip `None` + yield event + except _exception.ParseError: + raise + except Exception as e: + raise _exception.ParseError( + "Error parsing delta", data=delta + ) from e elif topic == "/thread_typing": yield Typing._parse(session, data) diff --git a/fbchat/_events/_common.py b/fbchat/_events/_common.py index e93d09b..d88fcc8 100644 --- a/fbchat/_events/_common.py +++ b/fbchat/_events/_common.py @@ -18,6 +18,17 @@ class Event(metaclass=abc.ABCMeta): def _parse(cls, session, data): raise NotImplementedError + @staticmethod + def _get_thread(session, data): + # TODO: Handle pages? Is it even possible? + key = data["threadKey"] + + if "threadFbId" in key: + return _threads.Group(session=session, id=str(key["threadFbId"])) + elif "otherUserFbId" in key: + return _threads.User(session=session, id=str(key["otherUserFbId"])) + raise _exception.ParseError("Could not find thread data", data=data) + @attrs_event class UnknownEvent(Event): @@ -42,21 +53,10 @@ class ThreadEvent(Event): #: Thread that the action was done in thread = attr.ib(type="_threads.ThreadABC") - @staticmethod - def _get_thread(session, data): - # TODO: Handle pages? Is it even possible? - key = data["threadKey"] - - if "threadFbId" in key: - return _threads.Group(session=session, id=str(key["threadFbId"])) - elif "otherUserFbId" in key: - return _threads.User(session=session, id=str(key["otherUserFbId"])) - raise _exception.ParseError("Could not find thread data", data=data) - - @staticmethod - def _parse_metadata(session, data): + @classmethod + def _parse_metadata(cls, session, data): metadata = data["messageMetadata"] author = _threads.User(session=session, id=metadata["actorFbId"]) - thread = ThreadEvent._get_thread(session, metadata) + thread = cls._get_thread(session, metadata) at = _util.millis_to_datetime(int(metadata["timestamp"])) return author, thread, at diff --git a/fbchat/_events/_delta_class.py b/fbchat/_events/_delta_class.py index 6aa40e8..94ed8f8 100644 --- a/fbchat/_events/_delta_class.py +++ b/fbchat/_events/_delta_class.py @@ -1,6 +1,7 @@ import attr import datetime from ._common import attrs_event, Event, UnknownEvent, ThreadEvent +from . import _delta_type from .. import _util, _threads, _models from typing import Sequence, Optional @@ -83,7 +84,7 @@ class UnfetchedThreadEvent(Event): @classmethod def _parse(cls, session, data): - thread = ThreadEvent._get_thread(session, data) + thread = cls._get_thread(session, data) message = None if "messageId" in data: message = _models.Message(thread=thread, id=data["messageId"]) @@ -125,7 +126,7 @@ class ThreadsRead(Event): @classmethod def _parse_read_receipt(cls, session, data): author = _threads.User(session=session, id=data["actorFbId"]) - thread = ThreadEvent._get_thread(session, data) + thread = cls._get_thread(session, data) at = _util.millis_to_datetime(int(data["actionTimestampMs"])) return cls(author=author, threads=[thread], at=at) @@ -133,8 +134,7 @@ class ThreadsRead(Event): def _parse(cls, session, data): author = _threads.User(session=session, id=session.user_id) threads = [ - ThreadEvent._get_thread(session, {"threadKey": x}) - for x in data["threadKeys"] + cls._get_thread(session, {"threadKey": x}) for x in data["threadKeys"] ] at = _util.millis_to_datetime(int(data["actionTimestamp"])) return cls(author=author, threads=threads, at=at) @@ -175,14 +175,16 @@ class ThreadFolder(Event): @classmethod def _parse(cls, session, data): - thread = ThreadEvent._get_thread(session, data) + thread = cls._get_thread(session, data) folder = _threads.ThreadLocation._parse(data["folder"]) return cls(thread=thread, folder=folder) def parse_delta(session, data): class_ = data["class"] - if class_ == "ParticipantsAddedToGroupThread": + if class_ == "AdminTextMessage": + return _delta_type.parse_admin_message(session, data) + elif class_ == "ParticipantsAddedToGroupThread": return PeopleAdded._parse(session, data) elif class_ == "ParticipantLeftGroupThread": return PersonRemoved._parse(session, data) @@ -204,10 +206,10 @@ def parse_delta(session, data): elif class_ == "NoOp": # Skip "no operation" events return None - elif class_ == "ClientPayload": - return X._parse(session, data) elif class_ == "NewMessage": return MessageEvent._parse(session, data) elif class_ == "ThreadFolder": return ThreadFolder._parse(session, data) + elif class_ == "ClientPayload": + raise ValueError("This is implemented in `parse_events`") return UnknownEvent(source="Delta class", data=data) diff --git a/fbchat/_events/_delta_type.py b/fbchat/_events/_delta_type.py index e22e1ee..518cea2 100644 --- a/fbchat/_events/_delta_type.py +++ b/fbchat/_events/_delta_type.py @@ -280,7 +280,7 @@ class PlanResponded(ThreadEvent): return cls(author=author, thread=thread, plan=plan, take_part=take_part, at=at) -def parse_delta(session, data): +def parse_admin_message(session, data): type_ = data["type"] if type_ == "change_thread_theme": return ColorSet._parse(session, data) diff --git a/tests/events/test_client_payload.py b/tests/events/test_client_payload.py index fc6e265..191c9da 100644 --- a/tests/events/test_client_payload.py +++ b/tests/events/test_client_payload.py @@ -13,7 +13,7 @@ from fbchat import ( UnsendEvent, MessageReplyEvent, ) -from fbchat._events._client_payload import parse_client_delta, parse_client_payloads +from fbchat._events import parse_client_delta, parse_client_payloads def test_reaction_event_added(session): diff --git a/tests/events/test_common.py b/tests/events/test_common.py index 74f73eb..b16a8df 100644 --- a/tests/events/test_common.py +++ b/tests/events/test_common.py @@ -1,9 +1,9 @@ import pytest import datetime -from fbchat import Group, User, ParseError, ThreadEvent +from fbchat import Group, User, ParseError, Event, ThreadEvent -def test_thread_event_get_thread_group1(session): +def test_event_get_thread_group1(session): data = { "threadKey": {"threadFbId": 1234}, "messageId": "mid.$gAAT4Sw1WSGh14A3MOFvrsiDvr3Yc", @@ -18,10 +18,10 @@ def test_thread_event_get_thread_group1(session): "source:messenger:web", ], } - assert Group(session=session, id="1234") == ThreadEvent._get_thread(session, data) + assert Group(session=session, id="1234") == Event._get_thread(session, data) -def test_thread_event_get_thread_group2(session): +def test_event_get_thread_group2(session): data = { "actorFbId": "4321", "folderId": {"systemFolderId": "INBOX"}, @@ -33,10 +33,10 @@ def test_thread_event_get_thread_group2(session): "threadReadStateEffect": "KEEP_AS_IS", "timestamp": "1500000000000", } - assert Group(session=session, id="1234") == ThreadEvent._get_thread(session, data) + assert Group(session=session, id="1234") == Event._get_thread(session, data) -def test_thread_event_get_thread_user(session): +def test_event_get_thread_user(session): data = { "actorFbId": "4321", "folderId": {"systemFolderId": "INBOX"}, @@ -49,13 +49,13 @@ def test_thread_event_get_thread_user(session): "threadReadStateEffect": "KEEP_AS_IS", "timestamp": "1500000000000", } - assert User(session=session, id="1234") == ThreadEvent._get_thread(session, data) + assert User(session=session, id="1234") == Event._get_thread(session, data) -def test_thread_event_get_thread_unknown(session): +def test_event_get_thread_unknown(session): data = {"threadKey": {"abc": "1234"}} with pytest.raises(ParseError, match="Could not find thread data"): - ThreadEvent._get_thread(session, data) + Event._get_thread(session, data) def test_thread_event_parse_metadata(session): diff --git a/tests/events/test_delta_class.py b/tests/events/test_delta_class.py index 7f85148..6038ca1 100644 --- a/tests/events/test_delta_class.py +++ b/tests/events/test_delta_class.py @@ -17,7 +17,7 @@ from fbchat import ( MessageEvent, ThreadFolder, ) -from fbchat._events._delta_class import parse_delta +from fbchat._events import parse_delta def test_people_added(session): diff --git a/tests/events/test_delta_type.py b/tests/events/test_delta_type.py index 28f8bf9..88d94bb 100644 --- a/tests/events/test_delta_type.py +++ b/tests/events/test_delta_type.py @@ -29,7 +29,7 @@ from fbchat import ( PlanDeleted, PlanResponded, ) -from fbchat._events._delta_type import parse_delta +from fbchat._events import parse_admin_message def test_color_set(session): @@ -65,7 +65,7 @@ def test_color_set(session): thread=Group(session=session, id="4321"), color="#ff7e29", at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_emoji_set(session): @@ -99,7 +99,7 @@ def test_emoji_set(session): thread=User(session=session, id="1234"), emoji="🌟", at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_nickname_set(session): @@ -132,7 +132,7 @@ def test_nickname_set(session): subject=User(session=session, id="2345"), nickname="abc", at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_nickname_clear(session): @@ -164,7 +164,7 @@ def test_nickname_clear(session): subject=User(session=session, id="1234"), nickname=None, at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_admins_added(session): @@ -201,7 +201,7 @@ def test_admins_added(session): thread=Group(session=session, id="4321"), added=[User(session=session, id="2345")], at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_admins_removed(session): @@ -238,7 +238,7 @@ def test_admins_removed(session): thread=Group(session=session, id="4321"), removed=[User(session=session, id="1234")], at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_approvalmode_set(session): @@ -270,7 +270,7 @@ def test_approvalmode_set(session): thread=Group(session=session, id="4321"), require_admin_approval=True, at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_approvalmode_unset(session): @@ -302,7 +302,7 @@ def test_approvalmode_unset(session): thread=Group(session=session, id="4321"), require_admin_approval=False, at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_call_started(session): @@ -360,7 +360,7 @@ def test_call_started(session): author=User(session=session, id="1234"), thread=Group(session=session, id="4321"), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_group_call_ended(session): @@ -418,7 +418,7 @@ def test_group_call_ended(session): thread=Group(session=session, id="4321"), duration=datetime.timedelta(seconds=31), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_user_call_ended(session): @@ -460,7 +460,7 @@ def test_user_call_ended(session): thread=User(session=session, id="1234"), duration=datetime.timedelta(seconds=3), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_call_joined(session): @@ -495,7 +495,7 @@ def test_call_joined(session): author=User(session=session, id="1234"), thread=Group(session=session, id="4321"), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_poll_created(session): @@ -572,7 +572,7 @@ def test_poll_created(session): options_count=2, ), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_poll_answered(session): @@ -665,7 +665,7 @@ def test_poll_answered(session): added_ids=["1002", "1003"], removed_ids=["1001"], at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_plan_created(session): @@ -725,7 +725,7 @@ def test_plan_created(session): }, ), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) @pytest.mark.skip(reason="Need to gather test data") @@ -749,7 +749,7 @@ def test_plan_ended(session): }, ), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_plan_edited(session): @@ -815,7 +815,7 @@ def test_plan_edited(session): }, ), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_plan_deleted(session): @@ -879,7 +879,7 @@ def test_plan_deleted(session): }, ), at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) def test_plan_participation(session): @@ -948,9 +948,11 @@ def test_plan_participation(session): ), take_part=False, at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc), - ) == parse_delta(session, data) + ) == parse_admin_message(session, data) -def test_parse_delta_unknown(session): +def test_parse_admin_message_unknown(session): data = {"class": "AdminTextMessage", "type": "abc"} - assert UnknownEvent(source="Delta type", data=data) == parse_delta(session, data) + assert UnknownEvent(source="Delta type", data=data) == parse_admin_message( + session, data + ) diff --git a/tests/events/test_main.py b/tests/events/test_main.py index cb1a99e..741a21a 100644 --- a/tests/events/test_main.py +++ b/tests/events/test_main.py @@ -13,7 +13,7 @@ from fbchat import ( UnfetchedThreadEvent, ActiveStatus, ) -from fbchat._events import parse_delta, parse_events +from fbchat._events import parse_events def test_t_ms_full(session):