Add ThreadABC helper, that'll contain functions that threads can call

This commit is contained in:
Mads Marquart
2020-01-09 00:35:43 +01:00
parent 4199439e07
commit 152f20027a
7 changed files with 80 additions and 34 deletions

View File

@@ -14,7 +14,7 @@ from . import _core, _util
from ._core import Image
from ._exception import FBchatException, FBchatFacebookError
from ._session import Session
from ._thread import ThreadType, ThreadLocation, ThreadColor, Thread
from ._thread import ThreadType, ThreadLocation, ThreadColor, ThreadABC, Thread
from ._user import TypingStatus, User, ActiveStatus
from ._group import Group
from ._page import Page

View File

@@ -108,11 +108,6 @@ class Client:
FETCH METHODS
"""
def _forced_fetch(self, thread_id, mid):
params = {"thread_and_message_id": {"thread_id": thread_id, "message_id": mid}}
(j,) = self.graphql_requests(_graphql.from_doc_id("1768656253222505", params))
return j
def fetch_threads(self, thread_location, before=None, after=None, limit=None):
"""Fetch all threads in ``thread_location``.
@@ -1820,7 +1815,8 @@ class Client:
self.on_unknown_messsage_type(msg=m)
else:
thread_id = str(delta["threadKey"]["threadFbId"])
fetch_info = self._forced_fetch(thread_id, mid)
thread = Thread(session=self.session, id=thread_id)
fetch_info = thread._forced_fetch(mid)
fetch_data = fetch_info["message"]
author_id = fetch_data["message_sender"]["id"]
at = _util.millis_to_datetime(int(fetch_data["timestamp_precise"]))

View File

@@ -1,13 +1,12 @@
import attr
from ._core import attrs_default, Image
from . import _util, _session, _plan
from ._thread import Thread
from . import _util, _session, _plan, _thread
from typing import Iterable
@attrs_default
class Group(Thread):
"""Represents a Facebook group. Inherits `Thread`."""
class Group(_thread.ThreadABC):
"""Represents a Facebook group. Implements `ThreadABC`."""
#: The session to use when making requests.
session = attr.ib(type=_session.Session)

View File

@@ -1,12 +1,11 @@
import attr
from ._core import attrs_default, Image
from . import _session, _plan
from ._thread import Thread
from . import _session, _plan, _thread
@attrs_default
class Page(Thread):
"""Represents a Facebook page. Inherits `Thread`."""
class Page(_thread.ThreadABC):
"""Represents a Facebook page. Implements `ThreadABC`."""
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
@@ -33,6 +32,9 @@ class Page(Thread):
#: The page's category
category = attr.ib(None)
def _to_send_data(self):
return {"other_user_fbid": self.id}
@classmethod
def _from_graphql(cls, session, data):
if data.get("profile_picture") is None:

View File

@@ -1,6 +1,8 @@
import abc
import attr
from ._core import attrs_default, Enum, Image
from . import _session
from typing import MutableMapping, Any
class ThreadType(Enum):
@@ -68,17 +70,39 @@ class ThreadColor(Enum):
return cls._extend_if_invalid(value)
@attrs_default
class Thread:
"""Represents a Facebook thread."""
class ThreadABC(metaclass=abc.ABCMeta):
"""Implemented by thread-like classes.
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The unique identifier of the thread.
id = attr.ib(converter=str)
This is private to implement.
"""
@property
@abc.abstractmethod
def session(self) -> _session.Session:
"""The session to use when making requests."""
raise NotImplementedError
@property
@abc.abstractmethod
def id(self) -> str:
"""The unique identifier of the thread."""
raise NotImplementedError
@abc.abstractmethod
def _to_send_data(self) -> MutableMapping[str, str]:
raise NotImplementedError
def _forced_fetch(self, message_id: str) -> dict:
params = {
"thread_and_message_id": {"thread_id": self.id, "message_id": message_id}
}
(j,) = self.session._graphql_requests(
_graphql.from_doc_id("1768656253222505", params)
)
return j
@staticmethod
def _parse_customization_info(data):
def _parse_customization_info(data: Any) -> MutableMapping[str, Any]:
if data is None or data.get("customization_info") is None:
return {}
info = data["customization_info"]
@@ -110,6 +134,24 @@ class Thread:
rtn["own_nickname"] = pc[1].get("nickname")
return rtn
@attrs_default
class Thread(ThreadABC):
"""Represents a Facebook thread, where the actual type is unknown.
Implements parts of `ThreadABC`, call the method to figure out if your use case is
supported. Otherwise, you'll have to use an `User`/`Group`/`Page` object.
Note: This list may change in minor versions!
"""
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The unique identifier of the thread.
id = attr.ib(converter=str)
def _to_send_data(self):
# TODO: Only implement this in subclasses
return {"other_user_fbid": self.id}
raise NotImplementedError(
"The method you called is not supported on raw Thread objects."
" Please use an appropriate User/Group/Page object instead!"
)

View File

@@ -1,7 +1,6 @@
import attr
from ._core import attrs_default, Enum, Image
from . import _util, _session, _plan
from ._thread import Thread
from . import _util, _session, _plan, _thread
GENDERS = {
@@ -42,8 +41,8 @@ class TypingStatus(Enum):
@attrs_default
class User(Thread):
"""Represents a Facebook user. Inherits `Thread`."""
class User(_thread.ThreadABC):
"""Represents a Facebook user. Implements `ThreadABC`."""
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
@@ -80,6 +79,9 @@ class User(Thread):
#: The default emoji
emoji = attr.ib(None)
def _to_send_data(self):
return {"other_user_fbid": self.id}
def confirm_friend_request(self):
"""Confirm a friend request, adding the user to your friend list."""
data = {"to_friend": self.id, "action": "confirm"}

View File

@@ -1,6 +1,6 @@
import pytest
import fbchat
from fbchat._thread import ThreadType, ThreadColor, Thread
from fbchat import ThreadType, ThreadColor, ThreadABC, Thread
def test_thread_type_to_class():
@@ -19,8 +19,8 @@ def test_thread_color_from_graphql():
def test_thread_parse_customization_info_empty():
assert {} == Thread._parse_customization_info(None)
assert {} == Thread._parse_customization_info({"customization_info": None})
assert {} == ThreadABC._parse_customization_info(None)
assert {} == ThreadABC._parse_customization_info({"customization_info": None})
def test_thread_parse_customization_info_group():
@@ -43,7 +43,7 @@ def test_thread_parse_customization_info_group():
"color": ThreadColor.BRILLIANT_ROSE,
"nicknames": {"123456789": "A", "987654321": "B"},
}
assert expected == Thread._parse_customization_info(data)
assert expected == ThreadABC._parse_customization_info(data)
def test_thread_parse_customization_info_user():
@@ -62,4 +62,9 @@ def test_thread_parse_customization_info_user():
# ... Other irrelevant fields
}
expected = {"emoji": None, "color": None, "own_nickname": "A", "nickname": "B"}
assert expected == Thread._parse_customization_info(data)
assert expected == ThreadABC._parse_customization_info(data)
def test_thread_create_and_implements_thread_abc(session):
thread = Thread(session=session, id="123")
assert thread._parse_customization_info