Move ThreadLocation, ActiveStatus and Image to _models/ folder

This commit is contained in:
Mads Marquart
2020-01-23 15:15:09 +01:00
parent c71c1d37c2
commit 4015bed474
20 changed files with 146 additions and 136 deletions

View File

@@ -15,7 +15,6 @@ _logging.getLogger(__name__).addHandler(_logging.NullHandler())
# The order of these is somewhat significant, e.g. User has to be imported after Thread! # The order of these is somewhat significant, e.g. User has to be imported after Thread!
from . import _common, _util from . import _common, _util
from ._common import Image
from ._exception import ( from ._exception import (
FacebookError, FacebookError,
HTTPError, HTTPError,
@@ -28,12 +27,10 @@ from ._exception import (
) )
from ._session import Session from ._session import Session
from ._threads import ( from ._threads import (
ThreadLocation,
ThreadABC, ThreadABC,
Thread, Thread,
User, User,
UserData, UserData,
ActiveStatus,
Group, Group,
GroupData, GroupData,
Page, Page,
@@ -42,6 +39,9 @@ from ._threads import (
# Models # Models
from ._models import ( from ._models import (
Image,
ThreadLocation,
ActiveStatus,
Attachment, Attachment,
UnsentMessage, UnsentMessage,
ShareAttachment, ShareAttachment,

View File

@@ -368,7 +368,7 @@ class Client:
def fetch_threads( def fetch_threads(
self, self,
limit: Optional[int], limit: Optional[int],
location: _threads.ThreadLocation = _threads.ThreadLocation.INBOX, location: _models.ThreadLocation = _models.ThreadLocation.INBOX,
) -> Iterable[_threads.ThreadABC]: ) -> Iterable[_threads.ThreadABC]:
"""Fetch the client's thread list. """Fetch the client's thread list.
@@ -554,7 +554,7 @@ class Client:
) )
def move_threads( def move_threads(
self, location: _threads.ThreadLocation, threads: Iterable[_threads.ThreadABC] self, location: _models.ThreadLocation, threads: Iterable[_threads.ThreadABC]
): ):
"""Move threads to specified location. """Move threads to specified location.
@@ -562,10 +562,10 @@ class Client:
location: INBOX, PENDING, ARCHIVED or OTHER location: INBOX, PENDING, ARCHIVED or OTHER
threads: Threads to move threads: Threads to move
""" """
if location == _threads.ThreadLocation.PENDING: if location == _models.ThreadLocation.PENDING:
location = _threads.ThreadLocation.OTHER location = _models.ThreadLocation.OTHER
if location == _threads.ThreadLocation.ARCHIVED: if location == _models.ThreadLocation.ARCHIVED:
data_archive = {} data_archive = {}
data_unpin = {} data_unpin = {}
for thread in threads: for thread in threads:

View File

@@ -9,45 +9,3 @@ kw_only = sys.version_info[:2] > (3, 5)
#: Default attrs settings for classes #: Default attrs settings for classes
attrs_default = attr.s(frozen=True, slots=True, kw_only=kw_only) attrs_default = attr.s(frozen=True, slots=True, kw_only=kw_only)
@attrs_default
class Image:
#: URL to the image
url = attr.ib(type=str)
#: Width of the image
width = attr.ib(None, type=int)
#: Height of the image
height = attr.ib(None, type=int)
@classmethod
def _from_uri(cls, data):
return cls(
url=data["uri"],
width=int(data["width"]) if data.get("width") else None,
height=int(data["height"]) if data.get("height") else None,
)
@classmethod
def _from_url(cls, data):
return cls(
url=data["url"],
width=int(data["width"]) if data.get("width") else None,
height=int(data["height"]) if data.get("height") else None,
)
@classmethod
def _from_uri_or_none(cls, data):
if data is None:
return None
if data.get("uri") is None:
return None
return cls._from_uri(data)
@classmethod
def _from_url_or_none(cls, data):
if data is None:
return None
if data.get("url") is None:
return None
return cls._from_url(data)

View File

@@ -5,7 +5,7 @@ from ._client_payload import *
from ._delta_class import * from ._delta_class import *
from ._delta_type import * from ._delta_type import *
from .. import _exception, _threads from .. import _exception, _threads, _models
from typing import Mapping from typing import Mapping
@@ -55,14 +55,14 @@ class Presence(Event):
# TODO: Document this better! # TODO: Document this better!
#: User ids mapped to their active status #: User ids mapped to their active status
statuses = attr.ib(type=Mapping[str, _threads.ActiveStatus]) statuses = attr.ib(type=Mapping[str, "_models.ActiveStatus"])
#: ``True`` if the list is fully updated and ``False`` if it's partially updated #: ``True`` if the list is fully updated and ``False`` if it's partially updated
full = attr.ib(type=bool) full = attr.ib(type=bool)
@classmethod @classmethod
def _parse(cls, session, data): def _parse(cls, session, data):
statuses = { statuses = {
str(d["u"]): _threads.ActiveStatus._from_orca_presence(d) str(d["u"]): _models.ActiveStatus._from_orca_presence(d)
for d in data["list"] for d in data["list"]
} }
return cls(statuses=statuses, full=data["list_type"] == "full") return cls(statuses=statuses, full=data["list_type"] == "full")

View File

@@ -171,12 +171,12 @@ class ThreadFolder(Event):
#: The created thread #: The created thread
thread = attr.ib(type="_threads.ThreadABC") thread = attr.ib(type="_threads.ThreadABC")
#: The folder/location #: The folder/location
folder = attr.ib(type=_threads.ThreadLocation) folder = attr.ib(type="_models.ThreadLocation")
@classmethod @classmethod
def _parse(cls, session, data): def _parse(cls, session, data):
thread = cls._get_thread(session, data) thread = cls._get_thread(session, data)
folder = _threads.ThreadLocation._parse(data["folder"]) folder = _models.ThreadLocation._parse(data["folder"])
return cls(thread=thread, folder=folder) return cls(thread=thread, folder=folder)
@@ -190,7 +190,7 @@ def parse_delta(session, data):
return PersonRemoved._parse(session, data) return PersonRemoved._parse(session, data)
elif class_ == "MarkFolderSeen": elif class_ == "MarkFolderSeen":
# TODO: Finish this # TODO: Finish this
folders = [_threads.ThreadLocation._parse(folder) for folder in data["folders"]] folders = [_models.ThreadLocation._parse(folder) for folder in data["folders"]]
at = _util.millis_to_datetime(int(data["timestamp"])) at = _util.millis_to_datetime(int(data["timestamp"]))
return None return None
elif class_ == "ThreadName": elif class_ == "ThreadName":

View File

@@ -1,3 +1,4 @@
from ._common import *
from ._attachment import * from ._attachment import *
from ._file import * from ._file import *
from ._location import * from ._location import *

View File

@@ -1,5 +1,6 @@
import attr import attr
from .._common import attrs_default, Image from . import Image
from .._common import attrs_default
from .. import _util from .. import _util
from typing import Sequence from typing import Sequence

79
fbchat/_models/_common.py Normal file
View File

@@ -0,0 +1,79 @@
import attr
import datetime
import enum
from .._common import attrs_default
from .. import _util
class ThreadLocation(enum.Enum):
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
INBOX = "INBOX"
PENDING = "PENDING"
ARCHIVED = "ARCHIVED"
OTHER = "OTHER"
@classmethod
def _parse(cls, value: str):
return cls(value.lstrip("FOLDER_"))
@attrs_default
class ActiveStatus:
#: Whether the user is active now
active = attr.ib(None, type=bool)
#: Datetime when the user was last active
last_active = attr.ib(None, type=datetime.datetime)
#: Whether the user is playing Messenger game now
in_game = attr.ib(None, type=bool)
@classmethod
def _from_orca_presence(cls, data):
# TODO: Handle `c` and `vc` keys (Probably some binary data)
return cls(
active=data["p"] in [2, 3],
last_active=_util.seconds_to_datetime(data["l"]) if "l" in data else None,
in_game=None,
)
@attrs_default
class Image:
#: URL to the image
url = attr.ib(type=str)
#: Width of the image
width = attr.ib(None, type=int)
#: Height of the image
height = attr.ib(None, type=int)
@classmethod
def _from_uri(cls, data):
return cls(
url=data["uri"],
width=int(data["width"]) if data.get("width") else None,
height=int(data["height"]) if data.get("height") else None,
)
@classmethod
def _from_url(cls, data):
return cls(
url=data["url"],
width=int(data["width"]) if data.get("width") else None,
height=int(data["height"]) if data.get("height") else None,
)
@classmethod
def _from_uri_or_none(cls, data):
if data is None:
return None
if data.get("uri") is None:
return None
return cls._from_uri(data)
@classmethod
def _from_url_or_none(cls, data):
if data is None:
return None
if data.get("url") is None:
return None
return cls._from_url(data)

View File

@@ -1,7 +1,7 @@
import attr import attr
import datetime import datetime
from ._attachment import Attachment from . import Image, Attachment
from .._common import attrs_default, Image from .._common import attrs_default
from .. import _util from .. import _util
from typing import Set from typing import Set

View File

@@ -1,6 +1,6 @@
import attr import attr
from ._attachment import Attachment from . import Image, Attachment
from .._common import attrs_default, Image from .._common import attrs_default
from .. import _util from .. import _util

View File

@@ -1,5 +1,5 @@
import attr import attr
from ._attachment import Attachment from . import Attachment
from .._common import attrs_default from .._common import attrs_default
from typing import Any from typing import Any

View File

@@ -1,6 +1,6 @@
import attr import attr
from ._attachment import Attachment from . import Image, Attachment
from .._common import attrs_default, Image from .._common import attrs_default
@attrs_default @attrs_default

View File

@@ -2,25 +2,11 @@ import abc
import attr import attr
import collections import collections
import datetime import datetime
import enum from .._common import log, attrs_default
from .._common import log, attrs_default, Image
from .. import _util, _exception, _session, _graphql, _models from .. import _util, _exception, _session, _graphql, _models
from typing import MutableMapping, Mapping, Any, Iterable, Tuple, Optional from typing import MutableMapping, Mapping, Any, Iterable, Tuple, Optional
class ThreadLocation(enum.Enum):
"""Used to specify where a thread is located (inbox, pending, archived, other)."""
INBOX = "INBOX"
PENDING = "PENDING"
ARCHIVED = "ARCHIVED"
OTHER = "OTHER"
@classmethod
def _parse(cls, value: str):
return cls(value.lstrip("FOLDER_"))
DEFAULT_COLOR = "#0084ff" DEFAULT_COLOR = "#0084ff"
SETABLE_COLORS = ( SETABLE_COLORS = (
DEFAULT_COLOR, DEFAULT_COLOR,

View File

@@ -2,7 +2,7 @@ import attr
import datetime import datetime
from ._abc import ThreadABC from ._abc import ThreadABC
from . import _user from . import _user
from .._common import attrs_default, Image from .._common import attrs_default
from .. import _util, _session, _graphql, _models from .. import _util, _session, _graphql, _models
from typing import Sequence, Iterable, Set, Mapping from typing import Sequence, Iterable, Set, Mapping
@@ -176,7 +176,7 @@ class GroupData(Group):
""" """
#: The group's picture #: The group's picture
photo = attr.ib(None, type=Image) photo = attr.ib(None, type="_models.Image")
#: The name of the group #: The name of the group
name = attr.ib(None, type=str) name = attr.ib(None, type=str)
#: When the group was last active / when the last message was sent #: When the group was last active / when the last message was sent
@@ -238,7 +238,7 @@ class GroupData(Group):
if data.get("group_approval_queue") if data.get("group_approval_queue")
else None, else None,
join_link=data["joinable_mode"].get("link"), join_link=data["joinable_mode"].get("link"),
photo=Image._from_uri_or_none(data["image"]), photo=_models.Image._from_uri_or_none(data["image"]),
name=data.get("name"), name=data.get("name"),
message_count=data.get("messages_count"), message_count=data.get("messages_count"),
last_active=last_active, last_active=last_active,

View File

@@ -1,7 +1,7 @@
import attr import attr
import datetime import datetime
from ._abc import ThreadABC from ._abc import ThreadABC
from .._common import attrs_default, Image from .._common import attrs_default
from .. import _session, _models from .. import _session, _models
@@ -32,7 +32,7 @@ class PageData(Page):
""" """
#: The page's picture #: The page's picture
photo = attr.ib(type=Image) photo = attr.ib(type="_models.Image")
#: The name of the page #: The name of the page
name = attr.ib(type=str) name = attr.ib(type=str)
#: When the thread was last active / when the last message was sent #: When the thread was last active / when the last message was sent
@@ -70,7 +70,7 @@ class PageData(Page):
url=data.get("url"), url=data.get("url"),
city=data.get("city").get("name"), city=data.get("city").get("name"),
category=data.get("category_type"), category=data.get("category_type"),
photo=Image._from_uri(data["profile_picture"]), photo=_models.Image._from_uri(data["profile_picture"]),
name=data["name"], name=data["name"],
message_count=data.get("messages_count"), message_count=data.get("messages_count"),
plan=plan, plan=plan,

View File

@@ -1,7 +1,7 @@
import attr import attr
import datetime import datetime
from ._abc import ThreadABC from ._abc import ThreadABC
from .._common import log, attrs_default, Image from .._common import log, attrs_default
from .. import _util, _session, _models from .. import _util, _session, _models
@@ -100,7 +100,7 @@ class UserData(User):
""" """
#: The user's picture #: The user's picture
photo = attr.ib(type=Image) photo = attr.ib(type="_models.Image")
#: The name of the user #: The name of the user
name = attr.ib(type=str) name = attr.ib(type=str)
#: Whether the user and the client are friends #: Whether the user and the client are friends
@@ -162,7 +162,7 @@ class UserData(User):
color=c_info["color"], color=c_info["color"],
emoji=c_info["emoji"], emoji=c_info["emoji"],
own_nickname=c_info.get("own_nickname"), own_nickname=c_info.get("own_nickname"),
photo=Image._from_uri(data["profile_picture"]), photo=_models.Image._from_uri(data["profile_picture"]),
name=data["name"], name=data["name"],
message_count=data.get("messages_count"), message_count=data.get("messages_count"),
plan=plan, plan=plan,
@@ -196,7 +196,7 @@ class UserData(User):
color=c_info["color"], color=c_info["color"],
emoji=c_info["emoji"], emoji=c_info["emoji"],
own_nickname=c_info.get("own_nickname"), own_nickname=c_info.get("own_nickname"),
photo=Image._from_uri(user["big_image_src"]), photo=_models.Image._from_uri(user["big_image_src"]),
message_count=data["messages_count"], message_count=data["messages_count"],
last_active=_util.millis_to_datetime(int(data["updated_time_precise"])), last_active=_util.millis_to_datetime(int(data["updated_time_precise"])),
plan=plan, plan=plan,
@@ -209,27 +209,8 @@ class UserData(User):
id=data["id"], id=data["id"],
first_name=data["firstName"], first_name=data["firstName"],
url=data["uri"], url=data["uri"],
photo=Image(url=data["thumbSrc"]), photo=_models.Image(url=data["thumbSrc"]),
name=data["name"], name=data["name"],
is_friend=data["is_friend"], is_friend=data["is_friend"],
gender=GENDERS.get(data["gender"]), gender=GENDERS.get(data["gender"]),
) )
@attrs_default
class ActiveStatus:
#: Whether the user is active now
active = attr.ib(None, type=bool)
#: Datetime when the user was last active
last_active = attr.ib(None, type=datetime.datetime)
#: Whether the user is playing Messenger game now
in_game = attr.ib(None, type=bool)
@classmethod
def _from_orca_presence(cls, data):
# TODO: Handle `c` and `vc` keys (Probably some binary data)
return cls(
active=data["p"] in [2, 3],
last_active=_util.seconds_to_datetime(data["l"]) if "l" in data else None,
in_game=None,
)

View File

@@ -1,7 +1,7 @@
import pytest import pytest
import datetime import datetime
import fbchat import fbchat
from fbchat import UnsentMessage, ShareAttachment from fbchat import Image, UnsentMessage, ShareAttachment
from fbchat._models._message import graphql_to_extensible_attachment from fbchat._models._message import graphql_to_extensible_attachment
@@ -122,7 +122,7 @@ def test_share_from_graphql_link_with_image():
" Share photos and videos, send messages and get updates." " Share photos and videos, send messages and get updates."
), ),
source=None, source=None,
image=fbchat.Image( image=Image(
url="https://www.facebook.com/rsrc.php/v3/x.png", width=325, height=325 url="https://www.facebook.com/rsrc.php/v3/x.png", width=325, height=325
), ),
original_image_url="https://www.facebook.com/rsrc.php/v3/x.png", original_image_url="https://www.facebook.com/rsrc.php/v3/x.png",
@@ -184,7 +184,7 @@ def test_share_from_graphql_video():
" Subscribe to the official Rick As..." " Subscribe to the official Rick As..."
), ),
source="youtube.com", source="youtube.com",
image=fbchat.Image( image=Image(
url="https://external-arn2-1.xx.fbcdn.net/safe_image.php?d=xyz123" url="https://external-arn2-1.xx.fbcdn.net/safe_image.php?d=xyz123"
"&w=960&h=540&url=https%3A%2F%2Fi.ytimg.com%2Fvi%2FdQw4w9WgXcQ" "&w=960&h=540&url=https%3A%2F%2Fi.ytimg.com%2Fvi%2FdQw4w9WgXcQ"
"%2Fmaxresdefault.jpg&sx=0&sy=0&sw=1280&sh=720&_nc_hash=abc123", "%2Fmaxresdefault.jpg&sx=0&sy=0&sw=1280&sh=720&_nc_hash=abc123",
@@ -307,7 +307,7 @@ def test_share_with_image_subattachment():
title="", title="",
description="Abc", description="Abc",
source="Def", source="Def",
image=fbchat.Image( image=Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t1.0-9/1.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t1.0-9/1.jpg",
width=720, width=720,
height=960, height=960,
@@ -435,7 +435,7 @@ def test_share_with_video_subattachment():
title="", title="",
description="Abc", description="Abc",
source="Def", source="Def",
image=fbchat.Image( image=Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg",
width=960, width=960,
height=540, height=540,
@@ -447,7 +447,7 @@ def test_share_with_video_subattachment():
duration=datetime.timedelta(seconds=24, microseconds=469000), duration=datetime.timedelta(seconds=24, microseconds=469000),
preview_url="https://video-arn2-1.xx.fbcdn.net/v/t42.9040-2/vid.mp4", preview_url="https://video-arn2-1.xx.fbcdn.net/v/t42.9040-2/vid.mp4",
previews={ previews={
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg",
width=960, width=960,
height=540, height=540,

View File

@@ -1,6 +1,12 @@
import datetime import datetime
import fbchat import fbchat
from fbchat import FileAttachment, AudioAttachment, ImageAttachment, VideoAttachment from fbchat import (
Image,
FileAttachment,
AudioAttachment,
ImageAttachment,
VideoAttachment,
)
from fbchat._models._file import graphql_to_attachment, graphql_to_subattachment from fbchat._models._file import graphql_to_attachment, graphql_to_subattachment
@@ -28,13 +34,13 @@ def test_imageattachment_from_list():
width=2833, width=2833,
height=1367, height=1367,
previews={ previews={
fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/s261x260/1.jpg"), Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/s261x260/1.jpg"),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/2.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/2.jpg",
width=960, width=960,
height=463, height=463,
), ),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/s2048x2048/3.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/s2048x2048/3.jpg",
width=2048, width=2048,
height=988, height=988,
@@ -68,15 +74,15 @@ def test_videoattachment_from_list():
width=640, width=640,
height=368, height=368,
previews={ previews={
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/p261x260/1.jpg" url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/p261x260/1.jpg"
), ),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/2.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/2.jpg",
width=640, width=640,
height=368, height=368,
), ),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/3.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.3394-10/3.jpg",
width=640, width=640,
height=368, height=368,
@@ -169,8 +175,8 @@ def test_graphql_to_attachment_image1():
height=None, height=None,
is_animated=False, is_animated=False,
previews={ previews={
fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/p50x50/2.png"), Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/p50x50/2.png"),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/1.png", url="https://scontent-arn2-1.xx.fbcdn.net/v/1.png",
width=128, width=128,
height=128, height=128,
@@ -204,9 +210,7 @@ def test_graphql_to_attachment_image2():
width=None, width=None,
height=None, height=None,
is_animated=True, is_animated=True,
previews={ previews={Image(url="https://cdn.fbsbx.com/v/1.gif", width=128, height=128)},
fbchat.Image(url="https://cdn.fbsbx.com/v/1.gif", width=128, height=128)
},
) == graphql_to_attachment(data) ) == graphql_to_attachment(data)
@@ -244,17 +248,17 @@ def test_graphql_to_attachment_video():
duration=datetime.timedelta(seconds=6), duration=datetime.timedelta(seconds=6),
preview_url="https://video-arn2-1.xx.fbcdn.net/v/video-4321.mp4", preview_url="https://video-arn2-1.xx.fbcdn.net/v/video-4321.mp4",
previews={ previews={
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/s168x128/1.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/s168x128/1.jpg",
width=168, width=168,
height=96, height=96,
), ),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/p261x260/3.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/p261x260/3.jpg",
width=452, width=452,
height=260, height=260,
), ),
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/2.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/2.jpg",
width=640, width=640,
height=368, height=368,
@@ -345,7 +349,7 @@ def test_graphql_to_subattachment_video():
duration=datetime.timedelta(seconds=24, microseconds=469000), duration=datetime.timedelta(seconds=24, microseconds=469000),
preview_url="https://video-arn2-1.xx.fbcdn.net/v/t42.9040-2/vid.mp4", preview_url="https://video-arn2-1.xx.fbcdn.net/v/t42.9040-2/vid.mp4",
previews={ previews={
fbchat.Image( Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg", url="https://scontent-arn2-1.xx.fbcdn.net/v/t15.5256-10/p180x540/1.jpg",
width=960, width=960,
height=540, height=540,

View File

@@ -1,7 +1,7 @@
import pytest import pytest
import datetime import datetime
import fbchat import fbchat
from fbchat import LocationAttachment, LiveLocationAttachment from fbchat import Image, LocationAttachment, LiveLocationAttachment
def test_location_attachment_from_graphql(): def test_location_attachment_from_graphql():
@@ -38,7 +38,7 @@ def test_location_attachment_from_graphql():
id=400828513928715, id=400828513928715,
latitude=55.4, latitude=55.4,
longitude=12.4322, longitude=12.4322,
image=fbchat.Image( image=Image(
url="https://external-arn2-1.xx.fbcdn.net/static_map.php?v=1020&osm_provider=2&size=545x280&zoom=15&markers=55.40000000%2C12.43220000&language=en", url="https://external-arn2-1.xx.fbcdn.net/static_map.php?v=1020&osm_provider=2&size=545x280&zoom=15&markers=55.40000000%2C12.43220000&language=en",
width=545, width=545,
height=280, height=280,

View File

@@ -1,6 +1,6 @@
import pytest import pytest
import fbchat import fbchat
from fbchat import Sticker from fbchat import Image, Sticker
def test_from_graphql_none(): def test_from_graphql_none():
@@ -20,7 +20,7 @@ def test_from_graphql_normal():
frames_per_col=1, frames_per_col=1,
frame_count=1, frame_count=1,
frame_rate=83, frame_rate=83,
image=fbchat.Image( image=Image(
url="https://scontent-arn2-1.xx.fbcdn.net/v/redacted.png", url="https://scontent-arn2-1.xx.fbcdn.net/v/redacted.png",
width=274, width=274,
height=274, height=274,
@@ -57,7 +57,7 @@ def test_from_graphql_animated():
frames_per_col=2, frames_per_col=2,
frame_count=4, frame_count=4,
frame_rate=142, frame_rate=142,
image=fbchat.Image( image=Image(
url="https://scontent-arn2-1.fbcdn.net/v/redacted1.png", url="https://scontent-arn2-1.fbcdn.net/v/redacted1.png",
width=240, width=240,
height=293, height=293,