diff options
| author | Rapptz <[email protected]> | 2019-04-08 07:40:26 -0400 |
|---|---|---|
| committer | Rapptz <[email protected]> | 2019-04-08 07:45:04 -0400 |
| commit | f8999b63ae5f331452eec611b874002aa6a88658 (patch) | |
| tree | 93c616dcd805ae91e1b1bcb5ddc8be8517dfd78a | |
| parent | GUILD_MEMBER_UPDATE no longer does actual user updates. (diff) | |
| download | discord.py-f8999b63ae5f331452eec611b874002aa6a88658.tar.xz discord.py-f8999b63ae5f331452eec611b874002aa6a88658.zip | |
Fix long-standing issue with user updates not dispatching properly.
This fix is long coming. For a long time due to the addition of a
global user cache, the on_member_update event would only have the
updated user in the very first dispatch due to a quirk in the reference
only being updated once.
In order to fix this issue two things had to change:
1. There had to be a new event, `on_user_update` to complement
the equivalent member event.
2. Unnecessary copies of User had to be removed to compensate for the
performance hit from the diffing.
While doing these two fixes I also re-evaluated some more unnecessary
copies done during the PRESENCE_UPDATE to add member case while
fetch_offline_members=False is set or due to chunking issues. The
number of copies was brought down from 2 to 1, discounting the original
Member creation. Unsure on the benefits of this one, however.
N.B: this doesn't change the pre-existing behaviour of on_member_update
| -rw-r--r-- | discord/member.py | 28 | ||||
| -rw-r--r-- | discord/state.py | 9 | ||||
| -rw-r--r-- | docs/api.rst | 14 |
3 files changed, 43 insertions, 8 deletions
diff --git a/discord/member.py b/discord/member.py index b3961cf2..6107038d 100644 --- a/discord/member.py +++ b/discord/member.py @@ -190,6 +190,17 @@ class Member(discord.abc.Messageable, _BaseUser): return cls(data=data, guild=message.guild, state=message._state) @classmethod + def _from_presence_update(cls, *, data, guild, state): + clone = cls(data=data, guild=guild, state=state) + to_return = cls(data=data, guild=guild, state=state) + to_return._client_status = { + key: value + for key, value in data.get('client_status', {}).items() + } + to_return._client_status[None] = data['status'] + return to_return, clone + + @classmethod def _copy(cls, member): self = cls.__new__(cls) # to bypass __init__ @@ -200,7 +211,10 @@ class Member(discord.abc.Messageable, _BaseUser): self.nick = member.nick self.activities = member.activities self._state = member._state - self._user = User._copy(member._user) + + # Reference will not be copied unless necessary by PRESENCE_UPDATE + # See below + self._user = member._user return self async def _get_channel(self): @@ -230,9 +244,15 @@ class Member(discord.abc.Messageable, _BaseUser): if len(user) > 1: u = self._user - u.name = user.get('username', u.name) - u.avatar = user.get('avatar', u.avatar) - u.discriminator = user.get('discriminator', u.discriminator) + original = (u.name, u.avatar, u.discriminator) + # These keys seem to always be available + modified = (user['username'], user['avatar'], user['discriminator']) + if original != modified: + to_return = User._copy(self._user) + u.name, u.avatar, u.discriminator = modified + # Signal to dispatch on_user_update + return to_return, u + return False @property def status(self): diff --git a/discord/state.py b/discord/state.py index ab3f2ac7..3d420a0a 100644 --- a/discord/state.py +++ b/discord/state.py @@ -461,11 +461,14 @@ class ConnectionState: # skip these useless cases. return - member = Member(guild=guild, data=data, state=self) + member, old_member = Member._from_presence_update(guild=guild, data=data, state=self) guild._add_member(member) + else: + old_member = Member._copy(member) + user_update = member._presence_update(data=data, user=user) + if user_update: + self.dispatch('user_update', user_update[0], user_update[1]) - old_member = Member._copy(member) - member._presence_update(data=data, user=user) self.dispatch('member_update', old_member, member) def parse_user_update(self, data): diff --git a/docs/api.rst b/docs/api.rst index 7371537d..5f1466e5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -439,13 +439,25 @@ to handle it, which defaults to print a traceback and ignoring the exception. - status - game playing - - avatar - nickname - roles :param before: The :class:`Member` that updated their profile with the old info. :param after: The :class:`Member` that updated their profile with the updated info. +.. function:: on_user_update(before, after) + + Called when a :class:`User` updates their profile. + + This is called when one or more of the following things change: + + - avatar + - username + - discriminator + + :param before: The :class:`User` that updated their profile with the old info. + :param after: The :class:`User` that updated their profile with the updated info. + .. function:: on_guild_join(guild) Called when a :class:`Guild` is either created by the :class:`Client` or when the |