diff --git a/docs/conf.py b/docs/conf.py index 9a50500..f2763f1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -174,5 +174,5 @@ html_sidebars = {"**": ["sidebar.html", "searchbox.html"]} html_show_sphinx = False html_show_sourcelink = False -autoclass_content = "init" +autoclass_content = "both" html_short_title = description diff --git a/fbchat/_attachment.py b/fbchat/_attachment.py index 20cd50e..4ee40b2 100644 --- a/fbchat/_attachment.py +++ b/fbchat/_attachment.py @@ -1,73 +1,48 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr + +@attr.s(cmp=False) class Attachment(object): + """Represents a Facebook attachment""" + #: The attachment ID - uid = None - - def __init__(self, uid=None): - """Represents a Facebook attachment""" - self.uid = uid + uid = attr.ib(None) +@attr.s(cmp=False) class UnsentMessage(Attachment): - def __init__(self, *args, **kwargs): - """Represents an unsent message attachment""" - super(UnsentMessage, self).__init__(*args, **kwargs) + """Represents an unsent message attachment""" +@attr.s(cmp=False) class ShareAttachment(Attachment): - #: ID of the author of the shared post - author = None - #: Target URL - url = None - #: Original URL if Facebook redirects the URL - original_url = None - #: Title of the attachment - title = None - #: Description of the attachment - description = None - #: Name of the source - source = None - #: URL of the attachment image - image_url = None - #: URL of the original image if Facebook uses `safe_image` - original_image_url = None - #: Width of the image - image_width = None - #: Height of the image - image_height = None - #: List of additional attachments - attachments = None + """Represents a shared item (eg. URL) that has been sent as a Facebook attachment""" - def __init__( - self, - author=None, - url=None, - original_url=None, - title=None, - description=None, - source=None, - image_url=None, - original_image_url=None, - image_width=None, - image_height=None, - attachments=None, - **kwargs - ): - """Represents a shared item (eg. URL) that has been sent as a Facebook attachment""" - super(ShareAttachment, self).__init__(**kwargs) - self.author = author - self.url = url - self.original_url = original_url - self.title = title - self.description = description - self.source = source - self.image_url = image_url - self.original_image_url = original_image_url - self.image_width = image_width - self.image_height = image_height - if attachments is None: - attachments = [] - self.attachments = attachments + #: ID of the author of the shared post + author = attr.ib(None) + #: Target URL + url = attr.ib(None) + #: Original URL if Facebook redirects the URL + original_url = attr.ib(None) + #: Title of the attachment + title = attr.ib(None) + #: Description of the attachment + description = attr.ib(None) + #: Name of the source + source = attr.ib(None) + #: URL of the attachment image + image_url = attr.ib(None) + #: URL of the original image if Facebook uses `safe_image` + original_image_url = attr.ib(None) + #: Width of the image + image_width = attr.ib(None) + #: Height of the image + image_height = attr.ib(None) + #: List of additional attachments + attachments = attr.ib(factory=list, converter=lambda x: [] if x is None else x) + + # Put here for backwards compatibility, so that the init argument order is preserved + uid = attr.ib(None) diff --git a/fbchat/_file.py b/fbchat/_file.py index 9acfd11..85b2055 100644 --- a/fbchat/_file.py +++ b/fbchat/_file.py @@ -1,83 +1,85 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._attachment import Attachment +@attr.s(cmp=False) class FileAttachment(Attachment): + """Represents a file that has been sent as a Facebook attachment""" + #: Url where you can download the file - url = None + url = attr.ib(None) #: Size of the file in bytes - size = None + size = attr.ib(None) #: Name of the file - name = None + name = attr.ib(None) #: Whether Facebook determines that this file may be harmful - is_malicious = None + is_malicious = attr.ib(None) - def __init__(self, url=None, size=None, name=None, is_malicious=None, **kwargs): - """Represents a file that has been sent as a Facebook attachment""" - super(FileAttachment, self).__init__(**kwargs) - self.url = url - self.size = size - self.name = name - self.is_malicious = is_malicious + # Put here for backwards compatibility, so that the init argument order is preserved + uid = attr.ib(None) +@attr.s(cmp=False) class AudioAttachment(Attachment): + """Represents an audio file that has been sent as a Facebook attachment""" + #: Name of the file - filename = None + filename = attr.ib(None) #: Url of the audio file - url = None + url = attr.ib(None) #: Duration of the audioclip in milliseconds - duration = None + duration = attr.ib(None) #: Audio type - audio_type = None + audio_type = attr.ib(None) - def __init__( - self, filename=None, url=None, duration=None, audio_type=None, **kwargs - ): - """Represents an audio file that has been sent as a Facebook attachment""" - super(AudioAttachment, self).__init__(**kwargs) - self.filename = filename - self.url = url - self.duration = duration - self.audio_type = audio_type + # Put here for backwards compatibility, so that the init argument order is preserved + uid = attr.ib(None) +@attr.s(cmp=False, init=False) class ImageAttachment(Attachment): + """Represents an image that has been sent as a Facebook attachment + + To retrieve the full image url, use: :func:`fbchat.Client.fetchImageUrl`, and pass + it the uid of the image attachment + """ + #: The extension of the original image (eg. 'png') - original_extension = None + original_extension = attr.ib(None) #: Width of original image - width = None + width = attr.ib(None, converter=lambda x: None if x is None else int(x)) #: Height of original image - height = None + height = attr.ib(None, converter=lambda x: None if x is None else int(x)) #: Whether the image is animated - is_animated = None + is_animated = attr.ib(None) #: URL to a thumbnail of the image - thumbnail_url = None + thumbnail_url = attr.ib(None) #: URL to a medium preview of the image - preview_url = None + preview_url = attr.ib(None) #: Width of the medium preview image - preview_width = None + preview_width = attr.ib(None) #: Height of the medium preview image - preview_height = None + preview_height = attr.ib(None) #: URL to a large preview of the image - large_preview_url = None + large_preview_url = attr.ib(None) #: Width of the large preview image - large_preview_width = None + large_preview_width = attr.ib(None) #: Height of the large preview image - large_preview_height = None + large_preview_height = attr.ib(None) #: URL to an animated preview of the image (eg. for gifs) - animated_preview_url = None + animated_preview_url = attr.ib(None) #: Width of the animated preview image - animated_preview_width = None + animated_preview_width = attr.ib(None) #: Height of the animated preview image - animated_preview_height = None + animated_preview_height = attr.ib(None) def __init__( self, @@ -91,11 +93,6 @@ class ImageAttachment(Attachment): animated_preview=None, **kwargs ): - """ - Represents an image that has been sent as a Facebook attachment - To retrieve the full image url, use: :func:`fbchat.Client.fetchImageUrl`, - and pass it the uid of the image attachment - """ super(ImageAttachment, self).__init__(**kwargs) self.original_extension = original_extension if width is not None: @@ -126,38 +123,41 @@ class ImageAttachment(Attachment): self.animated_preview_height = animated_preview.get("height") +@attr.s(cmp=False, init=False) class VideoAttachment(Attachment): + """Represents a video that has been sent as a Facebook attachment""" + #: Size of the original video in bytes - size = None + size = attr.ib(None) #: Width of original video - width = None + width = attr.ib(None) #: Height of original video - height = None + height = attr.ib(None) #: Length of video in milliseconds - duration = None + duration = attr.ib(None) #: URL to very compressed preview video - preview_url = None + preview_url = attr.ib(None) #: URL to a small preview image of the video - small_image_url = None + small_image_url = attr.ib(None) #: Width of the small preview image - small_image_width = None + small_image_width = attr.ib(None) #: Height of the small preview image - small_image_height = None + small_image_height = attr.ib(None) #: URL to a medium preview image of the video - medium_image_url = None + medium_image_url = attr.ib(None) #: Width of the medium preview image - medium_image_width = None + medium_image_width = attr.ib(None) #: Height of the medium preview image - medium_image_height = None + medium_image_height = attr.ib(None) #: URL to a large preview image of the video - large_image_url = None + large_image_url = attr.ib(None) #: Width of the large preview image - large_image_width = None + large_image_width = attr.ib(None) #: Height of the large preview image - large_image_height = None + large_image_height = attr.ib(None) def __init__( self, @@ -171,7 +171,6 @@ class VideoAttachment(Attachment): large_image=None, **kwargs ): - """Represents a video that has been sent as a Facebook attachment""" super(VideoAttachment, self).__init__(**kwargs) self.size = size self.width = width diff --git a/fbchat/_group.py b/fbchat/_group.py index 1a21bf3..62cf020 100644 --- a/fbchat/_group.py +++ b/fbchat/_group.py @@ -1,26 +1,32 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._thread import ThreadType, Thread +@attr.s(cmp=False, init=False) class Group(Thread): + """Represents a Facebook group. Inherits `Thread`""" + #: Unique list (set) of the group thread's participant user IDs - participants = None + participants = attr.ib(factory=set, converter=lambda x: set() if x is None else x) #: A dict, containing user nicknames mapped to their IDs - nicknames = None + nicknames = attr.ib(factory=dict, converter=lambda x: {} if x is None else x) #: A :class:`ThreadColor`. The groups's message color - color = None + color = attr.ib(None) #: The groups's default emoji - emoji = None + emoji = attr.ib(None) # Set containing user IDs of thread admins - admins = None + admins = attr.ib(factory=set, converter=lambda x: set() if x is None else x) # True if users need approval to join - approval_mode = None + approval_mode = attr.ib(None) # Set containing user IDs requesting to join - approval_requests = None + approval_requests = attr.ib( + factory=set, converter=lambda x: set() if x is None else x + ) # Link for joining group - join_link = None + join_link = attr.ib(None) def __init__( self, @@ -36,7 +42,6 @@ class Group(Thread): privacy_mode=None, **kwargs ): - """Represents a Facebook group. Inherits `Thread`""" super(Group, self).__init__(ThreadType.GROUP, uid, **kwargs) if participants is None: participants = set() @@ -56,12 +61,14 @@ class Group(Thread): self.join_link = join_link +@attr.s(cmp=False, init=False) class Room(Group): + """Deprecated. Use :class:`Group` instead""" + # True is room is not discoverable - privacy_mode = None + privacy_mode = attr.ib(None) def __init__(self, uid, privacy_mode=None, **kwargs): - """Deprecated. Use :class:`Group` instead""" super(Room, self).__init__(uid, **kwargs) self.type = ThreadType.ROOM self.privacy_mode = privacy_mode diff --git a/fbchat/_location.py b/fbchat/_location.py index b45a942..5361bb5 100644 --- a/fbchat/_location.py +++ b/fbchat/_location.py @@ -1,45 +1,48 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._attachment import Attachment +@attr.s(cmp=False) class LocationAttachment(Attachment): - """Latitude and longitude OR address is provided by Facebook""" + """Represents a user location + + Latitude and longitude OR address is provided by Facebook + """ #: Latitude of the location - latitude = None + latitude = attr.ib(None) #: Longitude of the location - longitude = None + longitude = attr.ib(None) #: URL of image showing the map of the location - image_url = None + image_url = attr.ib(None, init=False) #: Width of the image - image_width = None + image_width = attr.ib(None, init=False) #: Height of the image - image_height = None + image_height = attr.ib(None, init=False) #: URL to Bing maps with the location - url = None + url = attr.ib(None, init=False) # Address of the location - address = None + address = attr.ib(None) - def __init__(self, latitude=None, longitude=None, address=None, **kwargs): - """Represents a user location""" - super(LocationAttachment, self).__init__(**kwargs) - self.latitude = latitude - self.longitude = longitude - self.address = address + # Put here for backwards compatibility, so that the init argument order is preserved + uid = attr.ib(None) +@attr.s(cmp=False, init=False) class LiveLocationAttachment(LocationAttachment): + """Represents a live user location""" + #: Name of the location - name = None + name = attr.ib(None) #: Timestamp when live location expires - expiration_time = None + expiration_time = attr.ib(None) #: True if live location is expired - is_expired = None + is_expired = attr.ib(None) def __init__(self, name=None, expiration_time=None, is_expired=None, **kwargs): - """Represents a live user location""" super(LiveLocationAttachment, self).__init__(**kwargs) self.expiration_time = expiration_time self.is_expired = is_expired diff --git a/fbchat/_message.py b/fbchat/_message.py index c26b772..3f6f03d 100644 --- a/fbchat/_message.py +++ b/fbchat/_message.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from string import Formatter from ._core import Enum @@ -25,92 +26,48 @@ class MessageReaction(Enum): NO = "👎" +@attr.s(cmp=False) class Mention(object): + """Represents a @mention""" + #: The thread ID the mention is pointing at - thread_id = None + thread_id = attr.ib() #: The character where the mention starts - offset = None + offset = attr.ib(0) #: The length of the mention - length = None - - def __init__(self, thread_id, offset=0, length=10): - """Represents a @mention""" - self.thread_id = thread_id - self.offset = offset - self.length = length - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.thread_id, self.offset, self.length - ) + length = attr.ib(10) +@attr.s(cmp=False) class Message(object): + """Represents a Facebook message""" + #: The actual message - text = None + text = attr.ib(None) #: A list of :class:`Mention` objects - mentions = None + mentions = attr.ib(factory=list, converter=lambda x: [] if x is None else x) #: A :class:`EmojiSize`. Size of a sent emoji - emoji_size = None + emoji_size = attr.ib(None) #: The message ID - uid = None + uid = attr.ib(None, init=False) #: ID of the sender - author = None + author = attr.ib(None, init=False) #: Timestamp of when the message was sent - timestamp = None + timestamp = attr.ib(None, init=False) #: Whether the message is read - is_read = None + is_read = attr.ib(None, init=False) #: A list of pepole IDs who read the message, works only with :func:`fbchat.Client.fetchThreadMessages` - read_by = None + read_by = attr.ib(factory=list, init=False) #: A dict with user's IDs as keys, and their :class:`MessageReaction` as values - reactions = None - #: The actual message - text = None + reactions = attr.ib(factory=dict, init=False) #: A :class:`Sticker` - sticker = None + sticker = attr.ib(None) #: A list of attachments - attachments = None + attachments = attr.ib(factory=list, converter=lambda x: [] if x is None else x) #: A list of :class:`QuickReply` - quick_replies = None + quick_replies = attr.ib(factory=list, converter=lambda x: [] if x is None else x) #: Whether the message is unsent (deleted for everyone) - unsent = None - - def __init__( - self, - text=None, - mentions=None, - emoji_size=None, - sticker=None, - attachments=None, - quick_replies=None, - ): - """Represents a Facebook message""" - self.text = text - if mentions is None: - mentions = [] - self.mentions = mentions - self.emoji_size = emoji_size - self.sticker = sticker - if attachments is None: - attachments = [] - self.attachments = attachments - if quick_replies is None: - quick_replies = [] - self.quick_replies = quick_replies - self.reactions = {} - self.read_by = [] - self.deleted = False - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.uid, repr(self.text), self.mentions, self.emoji_size, self.attachments - ) + unsent = attr.ib(False, init=False) @classmethod def formatMentions(cls, text, *args, **kwargs): diff --git a/fbchat/_page.py b/fbchat/_page.py index 53a2bf1..9c696e0 100644 --- a/fbchat/_page.py +++ b/fbchat/_page.py @@ -1,20 +1,24 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._thread import ThreadType, Thread +@attr.s(cmp=False, init=False) class Page(Thread): + """Represents a Facebook page. Inherits `Thread`""" + #: The page's custom url - url = None + url = attr.ib(None) #: The name of the page's location city - city = None + city = attr.ib(None) #: Amount of likes the page has - likes = None + likes = attr.ib(None) #: Some extra information about the page - sub_title = None + sub_title = attr.ib(None) #: The page's category - category = None + category = attr.ib(None) def __init__( self, @@ -26,7 +30,6 @@ class Page(Thread): category=None, **kwargs ): - """Represents a Facebook page. Inherits `Thread`""" super(Page, self).__init__(ThreadType.PAGE, uid, **kwargs) self.url = url self.city = city diff --git a/fbchat/_plan.py b/fbchat/_plan.py index d9524dc..b6f7826 100644 --- a/fbchat/_plan.py +++ b/fbchat/_plan.py @@ -1,46 +1,28 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr + +@attr.s(cmp=False) class Plan(object): + """Represents a plan""" + #: ID of the plan - uid = None + uid = attr.ib(None, init=False) #: Plan time (unix time stamp), only precise down to the minute - time = None + time = attr.ib(converter=int) #: Plan title - title = None + title = attr.ib() #: Plan location name - location = None + location = attr.ib(None, converter=lambda x: x or "") #: Plan location ID - location_id = None + location_id = attr.ib(None, converter=lambda x: x or "") #: ID of the plan creator - author_id = None + author_id = attr.ib(None, init=False) #: List of the people IDs who will take part in the plan - going = None + going = attr.ib(factory=list, init=False) #: List of the people IDs who won't take part in the plan - declined = None + declined = attr.ib(factory=list, init=False) #: List of the people IDs who are invited to the plan - invited = None - - def __init__(self, time, title, location=None, location_id=None): - """Represents a plan""" - self.time = int(time) - self.title = title - self.location = location or "" - self.location_id = location_id or "" - self.author_id = None - self.going = [] - self.declined = [] - self.invited = [] - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.uid, - repr(self.title), - self.time, - repr(self.location), - repr(self.location_id), - ) + invited = attr.ib(factory=list, init=False) diff --git a/fbchat/_poll.py b/fbchat/_poll.py index 1276e1a..c2c02c0 100644 --- a/fbchat/_poll.py +++ b/fbchat/_poll.py @@ -1,52 +1,34 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr + +@attr.s(cmp=False) class Poll(object): + """Represents a poll""" + #: ID of the poll - uid = None + uid = attr.ib(None, init=False) #: Title of the poll - title = None + title = attr.ib() #: List of :class:`PollOption`, can be fetched with :func:`fbchat.Client.fetchPollOptions` - options = None + options = attr.ib() #: Options count - options_count = None - - def __init__(self, title, options): - """Represents a poll""" - self.title = title - self.options = options - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.uid, repr(self.title), self.options - ) + options_count = attr.ib(None, init=False) +@attr.s(cmp=False) class PollOption(object): + """Represents a poll option""" + #: ID of the poll option - uid = None + uid = attr.ib(None, init=False) #: Text of the poll option - text = None + text = attr.ib() #: Whether vote when creating or client voted - vote = None + vote = attr.ib(False) #: ID of the users who voted for this poll option - voters = None + voters = attr.ib(None, init=False) #: Votes count - votes_count = None - - def __init__(self, text, vote=False): - """Represents a poll option""" - self.text = text - self.vote = vote - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.uid, repr(self.text), self.voters - ) + votes_count = attr.ib(None, init=False) diff --git a/fbchat/_quick_reply.py b/fbchat/_quick_reply.py index 3c3cbf1..60323bf 100644 --- a/fbchat/_quick_reply.py +++ b/fbchat/_quick_reply.py @@ -1,76 +1,76 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._attachment import Attachment +@attr.s(cmp=False) class QuickReply(object): + """Represents a quick reply""" + #: Payload of the quick reply - payload = None + payload = attr.ib(None) #: External payload for responses - external_payload = None + external_payload = attr.ib(None, init=False) #: Additional data - data = None + data = attr.ib(None) #: Whether it's a response for a quick reply - is_response = None - - def __init__(self, payload=None, data=None, is_response=False): - """Represents a quick reply""" - self.payload = payload - self.data = data - self.is_response = is_response - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "<{}: payload={!r}>".format(self.__class__.__name__, self.payload) + is_response = attr.ib(False) +@attr.s(cmp=False, init=False) class QuickReplyText(QuickReply): + """Represents a text quick reply""" + #: Title of the quick reply - title = None + title = attr.ib(None) #: URL of the quick reply image (optional) - image_url = None + image_url = attr.ib(None) #: Type of the quick reply _type = "text" def __init__(self, title=None, image_url=None, **kwargs): - """Represents a text quick reply""" super(QuickReplyText, self).__init__(**kwargs) self.title = title self.image_url = image_url +@attr.s(cmp=False, init=False) class QuickReplyLocation(QuickReply): + """Represents a location quick reply (Doesn't work on mobile)""" + #: Type of the quick reply _type = "location" def __init__(self, **kwargs): - """Represents a location quick reply (Doesn't work on mobile)""" super(QuickReplyLocation, self).__init__(**kwargs) self.is_response = False +@attr.s(cmp=False, init=False) class QuickReplyPhoneNumber(QuickReply): + """Represents a phone number quick reply (Doesn't work on mobile)""" + #: URL of the quick reply image (optional) - image_url = None + image_url = attr.ib(None) #: Type of the quick reply _type = "user_phone_number" def __init__(self, image_url=None, **kwargs): - """Represents a phone number quick reply (Doesn't work on mobile)""" super(QuickReplyPhoneNumber, self).__init__(**kwargs) self.image_url = image_url +@attr.s(cmp=False, init=False) class QuickReplyEmail(QuickReply): + """Represents an email quick reply (Doesn't work on mobile)""" + #: URL of the quick reply image (optional) - image_url = None + image_url = attr.ib(None) #: Type of the quick reply _type = "user_email" def __init__(self, image_url=None, **kwargs): - """Represents an email quick reply (Doesn't work on mobile)""" super(QuickReplyEmail, self).__init__(**kwargs) self.image_url = image_url diff --git a/fbchat/_sticker.py b/fbchat/_sticker.py index e575681..e90655d 100644 --- a/fbchat/_sticker.py +++ b/fbchat/_sticker.py @@ -1,36 +1,39 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._attachment import Attachment +@attr.s(cmp=False, init=False) class Sticker(Attachment): + """Represents a Facebook sticker that has been sent to a thread as an attachment""" + #: The sticker-pack's ID - pack = None + pack = attr.ib(None) #: Whether the sticker is animated - is_animated = False + is_animated = attr.ib(False) # If the sticker is animated, the following should be present #: URL to a medium spritemap - medium_sprite_image = None + medium_sprite_image = attr.ib(None) #: URL to a large spritemap - large_sprite_image = None + large_sprite_image = attr.ib(None) #: The amount of frames present in the spritemap pr. row - frames_per_row = None + frames_per_row = attr.ib(None) #: The amount of frames present in the spritemap pr. coloumn - frames_per_col = None + frames_per_col = attr.ib(None) #: The frame rate the spritemap is intended to be played in - frame_rate = None + frame_rate = attr.ib(None) #: URL to the sticker's image - url = None + url = attr.ib(None) #: Width of the sticker - width = None + width = attr.ib(None) #: Height of the sticker - height = None + height = attr.ib(None) #: The sticker's label/name - label = None + label = attr.ib(None) - def __init__(self, *args, **kwargs): - """Represents a Facebook sticker that has been sent to a Facebook thread as an attachment""" - super(Sticker, self).__init__(*args, **kwargs) + def __init__(self, uid=None): + super(Sticker, self).__init__(uid=uid) diff --git a/fbchat/_thread.py b/fbchat/_thread.py index 37efd6d..6b4641e 100644 --- a/fbchat/_thread.py +++ b/fbchat/_thread.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._core import Enum @@ -42,21 +43,24 @@ class ThreadColor(Enum): BILOBA_FLOWER = "#a695c7" +@attr.s(cmp=False, init=False) class Thread(object): + """Represents a Facebook thread""" + #: The unique identifier of the thread. Can be used a `thread_id`. See :ref:`intro_threads` for more info - uid = None + uid = attr.ib(converter=str) #: Specifies the type of thread. Can be used a `thread_type`. See :ref:`intro_threads` for more info - type = None + type = attr.ib() #: A url to the thread's picture - photo = None + photo = attr.ib(None) #: The name of the thread - name = None + name = attr.ib(None) #: Timestamp of last message - last_message_timestamp = None + last_message_timestamp = attr.ib(None) #: Number of messages in the thread - message_count = None + message_count = attr.ib(None) #: Set :class:`Plan` - plan = None + plan = attr.ib(None) def __init__( self, @@ -68,7 +72,6 @@ class Thread(object): message_count=None, plan=None, ): - """Represents a Facebook thread""" self.uid = str(uid) self.type = _type self.photo = photo @@ -76,9 +79,3 @@ class Thread(object): self.last_message_timestamp = last_message_timestamp self.message_count = message_count self.plan = plan - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "<{} {} ({})>".format(self.type.name, self.name, self.uid) diff --git a/fbchat/_user.py b/fbchat/_user.py index 75a95c6..26e8f4d 100644 --- a/fbchat/_user.py +++ b/fbchat/_user.py @@ -1,6 +1,7 @@ # -*- coding: UTF-8 -*- from __future__ import unicode_literals +import attr from ._core import Enum from ._thread import ThreadType, Thread @@ -12,27 +13,30 @@ class TypingStatus(Enum): TYPING = 1 +@attr.s(cmp=False, init=False) class User(Thread): + """Represents a Facebook user. Inherits `Thread`""" + #: The profile url - url = None + url = attr.ib(None) #: The users first name - first_name = None + first_name = attr.ib(None) #: The users last name - last_name = None + last_name = attr.ib(None) #: Whether the user and the client are friends - is_friend = None + is_friend = attr.ib(None) #: The user's gender - gender = None + gender = attr.ib(None) #: From 0 to 1. How close the client is to the user - affinity = None + affinity = attr.ib(None) #: The user's nickname - nickname = None + nickname = attr.ib(None) #: The clients nickname, as seen by the user - own_nickname = None + own_nickname = attr.ib(None) #: A :class:`ThreadColor`. The message color - color = None + color = attr.ib(None) #: The default emoji - emoji = None + emoji = attr.ib(None) def __init__( self, @@ -49,7 +53,6 @@ class User(Thread): emoji=None, **kwargs ): - """Represents a Facebook user. Inherits `Thread`""" super(User, self).__init__(ThreadType.USER, uid, **kwargs) self.url = url self.first_name = first_name @@ -63,23 +66,11 @@ class User(Thread): self.emoji = emoji +@attr.s(cmp=False) class ActiveStatus(object): #: Whether the user is active now - active = None + active = attr.ib(None) #: Timestamp when the user was last active - last_active = None + last_active = attr.ib(None) #: Whether the user is playing Messenger game now - in_game = None - - def __init__(self, active=None, last_active=None, in_game=None): - self.active = active - self.last_active = last_active - self.in_game = in_game - - def __repr__(self): - return self.__unicode__() - - def __unicode__(self): - return "".format( - self.active, self.last_active, self.in_game - ) + in_game = attr.ib(None) diff --git a/pyproject.toml b/pyproject.toml index d1cc257..0e32539 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ maintainer-email = "madsmtm@gmail.com" home-page = "https://github.com/carpedm20/fbchat/" requires = [ "aenum", + "attrs~=18.2.0", "requests", "beautifulsoup4", ]