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.
This commit is contained in:
Rapptz 2016-10-09 19:23:49 -04:00
parent 31229a53e9
commit aa8a328f0a

View File

@ -41,8 +41,6 @@ class Message:
----------- -----------
edited_timestamp: Optional[datetime.datetime] edited_timestamp: Optional[datetime.datetime]
A naive UTC datetime object containing the edited time of the message. 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. Specifies if the message was done with text-to-speech.
type: :class:`MessageType` type: :class:`MessageType`
@ -99,6 +97,9 @@ class Message:
then the list is always empty. then the list is always empty.
id: str id: str
The message ID. The message ID.
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 attachments: list
A list of attachments given to a message. A list of attachments given to a message.
pinned: bool pinned: bool
@ -107,9 +108,9 @@ class Message:
Reactions to a message. Reactions can be either custom emoji or standard unicode emoji. 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', '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', '_cs_clean_content', '_cs_raw_channel_mentions', 'nonce', 'pinned',
'role_mentions', '_cs_raw_role_mentions', 'type', 'call', 'role_mentions', '_cs_raw_role_mentions', 'type', 'call',
'_cs_system_content', '_state', 'reactions' ) '_cs_system_content', '_state', 'reactions' )
@ -121,27 +122,31 @@ class Message:
reaction.message = self reaction.message = self
self._update(channel, data) 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): 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.channel = channel
self.author = self._state.try_insert_user(data['author']) for handler in ('mentions', 'mention_roles', 'call'):
self.nonce = data.get('nonce') try:
self.attachments = data['attachments'] getattr(self, '_handle_%s' % handler)(data[handler])
self.type = try_enum(MessageType, data.get('type')) except KeyError:
self._handle_upgrades(data['channel_id']) continue
self._handle_mentions(data.get('mentions', []), data.get('mention_roles', []))
self._handle_call(data.get('call')) 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 # clear the cached properties
cached = filter(lambda attr: attr.startswith('_cs_'), self.__slots__) cached = filter(lambda attr: attr.startswith('_cs_'), self.__slots__)
@ -151,24 +156,21 @@ class Message:
except AttributeError: except AttributeError:
pass pass
def _handle_mentions(self, mentions, role_mentions): def _handle_mentions(self, mentions):
self.mentions = [] self.mentions = []
self.channel_mentions = [] if self.server is None:
self.role_mentions = []
if getattr(self.channel, 'is_private', True):
self.mentions = [self._state.try_insert_user(m) for m in mentions] self.mentions = [self._state.try_insert_user(m) for m in mentions]
return return
if self.server is not None:
for mention in mentions: for mention in mentions:
id_search = mention.get('id') id_search = mention['id']
member = self.server.get_member(id_search) member = self.server.get_member(id_search)
if member is not None: if member is not None:
self.mentions.append(member) self.mentions.append(member)
it = filter(None, map(lambda m: self.server.get_channel(m), self.raw_channel_mentions)) def _handle_mention_roles(self, role_mentions):
self.channel_mentions = utils._unique(it) self.role_mentions = []
if self.server is not None:
for role_id in role_mentions: for role_id in role_mentions:
role = utils.get(self.server.roles, id=role_id) role = utils.get(self.server.roles, id=role_id)
if role is not None: if role is not None:
@ -218,6 +220,13 @@ class Message:
""" """
return re.findall(r'<@&([0-9]+)>', self.content) 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') @utils.cached_slot_property('_cs_clean_content')
def clean_content(self): def clean_content(self):
"""A property that returns the content in a "cleaned up" """A property that returns the content in a "cleaned up"
@ -289,6 +298,11 @@ class Message:
if found is not None: if found is not None:
self.author = found 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') @utils.cached_slot_property('_cs_system_content')
def system_content(self): def system_content(self):
"""A property that returns the content that is rendered """A property that returns the content that is rendered