From f9e95a35f9423bb127edc5c3edfb258889e0af66 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Sun, 28 Apr 2019 06:26:23 -0400 Subject: [PATCH] Fix USER_UPDATE changes not triggering for member instances. Also add a ClientUser.locale attribute. --- discord/state.py | 14 ++++++++------ discord/user.py | 36 +++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/discord/state.py b/discord/state.py index 3d420a0a6..a603c55d4 100644 --- a/discord/state.py +++ b/discord/state.py @@ -330,7 +330,8 @@ class ConnectionState: self._ready_state = ReadyState(launch=asyncio.Event(), guilds=[]) self.clear() - self.user = ClientUser(state=self, data=data['user']) + self.user = user = ClientUser(state=self, data=data['user']) + self._users[user.id] = user guilds = self._ready_state.guilds for guild_data in data['guilds']: @@ -344,11 +345,11 @@ class ConnectionState: except KeyError: continue else: - self.user._relationships[r_id] = Relationship(state=self, data=relationship) + user._relationships[r_id] = Relationship(state=self, data=relationship) for pm in data.get('private_channels', []): factory, _ = _channel_factory(pm['type']) - self._add_private_channel(factory(me=self.user, data=pm, state=self)) + self._add_private_channel(factory(me=user, data=pm, state=self)) self.dispatch('connect') self._ready_task = asyncio.ensure_future(self._delay_ready(), loop=self.loop) @@ -472,7 +473,7 @@ class ConnectionState: self.dispatch('member_update', old_member, member) def parse_user_update(self, data): - self.user = ClientUser(state=self, data=data) + self.user._update(data) def parse_channel_delete(self, data): guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id')) @@ -993,7 +994,8 @@ class AutoShardedConnectionState(ConnectionState): if not hasattr(self, '_ready_state'): self._ready_state = ReadyState(launch=asyncio.Event(), guilds=[]) - self.user = ClientUser(state=self, data=data['user']) + self.user = user = ClientUser(state=self, data=data['user']) + self._users[user.id] = user guilds = self._ready_state.guilds for guild_data in data['guilds']: @@ -1003,7 +1005,7 @@ class AutoShardedConnectionState(ConnectionState): for pm in data.get('private_channels', []): factory, _ = _channel_factory(pm['type']) - self._add_private_channel(factory(me=self.user, data=pm, state=self)) + self._add_private_channel(factory(me=user, data=pm, state=self)) self.dispatch('connect') if self._ready_task is None: diff --git a/discord/user.py b/discord/user.py index b1d34868d..a47e5351b 100644 --- a/discord/user.py +++ b/discord/user.py @@ -78,11 +78,7 @@ class BaseUser(_BaseUser): def __init__(self, *, state, data): self._state = state - self.name = data['username'] - self.id = int(data['id']) - self.discriminator = data['discriminator'] - self.avatar = data['avatar'] - self.bot = data.get('bot', False) + self._update(data) def __str__(self): return '{0.name}#{0.discriminator}'.format(self) @@ -96,6 +92,13 @@ class BaseUser(_BaseUser): def __hash__(self): return self.id >> 22 + def _update(self, data): + self.name = data['username'] + self.id = int(data['id']) + self.discriminator = data['discriminator'] + self.avatar = data['avatar'] + self.bot = data.get('bot', False) + @classmethod def _copy(cls, user): self = cls.__new__(cls) # bypass __init__ @@ -275,6 +278,8 @@ class ClientUser(BaseUser): Specifies if the user is a verified account. email: Optional[:class:`str`] The email the user used when registering. + locale: Optional[:class:`str`] + The IETF language tag used to identify the user is using. mfa_enabled: :class:`bool` Specifies if the user has MFA turned on and working. premium: :class:`bool` @@ -282,21 +287,27 @@ class ClientUser(BaseUser): premium_type: :class:`PremiumType` Specifies the type of premium a user has (e.g. Nitro or Nitro Classic). Could be None if the user is not premium. """ - __slots__ = ('email', 'verified', 'mfa_enabled', 'premium', 'premium_type', '_relationships') + __slots__ = ('email', 'locale', '_flags', 'verified', 'mfa_enabled', + 'premium', 'premium_type', '_relationships', '__weakref__') def __init__(self, *, state, data): super().__init__(state=state, data=data) - self.verified = data.get('verified', False) - self.email = data.get('email') - self.mfa_enabled = data.get('mfa_enabled', False) - self.premium = data.get('premium', False) - self.premium_type = try_enum(PremiumType, data.get('premium_type', None)) self._relationships = {} def __repr__(self): return ''.format(self) + def _update(self, data): + super()._update(data) + # There's actually an Optional[str] phone field as well but I won't use it + self.verified = data.get('verified', False) + self.email = data.get('email') + self.locale = data.get('locale') + self._flags = data.get('flags', 0) + self.mfa_enabled = data.get('mfa_enabled', False) + self.premium = data.get('premium', False) + self.premium_type = try_enum(PremiumType, data.get('premium_type', None)) def get_relationship(self, user_id): """Retrieves the :class:`Relationship` if applicable. @@ -444,8 +455,7 @@ class ClientUser(BaseUser): except KeyError: pass - # manually update data by calling __init__ explicitly. - self.__init__(state=self._state, data=data) + self._update(data) async def create_group(self, *recipients): r"""|coro|