diff --git a/changelog/1051.bugfix.rst b/changelog/1051.bugfix.rst new file mode 100644 index 0000000000..de4cb4ac01 --- /dev/null +++ b/changelog/1051.bugfix.rst @@ -0,0 +1 @@ +Fix typing issue with :class:`abc.User` protocol requirements, which previously resulted in :class:`User` and :class:`Member` not conforming to the protocol. diff --git a/disnake/abc.py b/disnake/abc.py index 879577abb8..5288c6065a 100644 --- a/disnake/abc.py +++ b/disnake/abc.py @@ -146,8 +146,6 @@ class User(Snowflake, Protocol): .. versionadded:: 2.9 - avatar: :class:`~disnake.Asset` - The avatar asset the user has. bot: :class:`bool` Whether the user is a bot account. """ @@ -157,7 +155,6 @@ class User(Snowflake, Protocol): name: str discriminator: str global_name: Optional[str] - avatar: Asset bot: bool @property @@ -170,6 +167,13 @@ def mention(self) -> str: """:class:`str`: Returns a string that allows you to mention the given user.""" raise NotImplementedError + @property + def avatar(self) -> Optional[Asset]: + """Optional[:class:`~disnake.Asset`]: Returns an :class:`~disnake.Asset` for + the avatar the user has. + """ + raise NotImplementedError + @runtime_checkable class PrivateChannel(Snowflake, Protocol): diff --git a/disnake/member.py b/disnake/member.py index daf8fa7cbf..f3ff9008f7 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -279,6 +279,7 @@ class Member(disnake.abc.Messageable, _UserTag): if TYPE_CHECKING: name: str id: int + discriminator: str global_name: Optional[str] bot: bool system: bool @@ -487,19 +488,7 @@ def status(self, value: Status) -> None: @property def tag(self) -> str: """:class:`str`: An alias of :attr:`.discriminator`.""" - return self._user.discriminator - - @property - def discriminator(self) -> str: - """:class:`str`: The user's discriminator. - - .. note:: - This is being phased out by Discord; the username system is moving away from ``username#discriminator`` - to users having a globally unique username. - The value of a single zero (``"0"``) indicates that the user has been migrated to the new system. - See the `help article `__ for details. - """ - return self._user.discriminator + return self.discriminator @property def mobile_status(self) -> Status: diff --git a/tests/test_abc.py b/tests/test_abc.py index 196b71c38b..844904630b 100644 --- a/tests/test_abc.py +++ b/tests/test_abc.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: MIT +from typing import cast from unittest import mock import pytest @@ -151,3 +152,16 @@ async def test_overwrites(self, channel, sync_permissions) -> None: channel._state.http.edit_channel.assert_awaited_once_with( channel.id, permission_overwrites=[], reason=None ) + + +class TestUserProtocol: + def _test_typing_assignable(self) -> None: + def handle_abc_user(user: disnake.abc.User) -> None: + ... + + # All of these should match the abc.User protocol and thus type-check correctly + # (they could just inherit from the protocol to ensure correct implementation, + # but we really only want structural (i.e. implicit) subtyping) + handle_abc_user(cast(disnake.User, ...)) + handle_abc_user(cast(disnake.ClientUser, ...)) + handle_abc_user(cast(disnake.Member, ...))