diff --git a/discord/member.py b/discord/member.py index 1c0b19df7..57de6d229 100644 --- a/discord/member.py +++ b/discord/member.py @@ -138,9 +138,9 @@ class Member(discord.abc.Messageable, _BaseUser): Attributes ---------- - joined_at: `datetime.datetime` + joined_at: Optional[:class:`datetime.datetime`] A datetime object that specifies the date and time in UTC that the member joined the guild for - the first time. + the first time. In certain cases, this can be ``None``. activities: Tuple[Union[:class:`Game`, :class:`Streaming`, :class:`Spotify`, :class:`Activity`]] The activities that the user is currently doing. guild: :class:`Guild` @@ -179,6 +179,16 @@ class Member(discord.abc.Messageable, _BaseUser): def __hash__(self): return hash(self._user) + @classmethod + def _from_message(cls, *, message, data): + author = message.author + data['user'] = { + attr: getattr(author, attr) + for attr in author.__slots__ + if attr[0] != '_' + } + return cls(data=data, guild=message.guild, state=message._state) + @classmethod def _copy(cls, member): self = cls.__new__(cls) # to bypass __init__ diff --git a/discord/message.py b/discord/message.py index 2a41c2fab..ca7b9ee33 100644 --- a/discord/message.py +++ b/discord/message.py @@ -35,6 +35,7 @@ from .calls import CallMessage from .enums import MessageType, try_enum from .errors import InvalidArgument, ClientException, HTTPException from .embeds import Embed +from .member import Member class Attachment: """Represents an attachment from Discord. @@ -277,7 +278,7 @@ class Message: self._try_patch(data, 'embeds', lambda x: list(map(Embed.from_data, x))) self._try_patch(data, 'nonce') - for handler in ('author', 'mentions', 'mention_roles', 'call'): + for handler in ('author', 'member', 'mentions', 'mention_roles', 'call'): try: getattr(self, '_handle_%s' % handler)(data[handler]) except KeyError: @@ -298,6 +299,20 @@ class Message: if found is not None: self.author = found + def _handle_member(self, member): + # The gateway now gives us full Member objects sometimes with the following keys + # deaf, mute, joined_at, roles + # For the sake of performance I'm going to assume that the only + # field that needs *updating* would be the joined_at field. + # If there is no Member object (for some strange reason), then we can upgrade + # ourselves to a more "partial" member object. + author = self.author + try: + if author.joined_at is None: + author.joined_at = utils.parse_time(member.get('joined_at')) + except AttributeError: + self.author = Member._from_message(message=self, data=member) + def _handle_mentions(self, mentions): self.mentions = [] if self.guild is None: