Browse Source

Remove Message.timestamp and make Message.channel_mentions lazy.

Message.timestamp is replaced with Message.created_at. This commit
also affects how MESSAGE_UPDATE is handled by only assuming that two
keys are provided rather than overwriting data with missing keys.
pull/447/head
Rapptz 9 years ago
parent
commit
aa8a328f0a
  1. 106
      discord/message.py

106
discord/message.py

@ -39,11 +39,9 @@ class Message:
Attributes
-----------
edited_timestamp : Optional[datetime.datetime]
edited_timestamp: Optional[datetime.datetime]
A naive UTC datetime object containing the edited time of the message.
timestamp : datetime.datetime
A naive UTC datetime object containing the time the message was created.
tts : bool
tts: bool
Specifies if the message was done with text-to-speech.
type: :class:`MessageType`
The type of message. In most cases this should not be checked, but it is helpful
@ -51,12 +49,12 @@ class Message:
author
A :class:`Member` that sent the message. If :attr:`channel` is a
private channel, then it is a :class:`User` instead.
content : str
content: str
The actual contents of the message.
nonce
The value used by the discord server and the client to verify that the message is successfully sent.
This is typically non-important.
embeds : list
embeds: list
A list of embedded objects. The elements are objects that meet oEmbed's specification_.
.. _specification: http://oembed.com/
@ -66,12 +64,12 @@ class Message:
In :issue:`very rare cases <21>` this could be a :class:`Object` instead.
For the sake of convenience, this :class:`Object` instance has an attribute ``is_private`` set to ``True``.
server : Optional[:class:`Server`]
server: Optional[:class:`Server`]
The server that the message belongs to. If not applicable (i.e. a PM) then it's None instead.
call: Optional[:class:`CallMessage`]
The call that the message refers to. This is only applicable to messages of type
:attr:`MessageType.call`.
mention_everyone : bool
mention_everyone: bool
Specifies if the message mentions everyone.
.. note::
@ -91,15 +89,18 @@ class Message:
The order of the mentions list is not in any particular order so you should
not rely on it. This is a discord limitation, not one with the library.
channel_mentions : list
channel_mentions: list
A list of :class:`Channel` that were mentioned. If the message is in a private message
then the list is always empty.
role_mentions : list
role_mentions: list
A list of :class:`Role` that were mentioned. If the message is in a private message
then the list is always empty.
id : str
id: str
The message ID.
attachments : list
webhook_id: Optional[str]
If this message was sent by a webhook, then this is the webhook ID's that sent this
message.
attachments: list
A list of attachments given to a message.
pinned: bool
Specifies if the message is currently pinned.
@ -107,9 +108,9 @@ class Message:
Reactions to a message. Reactions can be either custom emoji or standard unicode emoji.
"""
__slots__ = ( 'edited_timestamp', 'timestamp', 'tts', 'content', 'channel',
__slots__ = ( 'edited_timestamp', 'tts', 'content', 'channel', 'webhook_id',
'mention_everyone', 'embeds', 'id', 'mentions', 'author',
'channel_mentions', 'server', '_cs_raw_mentions', 'attachments',
'_cs_channel_mentions', 'server', '_cs_raw_mentions', 'attachments',
'_cs_clean_content', '_cs_raw_channel_mentions', 'nonce', 'pinned',
'role_mentions', '_cs_raw_role_mentions', 'type', 'call',
'_cs_system_content', '_state', 'reactions' )
@ -121,27 +122,31 @@ class Message:
reaction.message = self
self._update(channel, data)
def _try_patch(self, data, key, transform):
try:
value = data[key]
except KeyError:
pass
else:
setattr(self, key, transform(value))
def _update(self, channel, data):
# at the moment, the timestamps seem to be naive so they have no time zone and operate on UTC time.
# we can use this to our advantage to use strptime instead of a complicated parsing routine.
# example timestamp: 2015-08-21T12:03:45.782000+00:00
# sometimes the .%f modifier is missing
self.edited_timestamp = utils.parse_time(data['edited_timestamp'])
self.timestamp = utils.parse_time(data['timestamp'])
self.tts = data.get('tts', False)
self.pinned = data.get('pinned', False)
self.content = data['content']
self.mention_everyone = data['mention_everyone']
self.embeds = data['embeds']
self.id = data['id']
self.channel = channel
self.author = self._state.try_insert_user(data['author'])
self.nonce = data.get('nonce')
self.attachments = data['attachments']
self.type = try_enum(MessageType, data.get('type'))
self._handle_upgrades(data['channel_id'])
self._handle_mentions(data.get('mentions', []), data.get('mention_roles', []))
self._handle_call(data.get('call'))
for handler in ('mentions', 'mention_roles', 'call'):
try:
getattr(self, '_handle_%s' % handler)(data[handler])
except KeyError:
continue
self._try_patch(data, 'edited_timestamp', utils.parse_time)
self._try_patch(data, 'author', self._state.try_insert_user)
self._try_patch(data, 'pinned', bool)
self._try_patch(data, 'mention_everyone', bool)
self._try_patch(data, 'tts', bool)
self._try_patch(data, 'content', str)
self._try_patch(data, 'attachments', lambda x: x)
self._try_patch(data, 'embeds', lambda x: x)
self._try_patch(data, 'nonce', lambda x: x)
# clear the cached properties
cached = filter(lambda attr: attr.startswith('_cs_'), self.__slots__)
@ -151,24 +156,21 @@ class Message:
except AttributeError:
pass
def _handle_mentions(self, mentions, role_mentions):
def _handle_mentions(self, mentions):
self.mentions = []
self.channel_mentions = []
self.role_mentions = []
if getattr(self.channel, 'is_private', True):
if self.server is None:
self.mentions = [self._state.try_insert_user(m) for m in mentions]
return
if self.server is not None:
for mention in mentions:
id_search = mention.get('id')
member = self.server.get_member(id_search)
if member is not None:
self.mentions.append(member)
it = filter(None, map(lambda m: self.server.get_channel(m), self.raw_channel_mentions))
self.channel_mentions = utils._unique(it)
for mention in mentions:
id_search = mention['id']
member = self.server.get_member(id_search)
if member is not None:
self.mentions.append(member)
def _handle_mention_roles(self, role_mentions):
self.role_mentions = []
if self.server is not None:
for role_id in role_mentions:
role = utils.get(self.server.roles, id=role_id)
if role is not None:
@ -218,6 +220,13 @@ class Message:
"""
return re.findall(r'<@&([0-9]+)>', self.content)
@utils.cached_slot_property('_cs_channel_mentions')
def channel_mentions(self):
if self.server is None:
return []
it = filter(None, map(lambda m: self.server.get_channel(m), self.raw_channel_mentions))
return utils._unique(it)
@utils.cached_slot_property('_cs_clean_content')
def clean_content(self):
"""A property that returns the content in a "cleaned up"
@ -289,6 +298,11 @@ class Message:
if found is not None:
self.author = found
@property
def created_at(self):
"""Returns the message's creation time in UTC."""
return utils.snowflake_time(self.id)
@utils.cached_slot_property('_cs_system_content')
def system_content(self):
"""A property that returns the content that is rendered

Loading…
Cancel
Save