aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2019-04-08 07:40:26 -0400
committerRapptz <[email protected]>2019-04-08 07:45:04 -0400
commitf8999b63ae5f331452eec611b874002aa6a88658 (patch)
tree93c616dcd805ae91e1b1bcb5ddc8be8517dfd78a
parentGUILD_MEMBER_UPDATE no longer does actual user updates. (diff)
downloaddiscord.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.py28
-rw-r--r--discord/state.py9
-rw-r--r--docs/api.rst14
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