Browse Source

Initial support for pomelo migration

pull/9422/head
Rapptz 2 years ago
parent
commit
df01db3490
  1. 7
      discord/abc.py
  2. 36
      discord/ext/commands/converter.py
  3. 1
      discord/flags.py
  4. 30
      discord/guild.py
  5. 19
      discord/member.py
  6. 1
      discord/state.py
  7. 10
      discord/team.py
  8. 3
      discord/types/user.py
  9. 44
      discord/user.py
  10. 8
      discord/webhook/async_.py
  11. 14
      discord/widget.py

7
discord/abc.py

@ -219,7 +219,9 @@ class User(Snowflake, Protocol):
name: :class:`str` name: :class:`str`
The user's username. The user's username.
discriminator: :class:`str` discriminator: :class:`str`
The user's discriminator. The user's discriminator. This is a legacy concept that is no longer used.
global_name: Optional[:class:`str`]
The user's global nickname.
bot: :class:`bool` bot: :class:`bool`
If the user is a bot account. If the user is a bot account.
system: :class:`bool` system: :class:`bool`
@ -228,6 +230,7 @@ class User(Snowflake, Protocol):
name: str name: str
discriminator: str discriminator: str
global_name: Optional[str]
bot: bool bot: bool
system: bool system: bool
@ -248,7 +251,7 @@ class User(Snowflake, Protocol):
@property @property
def default_avatar(self) -> Asset: def default_avatar(self) -> Asset:
""":class:`~discord.Asset`: Returns the default avatar for a given user. This is calculated by the user's discriminator.""" """:class:`~discord.Asset`: Returns the default avatar for a given user."""
raise NotImplementedError raise NotImplementedError
@property @property

36
discord/ext/commands/converter.py

@ -186,9 +186,9 @@ class MemberConverter(IDConverter[discord.Member]):
1. Lookup by ID. 1. Lookup by ID.
2. Lookup by mention. 2. Lookup by mention.
3. Lookup by name#discrim 3. Lookup by guild nickname
4. Lookup by name 4. Lookup by global name
5. Lookup by nickname 5. Lookup by user name
.. versionchanged:: 1.5 .. versionchanged:: 1.5
Raise :exc:`.MemberNotFound` instead of generic :exc:`.BadArgument` Raise :exc:`.MemberNotFound` instead of generic :exc:`.BadArgument`
@ -196,17 +196,15 @@ class MemberConverter(IDConverter[discord.Member]):
.. versionchanged:: 1.5.1 .. versionchanged:: 1.5.1
This converter now lazily fetches members from the gateway and HTTP APIs, This converter now lazily fetches members from the gateway and HTTP APIs,
optionally caching the result if :attr:`.MemberCacheFlags.joined` is enabled. optionally caching the result if :attr:`.MemberCacheFlags.joined` is enabled.
.. versionchanged:: 2.3
This converter lookup strategy has changed due to the removal of discriminators.
""" """
async def query_member_named(self, guild: discord.Guild, argument: str) -> Optional[discord.Member]: async def query_member_named(self, guild: discord.Guild, argument: str) -> Optional[discord.Member]:
cache = guild._state.member_cache_flags.joined cache = guild._state.member_cache_flags.joined
if len(argument) > 5 and argument[-5] == '#': members = await guild.query_members(argument, limit=100, cache=cache)
username, _, discriminator = argument.rpartition('#') return discord.utils.find(lambda m: m.nick == argument or m.global_name == argument or m.name == argument, members)
members = await guild.query_members(username, limit=100, cache=cache)
return discord.utils.get(members, name=username, discriminator=discriminator)
else:
members = await guild.query_members(argument, limit=100, cache=cache)
return discord.utils.find(lambda m: m.name == argument or m.nick == argument, members)
async def query_member_by_id(self, bot: _Bot, guild: discord.Guild, user_id: int) -> Optional[discord.Member]: async def query_member_by_id(self, bot: _Bot, guild: discord.Guild, user_id: int) -> Optional[discord.Member]:
ws = bot._get_websocket(shard_id=guild.shard_id) ws = bot._get_websocket(shard_id=guild.shard_id)
@ -273,8 +271,8 @@ class UserConverter(IDConverter[discord.User]):
1. Lookup by ID. 1. Lookup by ID.
2. Lookup by mention. 2. Lookup by mention.
3. Lookup by name#discrim 3. Lookup by global name
4. Lookup by name 4. Lookup by user name
.. versionchanged:: 1.5 .. versionchanged:: 1.5
Raise :exc:`.UserNotFound` instead of generic :exc:`.BadArgument` Raise :exc:`.UserNotFound` instead of generic :exc:`.BadArgument`
@ -282,6 +280,9 @@ class UserConverter(IDConverter[discord.User]):
.. versionchanged:: 1.6 .. versionchanged:: 1.6
This converter now lazily fetches users from the HTTP APIs if an ID is passed This converter now lazily fetches users from the HTTP APIs if an ID is passed
and it's not available in cache. and it's not available in cache.
.. versionchanged:: 2.3
This converter lookup strategy has changed due to the removal of discriminators.
""" """
async def convert(self, ctx: Context[BotT], argument: str) -> discord.User: async def convert(self, ctx: Context[BotT], argument: str) -> discord.User:
@ -307,16 +308,7 @@ class UserConverter(IDConverter[discord.User]):
# Remove first character # Remove first character
arg = arg[1:] arg = arg[1:]
# check for discriminator if it exists, predicate = lambda u: u.global_name == arg or u.name == arg
if len(arg) > 5 and arg[-5] == '#':
discrim = arg[-4:]
name = arg[:-5]
predicate = lambda u: u.name == name and u.discriminator == discrim
result = discord.utils.find(predicate, state._users.values())
if result is not None:
return result
predicate = lambda u: u.name == arg
result = discord.utils.find(predicate, state._users.values()) result = discord.utils.find(predicate, state._users.values())
if result is None: if result is None:

1
discord/flags.py

@ -816,6 +816,7 @@ class Intents(BaseFlags):
- :attr:`User.name` - :attr:`User.name`
- :attr:`User.avatar` - :attr:`User.avatar`
- :attr:`User.discriminator` - :attr:`User.discriminator`
- :attr:`User.global_name`
For more information go to the :ref:`member intent documentation <need_members_intent>`. For more information go to the :ref:`member intent documentation <need_members_intent>`.

30
discord/guild.py

@ -1075,26 +1075,20 @@ class Guild(Hashable):
def get_member_named(self, name: str, /) -> Optional[Member]: def get_member_named(self, name: str, /) -> Optional[Member]:
"""Returns the first member found that matches the name provided. """Returns the first member found that matches the name provided.
The name can have an optional discriminator argument, e.g. "Jake#0001"
or "Jake" will both do the lookup. However the former will give a more
precise result. Note that the discriminator must have all 4 digits
for this to work.
If a nickname is passed, then it is looked up via the nickname. Note
however, that a nickname + discriminator combo will not lookup the nickname
but rather the username + discriminator combo due to nickname + discriminator
not being unique.
If no member is found, ``None`` is returned. If no member is found, ``None`` is returned.
.. versionchanged:: 2.0 .. versionchanged:: 2.0
``name`` parameter is now positional-only. ``name`` parameter is now positional-only.
.. versionchanged:: 2.3
``discriminator`` is no longer used in lookup, due to being removed on Discord.
Parameters Parameters
----------- -----------
name: :class:`str` name: :class:`str`
The name of the member to lookup with an optional discriminator. The name of the member to lookup.
Returns Returns
-------- --------
@ -1103,22 +1097,10 @@ class Guild(Hashable):
then ``None`` is returned. then ``None`` is returned.
""" """
result = None
members = self.members members = self.members
if len(name) > 5 and name[-5] == '#':
# The 5 length is checking to see if #0000 is in the string,
# as a#0000 has a length of 6, the minimum for a potential
# discriminator lookup.
potential_discriminator = name[-4:]
# do the actual lookup and return if found
# if it isn't found then we'll do a full name lookup below.
result = utils.get(members, name=name[:-5], discriminator=potential_discriminator)
if result is not None:
return result
def pred(m: Member) -> bool: def pred(m: Member) -> bool:
return m.nick == name or m.name == name return m.nick == name or m.global_name == name or m.name == name
return utils.find(pred, members) return utils.find(pred, members)

19
discord/member.py

@ -274,7 +274,7 @@ class Member(discord.abc.Messageable, _UserTag):
.. describe:: str(x) .. describe:: str(x)
Returns the member's name with the discriminator. Returns the member's name with a ``@``.
Attributes Attributes
---------- ----------
@ -293,7 +293,7 @@ class Member(discord.abc.Messageable, _UserTag):
guild: :class:`Guild` guild: :class:`Guild`
The guild that the member belongs to. The guild that the member belongs to.
nick: Optional[:class:`str`] nick: Optional[:class:`str`]
The guild specific nickname of the user. The guild specific nickname of the user. Takes precedence over the global name.
pending: :class:`bool` pending: :class:`bool`
Whether the member is pending member verification. Whether the member is pending member verification.
@ -329,6 +329,7 @@ class Member(discord.abc.Messageable, _UserTag):
name: str name: str
id: int id: int
discriminator: str discriminator: str
global_name: Optional[str]
bot: bool bot: bool
system: bool system: bool
created_at: datetime.datetime created_at: datetime.datetime
@ -368,7 +369,7 @@ class Member(discord.abc.Messageable, _UserTag):
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
f'<Member id={self._user.id} name={self._user.name!r} discriminator={self._user.discriminator!r}' f'<Member id={self._user.id} name={self._user.name!r} global_name={self._user.global_name!r}'
f' bot={self._user.bot} nick={self.nick!r} guild={self.guild!r}>' f' bot={self._user.bot} nick={self.nick!r} guild={self.guild!r}>'
) )
@ -463,12 +464,12 @@ class Member(discord.abc.Messageable, _UserTag):
def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]: def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]:
u = self._user u = self._user
original = (u.name, u._avatar, u.discriminator, u._public_flags) original = (u.name, u._avatar, u.global_name, u._public_flags)
# These keys seem to always be available # These keys seem to always be available
modified = (user['username'], user['avatar'], user['discriminator'], user.get('public_flags', 0)) modified = (user['username'], user['avatar'], user.get('global_name'), user.get('public_flags', 0))
if original != modified: if original != modified:
to_return = User._copy(self._user) to_return = User._copy(self._user)
u.name, u._avatar, u.discriminator, u._public_flags = modified u.name, u._avatar, u.global_name, u._public_flags = modified
# Signal to dispatch on_user_update # Signal to dispatch on_user_update
return to_return, u return to_return, u
@ -581,11 +582,11 @@ class Member(discord.abc.Messageable, _UserTag):
def display_name(self) -> str: def display_name(self) -> str:
""":class:`str`: Returns the user's display name. """:class:`str`: Returns the user's display name.
For regular users this is just their username, but For regular users this is just their global name or their username,
if they have a guild specific nickname then that but if they have a guild specific nickname then that
is returned instead. is returned instead.
""" """
return self.nick or self.name return self.nick or self.global_name or self.name
@property @property
def display_avatar(self) -> Asset: def display_avatar(self) -> Asset:

1
discord/state.py

@ -356,6 +356,7 @@ class ConnectionState(Generic[ClientT]):
return self._users[user_id] return self._users[user_id]
except KeyError: except KeyError:
user = User(state=self, data=data) user = User(state=self, data=data)
# TODO: with the removal of discrims this becomes a bit annoying
if user.discriminator != '0000': if user.discriminator != '0000':
self._users[user_id] = user self._users[user_id] = user
return user return user

10
discord/team.py

@ -108,7 +108,7 @@ class TeamMember(BaseUser):
.. describe:: str(x) .. describe:: str(x)
Returns the team member's name with discriminator. Returns the team member's name with a ``@``.
.. versionadded:: 1.3 .. versionadded:: 1.3
@ -119,7 +119,11 @@ class TeamMember(BaseUser):
id: :class:`int` id: :class:`int`
The team member's unique ID. The team member's unique ID.
discriminator: :class:`str` discriminator: :class:`str`
The team member's discriminator. This is given when the username has conflicts. The team member's discriminator. This is a legacy concept that is no longer used.
global_name: Optional[:class:`str`]
The user's global nickname, taking precedence over the username in display.
.. versionadded:: 2.3
bot: :class:`bool` bot: :class:`bool`
Specifies if the user is a bot account. Specifies if the user is a bot account.
team: :class:`Team` team: :class:`Team`
@ -139,5 +143,5 @@ class TeamMember(BaseUser):
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
f'<{self.__class__.__name__} id={self.id} name={self.name!r} ' f'<{self.__class__.__name__} id={self.id} name={self.name!r} '
f'discriminator={self.discriminator!r} membership_state={self.membership_state!r}>' f'global_name={self.global_name!r} membership_state={self.membership_state!r}>'
) )

3
discord/types/user.py

@ -31,6 +31,7 @@ class PartialUser(TypedDict):
username: str username: str
discriminator: str discriminator: str
avatar: Optional[str] avatar: Optional[str]
global_name: Optional[str]
PremiumType = Literal[0, 1, 2] PremiumType = Literal[0, 1, 2]
@ -40,7 +41,7 @@ class User(PartialUser, total=False):
bot: bool bot: bool
system: bool system: bool
mfa_enabled: bool mfa_enabled: bool
local: str locale: str
verified: bool verified: bool
email: Optional[str] email: Optional[str]
flags: int flags: int

44
discord/user.py

@ -65,6 +65,7 @@ class BaseUser(_UserTag):
'name', 'name',
'id', 'id',
'discriminator', 'discriminator',
'global_name',
'_avatar', '_avatar',
'_banner', '_banner',
'_accent_colour', '_accent_colour',
@ -78,6 +79,7 @@ class BaseUser(_UserTag):
name: str name: str
id: int id: int
discriminator: str discriminator: str
global_name: Optional[str]
bot: bool bot: bool
system: bool system: bool
_state: ConnectionState _state: ConnectionState
@ -92,12 +94,12 @@ class BaseUser(_UserTag):
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
f"<BaseUser id={self.id} name={self.name!r} discriminator={self.discriminator!r}" f"<BaseUser id={self.id} name={self.name!r} global_name={self.global_name!r}"
f" bot={self.bot} system={self.system}>" f" bot={self.bot} system={self.system}>"
) )
def __str__(self) -> str: def __str__(self) -> str:
return f'{self.name}#{self.discriminator}' return f'@{self.name}'
def __eq__(self, other: object) -> bool: def __eq__(self, other: object) -> bool:
return isinstance(other, _UserTag) and other.id == self.id return isinstance(other, _UserTag) and other.id == self.id
@ -112,6 +114,7 @@ class BaseUser(_UserTag):
self.name = data['username'] self.name = data['username']
self.id = int(data['id']) self.id = int(data['id'])
self.discriminator = data['discriminator'] self.discriminator = data['discriminator']
self.global_name = data.get('global_name')
self._avatar = data['avatar'] self._avatar = data['avatar']
self._banner = data.get('banner', None) self._banner = data.get('banner', None)
self._accent_colour = data.get('accent_color', None) self._accent_colour = data.get('accent_color', None)
@ -126,6 +129,7 @@ class BaseUser(_UserTag):
self.name = user.name self.name = user.name
self.id = user.id self.id = user.id
self.discriminator = user.discriminator self.discriminator = user.discriminator
self.global_name = user.global_name
self._avatar = user._avatar self._avatar = user._avatar
self._banner = user._banner self._banner = user._banner
self._accent_colour = user._accent_colour self._accent_colour = user._accent_colour
@ -141,6 +145,7 @@ class BaseUser(_UserTag):
'id': self.id, 'id': self.id,
'avatar': self._avatar, 'avatar': self._avatar,
'discriminator': self.discriminator, 'discriminator': self.discriminator,
'global_name': self.global_name,
'bot': self.bot, 'bot': self.bot,
} }
@ -162,8 +167,13 @@ class BaseUser(_UserTag):
@property @property
def default_avatar(self) -> Asset: def default_avatar(self) -> Asset:
""":class:`Asset`: Returns the default avatar for a given user. This is calculated by the user's discriminator.""" """:class:`Asset`: Returns the default avatar for a given user."""
return Asset._from_default_avatar(self._state, int(self.discriminator) % len(DefaultAvatar)) if self.discriminator == '0':
avatar_id = self.id % len(DefaultAvatar)
else:
avatar_id = int(self.discriminator) % len(DefaultAvatar)
return Asset._from_default_avatar(self._state, avatar_id)
@property @property
def display_avatar(self) -> Asset: def display_avatar(self) -> Asset:
@ -260,10 +270,12 @@ class BaseUser(_UserTag):
def display_name(self) -> str: def display_name(self) -> str:
""":class:`str`: Returns the user's display name. """:class:`str`: Returns the user's display name.
For regular users this is just their username, but For regular users this is just their global name or their username,
if they have a guild specific nickname then that but if they have a guild specific nickname then that
is returned instead. is returned instead.
""" """
if self.global_name:
return self.global_name
return self.name return self.name
def mentioned_in(self, message: Message) -> bool: def mentioned_in(self, message: Message) -> bool:
@ -305,7 +317,7 @@ class ClientUser(BaseUser):
.. describe:: str(x) .. describe:: str(x)
Returns the user's name with discriminator. Returns the user's name with a ``@``.
Attributes Attributes
----------- -----------
@ -314,7 +326,11 @@ class ClientUser(BaseUser):
id: :class:`int` id: :class:`int`
The user's unique ID. The user's unique ID.
discriminator: :class:`str` discriminator: :class:`str`
The user's discriminator. This is given when the username has conflicts. The user's discriminator. This is a legacy concept that is no longer used.
global_name: Optional[:class:`str`]
The user's global nickname, taking precedence over the username in display.
.. versionadded:: 2.3
bot: :class:`bool` bot: :class:`bool`
Specifies if the user is a bot account. Specifies if the user is a bot account.
system: :class:`bool` system: :class:`bool`
@ -343,7 +359,7 @@ class ClientUser(BaseUser):
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
f'<ClientUser id={self.id} name={self.name!r} discriminator={self.discriminator!r}' f'<ClientUser id={self.id} name={self.name!r} global_name={self.global_name!r}'
f' bot={self.bot} verified={self.verified} mfa_enabled={self.mfa_enabled}>' f' bot={self.bot} verified={self.verified} mfa_enabled={self.mfa_enabled}>'
) )
@ -441,7 +457,7 @@ class User(BaseUser, discord.abc.Messageable):
.. describe:: str(x) .. describe:: str(x)
Returns the user's name with discriminator. Returns the user's name with a ``@``.
Attributes Attributes
----------- -----------
@ -450,7 +466,11 @@ class User(BaseUser, discord.abc.Messageable):
id: :class:`int` id: :class:`int`
The user's unique ID. The user's unique ID.
discriminator: :class:`str` discriminator: :class:`str`
The user's discriminator. This is given when the username has conflicts. The user's discriminator. This is a legacy concept that is no longer used.
global_name: Optional[:class:`str`]
The user's global nickname, taking precedence over the username in display.
.. versionadded:: 2.3
bot: :class:`bool` bot: :class:`bool`
Specifies if the user is a bot account. Specifies if the user is a bot account.
system: :class:`bool` system: :class:`bool`
@ -460,7 +480,7 @@ class User(BaseUser, discord.abc.Messageable):
__slots__ = ('__weakref__',) __slots__ = ('__weakref__',)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<User id={self.id} name={self.name!r} discriminator={self.discriminator!r} bot={self.bot}>' return f'<User id={self.id} name={self.name!r} global_name={self.global_name!r} bot={self.bot}>'
async def _get_channel(self) -> DMChannel: async def _get_channel(self) -> DMChannel:
ch = await self.create_dm() ch = await self.create_dm()

8
discord/webhook/async_.py

@ -1301,7 +1301,13 @@ class Webhook(BaseWebhook):
'name': name, 'name': name,
'channel_id': channel.id, 'channel_id': channel.id,
'guild_id': channel.guild.id, 'guild_id': channel.guild.id,
'user': {'username': user.name, 'discriminator': user.discriminator, 'id': user.id, 'avatar': user._avatar}, 'user': {
'username': user.name,
'discriminator': user.discriminator,
'global_name': user.global_name,
'id': user.id,
'avatar': user._avatar,
},
} }
state = channel._state state = channel._state

14
discord/widget.py

@ -121,7 +121,7 @@ class WidgetMember(BaseUser):
.. describe:: str(x) .. describe:: str(x)
Returns the widget member's ``name#discriminator``. Returns the widget member's name with a ``@``.
Attributes Attributes
----------- -----------
@ -130,13 +130,17 @@ class WidgetMember(BaseUser):
name: :class:`str` name: :class:`str`
The member's username. The member's username.
discriminator: :class:`str` discriminator: :class:`str`
The member's discriminator. The member's discriminator. This is a legacy concept that is no longer used.
global_name: Optional[:class:`str`]
The member's global nickname, taking precedence over the username in display.
.. versionadded:: 2.3
bot: :class:`bool` bot: :class:`bool`
Whether the member is a bot. Whether the member is a bot.
status: :class:`Status` status: :class:`Status`
The member's status. The member's status.
nick: Optional[:class:`str`] nick: Optional[:class:`str`]
The member's nickname. The member's guild-specific nickname. Takes precedence over the global name.
avatar: Optional[:class:`str`] avatar: Optional[:class:`str`]
The member's avatar hash. The member's avatar hash.
activity: Optional[Union[:class:`BaseActivity`, :class:`Spotify`]] activity: Optional[Union[:class:`BaseActivity`, :class:`Spotify`]]
@ -191,9 +195,7 @@ class WidgetMember(BaseUser):
self.connected_channel: Optional[WidgetChannel] = connected_channel self.connected_channel: Optional[WidgetChannel] = connected_channel
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return f"<WidgetMember name={self.name!r} global_name={self.global_name!r}" f" bot={self.bot} nick={self.nick!r}>"
f"<WidgetMember name={self.name!r} discriminator={self.discriminator!r}" f" bot={self.bot} nick={self.nick!r}>"
)
@property @property
def display_name(self) -> str: def display_name(self) -> str:

Loading…
Cancel
Save