Skip to content

Commit

Permalink
typing: fix abc.User protocol structural subtyping (#1051)
Browse files Browse the repository at this point in the history
  • Loading branch information
shiftinv authored Jun 19, 2023
1 parent 1ef57f5 commit 375840e
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 16 deletions.
1 change: 1 addition & 0 deletions changelog/1051.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 7 additions & 3 deletions disnake/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -157,7 +155,6 @@ class User(Snowflake, Protocol):
name: str
discriminator: str
global_name: Optional[str]
avatar: Asset
bot: bool

@property
Expand All @@ -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):
Expand Down
15 changes: 2 additions & 13 deletions disnake/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <https://dis.gd/app-usernames>`__ for details.
"""
return self._user.discriminator
return self.discriminator

@property
def mobile_status(self) -> Status:
Expand Down
14 changes: 14 additions & 0 deletions tests/test_abc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: MIT

from typing import cast
from unittest import mock

import pytest
Expand Down Expand Up @@ -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, ...))

0 comments on commit 375840e

Please sign in to comment.