Browse Source

Typehint Role and RoleTags

pull/6985/head
Rapptz 4 years ago
parent
commit
c475218112
  1. 107
      discord/role.py

107
discord/role.py

@ -22,19 +22,30 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from typing import Optional, Union, overload from __future__ import annotations
from typing import Any, List, Optional, TypeVar, Union, overload, TYPE_CHECKING
from .permissions import Permissions from .permissions import Permissions
from .errors import InvalidArgument from .errors import InvalidArgument
from .colour import Colour from .colour import Colour
from .mixins import Hashable from .mixins import Hashable
from .utils import snowflake_time, _get_as_snowflake from .utils import snowflake_time, _get_as_snowflake, MISSING
__all__ = ( __all__ = (
'RoleTags', 'RoleTags',
'Role', 'Role',
) )
if TYPE_CHECKING:
import datetime
from .types.role import (
Role as RolePayload,
RoleTags as RoleTagPayload,
)
from .guild import Guild
from .member import Member
from .state import ConnectionState
class RoleTags: class RoleTags:
"""Represents tags on a role. """Represents tags on a role.
@ -61,34 +72,37 @@ class RoleTags:
'_premium_subscriber', '_premium_subscriber',
) )
def __init__(self, data): def __init__(self, data: RoleTagPayload):
self.bot_id = _get_as_snowflake(data, 'bot_id') self.bot_id: Optional[int] = _get_as_snowflake(data, 'bot_id')
self.integration_id = _get_as_snowflake(data, 'integration_id') self.integration_id: Optional[int] = _get_as_snowflake(data, 'integration_id')
# NOTE: The API returns "null" for this if it's valid, which corresponds to None. # NOTE: The API returns "null" for this if it's valid, which corresponds to None.
# This is different from other fields where "null" means "not there". # This is different from other fields where "null" means "not there".
# So in this case, a value of None is the same as True. # So in this case, a value of None is the same as True.
# Which means we would need a different sentinel. For this purpose I used ellipsis. # Which means we would need a different sentinel.
self._premium_subscriber = data.get('premium_subscriber', ...) self._premium_subscriber: Optional[Any] = data.get('premium_subscriber', MISSING)
def is_bot_managed(self): def is_bot_managed(self) -> bool:
""":class:`bool`: Whether the role is associated with a bot.""" """:class:`bool`: Whether the role is associated with a bot."""
return self.bot_id is not None return self.bot_id is not None
def is_premium_subscriber(self): def is_premium_subscriber(self) -> bool:
""":class:`bool`: Whether the role is the premium subscriber, AKA "boost", role for the guild.""" """:class:`bool`: Whether the role is the premium subscriber, AKA "boost", role for the guild."""
return self._premium_subscriber is None return self._premium_subscriber is None
def is_integration(self): def is_integration(self) -> bool:
""":class:`bool`: Whether the role is managed by an integration.""" """:class:`bool`: Whether the role is managed by an integration."""
return self.integration_id is not None return self.integration_id is not None
def __repr__(self): def __repr__(self) -> str:
return ( return (
f'<RoleTags bot_id={self.bot_id} integration_id={self.integration_id} ' f'<RoleTags bot_id={self.bot_id} integration_id={self.integration_id} '
f'premium_subscriber={self.is_premium_subscriber()}>' f'premium_subscriber={self.is_premium_subscriber()}>'
) )
R = TypeVar('R', bound='Role')
class Role(Hashable): class Role(Hashable):
"""Represents a Discord role in a :class:`Guild`. """Represents a Discord role in a :class:`Guild`.
@ -171,19 +185,19 @@ class Role(Hashable):
'_state', '_state',
) )
def __init__(self, *, guild, state, data): def __init__(self, *, guild: Guild, state: ConnectionState, data: RolePayload):
self.guild = guild self.guild: Guild = guild
self._state = state self._state: ConnectionState = state
self.id = int(data['id']) self.id: int = int(data['id'])
self._update(data) self._update(data)
def __str__(self): def __str__(self) -> str:
return self.name return self.name
def __repr__(self): def __repr__(self) -> str:
return f'<Role id={self.id} name={self.name!r}>' return f'<Role id={self.id} name={self.name!r}>'
def __lt__(self, other): def __lt__(self: R, other: R) -> bool:
if not isinstance(other, Role) or not isinstance(self, Role): if not isinstance(other, Role) or not isinstance(self, Role):
return NotImplemented return NotImplemented
@ -204,99 +218,96 @@ class Role(Hashable):
return False return False
def __le__(self, other): def __le__(self: R, other: R) -> bool:
r = Role.__lt__(other, self) r = Role.__lt__(other, self)
if r is NotImplemented: if r is NotImplemented:
return NotImplemented return NotImplemented
return not r return not r
def __gt__(self, other): def __gt__(self: R, other: R) -> bool:
return Role.__lt__(other, self) return Role.__lt__(other, self)
def __ge__(self, other): def __ge__(self: R, other: R) -> bool:
r = Role.__lt__(self, other) r = Role.__lt__(self, other)
if r is NotImplemented: if r is NotImplemented:
return NotImplemented return NotImplemented
return not r return not r
def _update(self, data): def _update(self, data: RolePayload):
self.name = data['name'] self.name: str = data['name']
self._permissions = int(data.get('permissions', 0)) self._permissions: int = int(data.get('permissions', 0))
self.position = data.get('position', 0) self.position: int = data.get('position', 0)
self._colour = data.get('color', 0) self._colour: int = data.get('color', 0)
self.hoist = data.get('hoist', False) self.hoist: bool = data.get('hoist', False)
self.managed = data.get('managed', False) self.managed: bool = data.get('managed', False)
self.mentionable = data.get('mentionable', False) self.mentionable: bool = data.get('mentionable', False)
self.tags: Optional[RoleTags]
try: try:
self.tags = RoleTags(data['tags']) self.tags = RoleTags(data['tags'])
except KeyError: except KeyError:
self.tags = None self.tags = None
def is_default(self): def is_default(self) -> bool:
""":class:`bool`: Checks if the role is the default role.""" """:class:`bool`: Checks if the role is the default role."""
return self.guild.id == self.id return self.guild.id == self.id
def is_bot_managed(self): def is_bot_managed(self) -> bool:
""":class:`bool`: Whether the role is associated with a bot. """:class:`bool`: Whether the role is associated with a bot.
.. versionadded:: 1.6 .. versionadded:: 1.6
""" """
return self.tags is not None and self.tags.is_bot_managed() return self.tags is not None and self.tags.is_bot_managed()
def is_premium_subscriber(self): def is_premium_subscriber(self) -> bool:
""":class:`bool`: Whether the role is the premium subscriber, AKA "boost", role for the guild. """:class:`bool`: Whether the role is the premium subscriber, AKA "boost", role for the guild.
.. versionadded:: 1.6 .. versionadded:: 1.6
""" """
return self.tags is not None and self.tags.is_premium_subscriber() return self.tags is not None and self.tags.is_premium_subscriber()
def is_integration(self): def is_integration(self) -> bool:
""":class:`bool`: Whether the role is managed by an integration. """:class:`bool`: Whether the role is managed by an integration.
.. versionadded:: 1.6 .. versionadded:: 1.6
""" """
return self.tags is not None and self.tags.is_integration() return self.tags is not None and self.tags.is_integration()
def is_assignable(self): def is_assignable(self) -> bool:
""":class:`bool`: Whether the role is able to be assigned or removed by the bot. """:class:`bool`: Whether the role is able to be assigned or removed by the bot.
.. versionadded:: 2.0 .. versionadded:: 2.0
""" """
me = self.guild.me me = self.guild.me
return ( return not self.is_default() and not self.managed and (me.top_role > self or me.id == self.guild.owner_id)
not self.is_default()
and not self.managed
and (me.top_role > self or me.id == self.guild.owner_id)
)
@property @property
def permissions(self): def permissions(self) -> Permissions:
""":class:`Permissions`: Returns the role's permissions.""" """:class:`Permissions`: Returns the role's permissions."""
return Permissions(self._permissions) return Permissions(self._permissions)
@property @property
def colour(self): def colour(self) -> Colour:
""":class:`Colour`: Returns the role colour. An alias exists under ``color``.""" """:class:`Colour`: Returns the role colour. An alias exists under ``color``."""
return Colour(self._colour) return Colour(self._colour)
@property @property
def color(self): def color(self) -> Colour:
""":class:`Colour`: Returns the role color. An alias exists under ``colour``.""" """:class:`Colour`: Returns the role color. An alias exists under ``colour``."""
return self.colour return self.colour
@property @property
def created_at(self): def created_at(self) -> datetime.datetime:
""":class:`datetime.datetime`: Returns the role's creation time in UTC.""" """:class:`datetime.datetime`: Returns the role's creation time in UTC."""
return snowflake_time(self.id) return snowflake_time(self.id)
@property @property
def mention(self): def mention(self) -> str:
""":class:`str`: Returns a string that allows you to mention a role.""" """:class:`str`: Returns a string that allows you to mention a role."""
return f'<@&{self.id}>' return f'<@&{self.id}>'
@property @property
def members(self): def members(self) -> List[Member]:
"""List[:class:`Member`]: Returns all the members with this role.""" """List[:class:`Member`]: Returns all the members with this role."""
all_members = self.guild.members all_members = self.guild.members
if self.is_default(): if self.is_default():
@ -305,7 +316,7 @@ class Role(Hashable):
role_id = self.id role_id = self.id
return [member for member in all_members if member._roles.has(role_id)] return [member for member in all_members if member._roles.has(role_id)]
async def _move(self, position, reason): async def _move(self, position: int, reason: Optional[str]) -> None:
if position <= 0: if position <= 0:
raise InvalidArgument("Cannot move role to position 0 or below") raise InvalidArgument("Cannot move role to position 0 or below")
@ -346,7 +357,7 @@ class Role(Hashable):
async def edit(self) -> None: async def edit(self) -> None:
... ...
async def edit(self, *, reason=None, **fields): async def edit(self, *, reason=None, **fields) -> None:
"""|coro| """|coro|
Edits the role. Edits the role.
@ -412,7 +423,7 @@ class Role(Hashable):
data = await self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload) data = await self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload)
self._update(data) self._update(data)
async def delete(self, *, reason: Optional[str] = None): async def delete(self, *, reason: Optional[str] = None) -> None:
"""|coro| """|coro|
Deletes the role. Deletes the role.

Loading…
Cancel
Save