Browse Source

Use typing.Self throughout library

pull/7492/head
Josh 3 years ago
committed by GitHub
parent
commit
147948af9b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      discord/abc.py
  2. 11
      discord/channel.py
  3. 81
      discord/colour.py
  4. 10
      discord/components.py
  5. 32
      discord/embeds.py
  6. 6
      discord/enums.py
  7. 23
      discord/ext/commands/bot.py
  8. 15
      discord/ext/commands/cog.py
  9. 11
      discord/ext/commands/cooldowns.py
  10. 12
      discord/ext/commands/core.py
  11. 17
      discord/ext/commands/flags.py
  12. 9
      discord/flags.py
  13. 5
      discord/http.py
  14. 13
      discord/invite.py
  15. 15
      discord/member.py
  16. 10
      discord/mentions.py
  17. 9
      discord/message.py
  18. 20
      discord/partial_emoji.py
  19. 31
      discord/permissions.py
  20. 9
      discord/player.py
  21. 15
      discord/role.py
  22. 8
      discord/shard.py
  23. 1
      discord/state.py
  24. 7
      discord/ui/button.py
  25. 5
      discord/ui/select.py
  26. 7
      discord/ui/text_input.py
  27. 8
      discord/user.py
  28. 2
      discord/webhook/sync.py

11
discord/abc.py

@ -70,6 +70,8 @@ __all__ = (
T = TypeVar('T', bound=VoiceProtocol) T = TypeVar('T', bound=VoiceProtocol)
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .client import Client from .client import Client
from .user import ClientUser from .user import ClientUser
from .asset import Asset from .asset import Asset
@ -216,9 +218,6 @@ class _Overwrites:
return self.type == 1 return self.type == 1
GCH = TypeVar('GCH', bound='GuildChannel')
class GuildChannel: class GuildChannel:
"""An ABC that details the common operations on a Discord guild channel. """An ABC that details the common operations on a Discord guild channel.
@ -817,12 +816,12 @@ class GuildChannel:
raise TypeError('Invalid overwrite type provided.') raise TypeError('Invalid overwrite type provided.')
async def _clone_impl( async def _clone_impl(
self: GCH, self,
base_attrs: Dict[str, Any], base_attrs: Dict[str, Any],
*, *,
name: Optional[str] = None, name: Optional[str] = None,
reason: Optional[str] = None, reason: Optional[str] = None,
) -> GCH: ) -> Self:
base_attrs['permission_overwrites'] = [x._asdict() for x in self._overwrites] base_attrs['permission_overwrites'] = [x._asdict() for x in self._overwrites]
base_attrs['parent_id'] = self.category_id base_attrs['parent_id'] = self.category_id
base_attrs['name'] = name or self.name base_attrs['name'] = name or self.name
@ -835,7 +834,7 @@ class GuildChannel:
self.guild._channels[obj.id] = obj # type: ignore - obj is a GuildChannel self.guild._channels[obj.id] = obj # type: ignore - obj is a GuildChannel
return obj return obj
async def clone(self: GCH, *, name: Optional[str] = None, reason: Optional[str] = None) -> GCH: async def clone(self, *, name: Optional[str] = None, reason: Optional[str] = None) -> Self:
"""|coro| """|coro|
Clones this channel. This creates a channel with the same properties Clones this channel. This creates a channel with the same properties

11
discord/channel.py

@ -37,8 +37,6 @@ from typing import (
Optional, Optional,
TYPE_CHECKING, TYPE_CHECKING,
Tuple, Tuple,
Type,
TypeVar,
Union, Union,
overload, overload,
) )
@ -69,6 +67,8 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .types.threads import ThreadArchiveDuration from .types.threads import ThreadArchiveDuration
from .role import Role from .role import Role
from .member import Member, VoiceState from .member import Member, VoiceState
@ -1827,9 +1827,6 @@ class StoreChannel(discord.abc.GuildChannel, Hashable):
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
DMC = TypeVar('DMC', bound='DMChannel')
class DMChannel(discord.abc.Messageable, Hashable): class DMChannel(discord.abc.Messageable, Hashable):
"""Represents a Discord direct message channel. """Represents a Discord direct message channel.
@ -1883,8 +1880,8 @@ class DMChannel(discord.abc.Messageable, Hashable):
return f'<DMChannel id={self.id} recipient={self.recipient!r}>' return f'<DMChannel id={self.id} recipient={self.recipient!r}>'
@classmethod @classmethod
def _from_message(cls: Type[DMC], state: ConnectionState, channel_id: int) -> DMC: def _from_message(cls, state: ConnectionState, channel_id: int) -> Self:
self: DMC = cls.__new__(cls) self = cls.__new__(cls)
self._state = state self._state = state
self.id = channel_id self.id = channel_id
self.recipient = None self.recipient = None

81
discord/colour.py

@ -21,26 +21,29 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations
import colorsys import colorsys
import random import random
from typing import ( from typing import (
TYPE_CHECKING,
Any, Any,
Callable,
Optional, Optional,
Tuple, Tuple,
Type, Type,
TypeVar,
Union, Union,
) )
if TYPE_CHECKING:
from typing_extensions import Self
__all__ = ( __all__ = (
'Colour', 'Colour',
'Color', 'Color',
) )
CT = TypeVar('CT', bound='Colour')
class Colour: class Colour:
"""Represents a Discord role colour. This class is similar """Represents a Discord role colour. This class is similar
@ -125,23 +128,23 @@ class Colour:
return (self.r, self.g, self.b) return (self.r, self.g, self.b)
@classmethod @classmethod
def from_rgb(cls: Type[CT], r: int, g: int, b: int) -> CT: def from_rgb(cls, r: int, g: int, b: int) -> Self:
"""Constructs a :class:`Colour` from an RGB tuple.""" """Constructs a :class:`Colour` from an RGB tuple."""
return cls((r << 16) + (g << 8) + b) return cls((r << 16) + (g << 8) + b)
@classmethod @classmethod
def from_hsv(cls: Type[CT], h: float, s: float, v: float) -> CT: def from_hsv(cls, h: float, s: float, v: float) -> Self:
"""Constructs a :class:`Colour` from an HSV tuple.""" """Constructs a :class:`Colour` from an HSV tuple."""
rgb = colorsys.hsv_to_rgb(h, s, v) rgb = colorsys.hsv_to_rgb(h, s, v)
return cls.from_rgb(*(int(x * 255) for x in rgb)) return cls.from_rgb(*(int(x * 255) for x in rgb))
@classmethod @classmethod
def default(cls: Type[CT]) -> CT: def default(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0``.""" """A factory method that returns a :class:`Colour` with a value of ``0``."""
return cls(0) return cls(0)
@classmethod @classmethod
def random(cls: Type[CT], *, seed: Optional[Union[int, str, float, bytes, bytearray]] = None) -> CT: def random(cls, *, seed: Optional[Union[int, str, float, bytes, bytearray]] = None) -> Self:
"""A factory method that returns a :class:`Colour` with a random hue. """A factory method that returns a :class:`Colour` with a random hue.
.. note:: .. note::
@ -162,17 +165,17 @@ class Colour:
return cls.from_hsv(rand.random(), 1, 1) return cls.from_hsv(rand.random(), 1, 1)
@classmethod @classmethod
def teal(cls: Type[CT]) -> CT: def teal(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x1abc9c``.""" """A factory method that returns a :class:`Colour` with a value of ``0x1abc9c``."""
return cls(0x1ABC9C) return cls(0x1ABC9C)
@classmethod @classmethod
def dark_teal(cls: Type[CT]) -> CT: def dark_teal(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x11806a``.""" """A factory method that returns a :class:`Colour` with a value of ``0x11806a``."""
return cls(0x11806A) return cls(0x11806A)
@classmethod @classmethod
def brand_green(cls: Type[CT]) -> CT: def brand_green(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x57F287``. """A factory method that returns a :class:`Colour` with a value of ``0x57F287``.
.. versionadded:: 2.0 .. versionadded:: 2.0
@ -180,67 +183,67 @@ class Colour:
return cls(0x57F287) return cls(0x57F287)
@classmethod @classmethod
def green(cls: Type[CT]) -> CT: def green(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x2ecc71``.""" """A factory method that returns a :class:`Colour` with a value of ``0x2ecc71``."""
return cls(0x2ECC71) return cls(0x2ECC71)
@classmethod @classmethod
def dark_green(cls: Type[CT]) -> CT: def dark_green(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x1f8b4c``.""" """A factory method that returns a :class:`Colour` with a value of ``0x1f8b4c``."""
return cls(0x1F8B4C) return cls(0x1F8B4C)
@classmethod @classmethod
def blue(cls: Type[CT]) -> CT: def blue(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x3498db``.""" """A factory method that returns a :class:`Colour` with a value of ``0x3498db``."""
return cls(0x3498DB) return cls(0x3498DB)
@classmethod @classmethod
def dark_blue(cls: Type[CT]) -> CT: def dark_blue(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x206694``.""" """A factory method that returns a :class:`Colour` with a value of ``0x206694``."""
return cls(0x206694) return cls(0x206694)
@classmethod @classmethod
def purple(cls: Type[CT]) -> CT: def purple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x9b59b6``.""" """A factory method that returns a :class:`Colour` with a value of ``0x9b59b6``."""
return cls(0x9B59B6) return cls(0x9B59B6)
@classmethod @classmethod
def dark_purple(cls: Type[CT]) -> CT: def dark_purple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x71368a``.""" """A factory method that returns a :class:`Colour` with a value of ``0x71368a``."""
return cls(0x71368A) return cls(0x71368A)
@classmethod @classmethod
def magenta(cls: Type[CT]) -> CT: def magenta(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe91e63``.""" """A factory method that returns a :class:`Colour` with a value of ``0xe91e63``."""
return cls(0xE91E63) return cls(0xE91E63)
@classmethod @classmethod
def dark_magenta(cls: Type[CT]) -> CT: def dark_magenta(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xad1457``.""" """A factory method that returns a :class:`Colour` with a value of ``0xad1457``."""
return cls(0xAD1457) return cls(0xAD1457)
@classmethod @classmethod
def gold(cls: Type[CT]) -> CT: def gold(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xf1c40f``.""" """A factory method that returns a :class:`Colour` with a value of ``0xf1c40f``."""
return cls(0xF1C40F) return cls(0xF1C40F)
@classmethod @classmethod
def dark_gold(cls: Type[CT]) -> CT: def dark_gold(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xc27c0e``.""" """A factory method that returns a :class:`Colour` with a value of ``0xc27c0e``."""
return cls(0xC27C0E) return cls(0xC27C0E)
@classmethod @classmethod
def orange(cls: Type[CT]) -> CT: def orange(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe67e22``.""" """A factory method that returns a :class:`Colour` with a value of ``0xe67e22``."""
return cls(0xE67E22) return cls(0xE67E22)
@classmethod @classmethod
def dark_orange(cls: Type[CT]) -> CT: def dark_orange(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xa84300``.""" """A factory method that returns a :class:`Colour` with a value of ``0xa84300``."""
return cls(0xA84300) return cls(0xA84300)
@classmethod @classmethod
def brand_red(cls: Type[CT]) -> CT: def brand_red(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xED4245``. """A factory method that returns a :class:`Colour` with a value of ``0xED4245``.
.. versionadded:: 2.0 .. versionadded:: 2.0
@ -248,60 +251,60 @@ class Colour:
return cls(0xED4245) return cls(0xED4245)
@classmethod @classmethod
def red(cls: Type[CT]) -> CT: def red(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe74c3c``.""" """A factory method that returns a :class:`Colour` with a value of ``0xe74c3c``."""
return cls(0xE74C3C) return cls(0xE74C3C)
@classmethod @classmethod
def dark_red(cls: Type[CT]) -> CT: def dark_red(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x992d22``.""" """A factory method that returns a :class:`Colour` with a value of ``0x992d22``."""
return cls(0x992D22) return cls(0x992D22)
@classmethod @classmethod
def lighter_grey(cls: Type[CT]) -> CT: def lighter_grey(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x95a5a6``.""" """A factory method that returns a :class:`Colour` with a value of ``0x95a5a6``."""
return cls(0x95A5A6) return cls(0x95A5A6)
lighter_gray = lighter_grey lighter_gray: Callable[[Type[Self]], Self] = lighter_grey
@classmethod @classmethod
def dark_grey(cls: Type[CT]) -> CT: def dark_grey(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x607d8b``.""" """A factory method that returns a :class:`Colour` with a value of ``0x607d8b``."""
return cls(0x607D8B) return cls(0x607D8B)
dark_gray = dark_grey dark_gray: Callable[[Type[Self]], Self] = dark_grey
@classmethod @classmethod
def light_grey(cls: Type[CT]) -> CT: def light_grey(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x979c9f``.""" """A factory method that returns a :class:`Colour` with a value of ``0x979c9f``."""
return cls(0x979C9F) return cls(0x979C9F)
light_gray = light_grey light_gray: Callable[[Type[Self]], Self] = light_grey
@classmethod @classmethod
def darker_grey(cls: Type[CT]) -> CT: def darker_grey(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x546e7a``.""" """A factory method that returns a :class:`Colour` with a value of ``0x546e7a``."""
return cls(0x546E7A) return cls(0x546E7A)
darker_gray = darker_grey darker_gray: Callable[[Type[Self]], Self] = darker_grey
@classmethod @classmethod
def og_blurple(cls: Type[CT]) -> CT: def og_blurple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x7289da``.""" """A factory method that returns a :class:`Colour` with a value of ``0x7289da``."""
return cls(0x7289DA) return cls(0x7289DA)
@classmethod @classmethod
def blurple(cls: Type[CT]) -> CT: def blurple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x5865F2``.""" """A factory method that returns a :class:`Colour` with a value of ``0x5865F2``."""
return cls(0x5865F2) return cls(0x5865F2)
@classmethod @classmethod
def greyple(cls: Type[CT]) -> CT: def greyple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x99aab5``.""" """A factory method that returns a :class:`Colour` with a value of ``0x99aab5``."""
return cls(0x99AAB5) return cls(0x99AAB5)
@classmethod @classmethod
def dark_theme(cls: Type[CT]) -> CT: def dark_theme(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x36393F``. """A factory method that returns a :class:`Colour` with a value of ``0x36393F``.
This will appear transparent on Discord's dark theme. This will appear transparent on Discord's dark theme.
@ -310,7 +313,7 @@ class Colour:
return cls(0x36393F) return cls(0x36393F)
@classmethod @classmethod
def fuchsia(cls: Type[CT]) -> CT: def fuchsia(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xEB459E``. """A factory method that returns a :class:`Colour` with a value of ``0xEB459E``.
.. versionadded:: 2.0 .. versionadded:: 2.0
@ -318,7 +321,7 @@ class Colour:
return cls(0xEB459E) return cls(0xEB459E)
@classmethod @classmethod
def yellow(cls: Type[CT]) -> CT: def yellow(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xFEE75C``. """A factory method that returns a :class:`Colour` with a value of ``0xFEE75C``.
.. versionadded:: 2.0 .. versionadded:: 2.0

10
discord/components.py

@ -24,12 +24,14 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Tuple, Union
from .enums import try_enum, ComponentType, ButtonStyle, TextStyle from .enums import try_enum, ComponentType, ButtonStyle, TextStyle
from .utils import get_slots, MISSING from .utils import get_slots, MISSING
from .partial_emoji import PartialEmoji, _EmojiTag from .partial_emoji import PartialEmoji, _EmojiTag
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .types.components import ( from .types.components import (
Component as ComponentPayload, Component as ComponentPayload,
ButtonComponent as ButtonComponentPayload, ButtonComponent as ButtonComponentPayload,
@ -50,8 +52,6 @@ __all__ = (
'TextInput', 'TextInput',
) )
C = TypeVar('C', bound='Component')
class Component: class Component:
"""Represents a Discord Bot UI Kit Component. """Represents a Discord Bot UI Kit Component.
@ -82,8 +82,8 @@ class Component:
return f'<{self.__class__.__name__} {attrs}>' return f'<{self.__class__.__name__} {attrs}>'
@classmethod @classmethod
def _raw_construct(cls: Type[C], **kwargs) -> C: def _raw_construct(cls, **kwargs) -> Self:
self: C = cls.__new__(cls) self = cls.__new__(cls)
for slot in get_slots(cls): for slot in get_slots(cls):
try: try:
value = kwargs[slot] value = kwargs[slot]

32
discord/embeds.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
import datetime import datetime
from typing import Any, Dict, Final, List, Mapping, Protocol, TYPE_CHECKING, Type, TypeVar, Union from typing import Any, Dict, Final, List, Mapping, Protocol, TYPE_CHECKING, TypeVar, Union
from . import utils from . import utils
from .colour import Colour from .colour import Colour
@ -66,10 +66,10 @@ class EmbedProxy:
return EmptyEmbed return EmptyEmbed
E = TypeVar('E', bound='Embed')
if TYPE_CHECKING: if TYPE_CHECKING:
from discord.types.embed import Embed as EmbedData, EmbedType from typing_extensions import Self
from .types.embed import Embed as EmbedData, EmbedType
T = TypeVar('T') T = TypeVar('T')
MaybeEmpty = Union[T, _EmptyEmbed] MaybeEmpty = Union[T, _EmptyEmbed]
@ -207,7 +207,7 @@ class Embed:
self.timestamp = timestamp self.timestamp = timestamp
@classmethod @classmethod
def from_dict(cls: Type[E], data: Mapping[str, Any]) -> E: def from_dict(cls, data: Mapping[str, Any]) -> Self:
"""Converts a :class:`dict` to a :class:`Embed` provided it is in the """Converts a :class:`dict` to a :class:`Embed` provided it is in the
format that Discord expects it to be in. format that Discord expects it to be in.
@ -223,7 +223,7 @@ class Embed:
The dictionary to convert into an embed. The dictionary to convert into an embed.
""" """
# we are bypassing __init__ here since it doesn't apply here # we are bypassing __init__ here since it doesn't apply here
self: E = cls.__new__(cls) self = cls.__new__(cls)
# fill in the basic fields # fill in the basic fields
@ -263,7 +263,7 @@ class Embed:
return self return self
def copy(self: E) -> E: def copy(self) -> Self:
"""Returns a shallow copy of the embed.""" """Returns a shallow copy of the embed."""
return self.__class__.from_dict(self.to_dict()) return self.__class__.from_dict(self.to_dict())
@ -347,7 +347,7 @@ class Embed:
# Lying to the type checker for better developer UX. # Lying to the type checker for better developer UX.
return EmbedProxy(getattr(self, '_footer', {})) # type: ignore return EmbedProxy(getattr(self, '_footer', {})) # type: ignore
def set_footer(self: E, *, text: MaybeEmpty[Any] = EmptyEmbed, icon_url: MaybeEmpty[Any] = EmptyEmbed) -> E: def set_footer(self, *, text: MaybeEmpty[Any] = EmptyEmbed, icon_url: MaybeEmpty[Any] = EmptyEmbed) -> Self:
"""Sets the footer for the embed content. """Sets the footer for the embed content.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -370,7 +370,7 @@ class Embed:
return self return self
def remove_footer(self: E) -> E: def remove_footer(self) -> Self:
"""Clears embed's footer information. """Clears embed's footer information.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -401,7 +401,7 @@ class Embed:
# Lying to the type checker for better developer UX. # Lying to the type checker for better developer UX.
return EmbedProxy(getattr(self, '_image', {})) # type: ignore return EmbedProxy(getattr(self, '_image', {})) # type: ignore
def set_image(self: E, *, url: MaybeEmpty[Any]) -> E: def set_image(self, *, url: MaybeEmpty[Any]) -> Self:
"""Sets the image for the embed content. """Sets the image for the embed content.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -444,7 +444,7 @@ class Embed:
# Lying to the type checker for better developer UX. # Lying to the type checker for better developer UX.
return EmbedProxy(getattr(self, '_thumbnail', {})) # type: ignore return EmbedProxy(getattr(self, '_thumbnail', {})) # type: ignore
def set_thumbnail(self: E, *, url: MaybeEmpty[Any]) -> E: def set_thumbnail(self, *, url: MaybeEmpty[Any]) -> Self:
"""Sets the thumbnail for the embed content. """Sets the thumbnail for the embed content.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -508,7 +508,7 @@ class Embed:
# Lying to the type checker for better developer UX. # Lying to the type checker for better developer UX.
return EmbedProxy(getattr(self, '_author', {})) # type: ignore return EmbedProxy(getattr(self, '_author', {})) # type: ignore
def set_author(self: E, *, name: Any, url: MaybeEmpty[Any] = EmptyEmbed, icon_url: MaybeEmpty[Any] = EmptyEmbed) -> E: def set_author(self, *, name: Any, url: MaybeEmpty[Any] = EmptyEmbed, icon_url: MaybeEmpty[Any] = EmptyEmbed) -> Self:
"""Sets the author for the embed content. """Sets the author for the embed content.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -536,7 +536,7 @@ class Embed:
return self return self
def remove_author(self: E) -> E: def remove_author(self) -> Self:
"""Clears embed's author information. """Clears embed's author information.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -562,7 +562,7 @@ class Embed:
# Lying to the type checker for better developer UX. # Lying to the type checker for better developer UX.
return [EmbedProxy(d) for d in getattr(self, '_fields', [])] # type: ignore return [EmbedProxy(d) for d in getattr(self, '_fields', [])] # type: ignore
def add_field(self: E, *, name: Any, value: Any, inline: bool = True) -> E: def add_field(self, *, name: Any, value: Any, inline: bool = True) -> Self:
"""Adds a field to the embed object. """Adds a field to the embed object.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -591,7 +591,7 @@ class Embed:
return self return self
def insert_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool = True) -> E: def insert_field_at(self, index: int, *, name: Any, value: Any, inline: bool = True) -> Self:
"""Inserts a field before a specified index to the embed. """Inserts a field before a specified index to the embed.
This function returns the class instance to allow for fluent-style This function returns the class instance to allow for fluent-style
@ -652,7 +652,7 @@ class Embed:
except (AttributeError, IndexError): except (AttributeError, IndexError):
pass pass
def set_field_at(self: E, index: int, *, name: Any, value: Any, inline: bool = True) -> E: def set_field_at(self, index: int, *, name: Any, value: Any, inline: bool = True) -> Self:
"""Modifies a field to the embed object. """Modifies a field to the embed object.
The index must point to a valid pre-existing field. The index must point to a valid pre-existing field.

6
discord/enums.py

@ -21,6 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations
import types import types
from collections import namedtuple from collections import namedtuple
@ -61,6 +62,9 @@ __all__ = (
'EventStatus', 'EventStatus',
) )
if TYPE_CHECKING:
from typing_extensions import Self
def _create_value_cls(name: str, comparable: bool): def _create_value_cls(name: str, comparable: bool):
# All the type ignores here are due to the type checker being unable to recognise # All the type ignores here are due to the type checker being unable to recognise
@ -87,7 +91,7 @@ class EnumMeta(type):
_enum_member_map_: ClassVar[Dict[str, Any]] _enum_member_map_: ClassVar[Dict[str, Any]]
_enum_value_map_: ClassVar[Dict[Any, Any]] _enum_value_map_: ClassVar[Dict[Any, Any]]
def __new__(cls: Type[type], name: str, bases: Tuple[type, ...], attrs: Dict[str, Any], *, comparable: bool = False): def __new__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any], *, comparable: bool = False) -> Self:
value_mapping = {} value_mapping = {}
member_mapping = {} member_mapping = {}
member_names = [] member_names = []

23
discord/ext/commands/bot.py

@ -45,6 +45,8 @@ from .help import HelpCommand, DefaultHelpCommand
from .cog import Cog from .cog import Cog
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
import importlib.machinery import importlib.machinery
from discord.message import Message from discord.message import Message
@ -934,14 +936,27 @@ class BotBase(GroupMixin):
return ret return ret
@overload @overload
async def get_context(self: BT, message: Message) -> Context[BT]: async def get_context(
self,
message: Message,
) -> Context[Self]: # type: ignore
... ...
@overload @overload
async def get_context(self, message: Message, *, cls: Type[CXT] = ...) -> CXT: async def get_context(
self,
message: Message,
*,
cls: Type[CXT] = ...,
) -> CXT: # type: ignore
... ...
async def get_context(self, message: Message, *, cls: Type[Context] = Context) -> Any: async def get_context(
self,
message: Message,
*,
cls: Type[CXT] = MISSING,
) -> Any:
r"""|coro| r"""|coro|
Returns the invocation context from the message. Returns the invocation context from the message.
@ -970,6 +985,8 @@ class BotBase(GroupMixin):
The invocation context. The type of this can change via the The invocation context. The type of this can change via the
``cls`` parameter. ``cls`` parameter.
""" """
if cls is MISSING:
cls = Context # type: ignore
view = StringView(message.content) view = StringView(message.content)
ctx = cls(prefix=None, view=view, bot=self, message=message) ctx = cls(prefix=None, view=view, bot=self, message=message)

15
discord/ext/commands/cog.py

@ -31,6 +31,8 @@ from typing import Any, Callable, ClassVar, Dict, Generator, List, Optional, TYP
from ._types import _BaseCommand from ._types import _BaseCommand
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .bot import BotBase from .bot import BotBase
from .context import Context from .context import Context
from .core import Command from .core import Command
@ -40,7 +42,6 @@ __all__ = (
'Cog', 'Cog',
) )
CogT = TypeVar('CogT', bound='Cog')
FuncT = TypeVar('FuncT', bound=Callable[..., Any]) FuncT = TypeVar('FuncT', bound=Callable[..., Any])
MISSING: Any = discord.utils.MISSING MISSING: Any = discord.utils.MISSING
@ -111,7 +112,7 @@ class CogMeta(type):
__cog_commands__: List[Command] __cog_commands__: List[Command]
__cog_listeners__: List[Tuple[str, str]] __cog_listeners__: List[Tuple[str, str]]
def __new__(cls: Type[CogMeta], *args: Any, **kwargs: Any) -> CogMeta: def __new__(cls, *args: Any, **kwargs: Any) -> Self:
name, bases, attrs = args name, bases, attrs = args
attrs['__cog_name__'] = kwargs.pop('name', name) attrs['__cog_name__'] = kwargs.pop('name', name)
attrs['__cog_settings__'] = kwargs.pop('command_attrs', {}) attrs['__cog_settings__'] = kwargs.pop('command_attrs', {})
@ -190,10 +191,10 @@ class Cog(metaclass=CogMeta):
__cog_name__: ClassVar[str] __cog_name__: ClassVar[str]
__cog_settings__: ClassVar[Dict[str, Any]] __cog_settings__: ClassVar[Dict[str, Any]]
__cog_commands__: ClassVar[List[Command]] __cog_commands__: ClassVar[List[Command[Self, Any, Any]]]
__cog_listeners__: ClassVar[List[Tuple[str, str]]] __cog_listeners__: ClassVar[List[Tuple[str, str]]]
def __new__(cls: Type[CogT], *args: Any, **kwargs: Any) -> CogT: def __new__(cls, *args: Any, **kwargs: Any) -> Self:
# For issue 426, we need to store a copy of the command objects # For issue 426, we need to store a copy of the command objects
# since we modify them to inject `self` to them. # since we modify them to inject `self` to them.
# To do this, we need to interfere with the Cog creation process. # To do this, we need to interfere with the Cog creation process.
@ -220,7 +221,7 @@ class Cog(metaclass=CogMeta):
return self return self
def get_commands(self) -> List[Command]: def get_commands(self) -> List[Command[Self, Any, Any]]:
r""" r"""
Returns Returns
-------- --------
@ -248,7 +249,7 @@ class Cog(metaclass=CogMeta):
def description(self, description: str) -> None: def description(self, description: str) -> None:
self.__cog_description__ = description self.__cog_description__ = description
def walk_commands(self) -> Generator[Command, None, None]: def walk_commands(self) -> Generator[Command[Self, Any, Any], None, None]:
"""An iterator that recursively walks through this cog's commands and subcommands. """An iterator that recursively walks through this cog's commands and subcommands.
Yields Yields
@ -418,7 +419,7 @@ class Cog(metaclass=CogMeta):
""" """
pass pass
def _inject(self: CogT, bot: BotBase) -> CogT: def _inject(self, bot: BotBase) -> Self:
cls = self.__class__ cls = self.__class__
# realistically, the only thing that can cause loading errors # realistically, the only thing that can cause loading errors

11
discord/ext/commands/cooldowns.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Callable, Deque, Dict, Optional, Type, TypeVar, TYPE_CHECKING from typing import Any, Callable, Deque, Dict, Optional, TYPE_CHECKING
from discord.enums import Enum from discord.enums import Enum
import time import time
import asyncio import asyncio
@ -35,6 +35,8 @@ from ...abc import PrivateChannel
from .errors import MaxConcurrencyReached from .errors import MaxConcurrencyReached
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from ...message import Message from ...message import Message
__all__ = ( __all__ = (
@ -45,9 +47,6 @@ __all__ = (
'MaxConcurrency', 'MaxConcurrency',
) )
C = TypeVar('C', bound='CooldownMapping')
MC = TypeVar('MC', bound='MaxConcurrency')
class BucketType(Enum): class BucketType(Enum):
default = 0 default = 0
@ -221,7 +220,7 @@ class CooldownMapping:
return self._type return self._type
@classmethod @classmethod
def from_cooldown(cls: Type[C], rate, per, type) -> C: def from_cooldown(cls, rate, per, type) -> Self:
return cls(Cooldown(rate, per), type) return cls(Cooldown(rate, per), type)
def _bucket_key(self, msg: Message) -> Any: def _bucket_key(self, msg: Message) -> Any:
@ -356,7 +355,7 @@ class MaxConcurrency:
if not isinstance(per, BucketType): if not isinstance(per, BucketType):
raise TypeError(f'max_concurrency \'per\' must be of type BucketType not {type(per)!r}') raise TypeError(f'max_concurrency \'per\' must be of type BucketType not {type(per)!r}')
def copy(self: MC) -> MC: def copy(self) -> Self:
return self.__class__(self.number, per=self.per, wait=self.wait) return self.__class__(self.number, per=self.per, wait=self.wait)
def __repr__(self) -> str: def __repr__(self) -> str:

12
discord/ext/commands/core.py

@ -56,7 +56,7 @@ from .context import Context
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Concatenate, ParamSpec, TypeGuard from typing_extensions import Concatenate, ParamSpec, TypeGuard, Self
from discord.message import Message from discord.message import Message
@ -292,7 +292,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
""" """
__original_kwargs__: Dict[str, Any] __original_kwargs__: Dict[str, Any]
def __new__(cls: Type[CommandT], *args: Any, **kwargs: Any) -> CommandT: def __new__(cls, *args: Any, **kwargs: Any) -> Self:
# if you're wondering why this is done, it's because we need to ensure # if you're wondering why this is done, it's because we need to ensure
# we have a complete original copy of **kwargs even for classes that # we have a complete original copy of **kwargs even for classes that
# mess with it by popping before delegating to the subclass __init__. # mess with it by popping before delegating to the subclass __init__.
@ -498,7 +498,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
else: else:
return await self.callback(context, *args, **kwargs) # type: ignore return await self.callback(context, *args, **kwargs) # type: ignore
def _ensure_assignment_on_copy(self, other: CommandT) -> CommandT: def _ensure_assignment_on_copy(self, other: Self) -> Self:
other._before_invoke = self._before_invoke other._before_invoke = self._before_invoke
other._after_invoke = self._after_invoke other._after_invoke = self._after_invoke
if self.checks != other.checks: if self.checks != other.checks:
@ -515,7 +515,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
pass pass
return other return other
def copy(self: CommandT) -> CommandT: def copy(self) -> Self:
"""Creates a copy of this command. """Creates a copy of this command.
Returns Returns
@ -526,7 +526,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
ret = self.__class__(self.callback, **self.__original_kwargs__) ret = self.__class__(self.callback, **self.__original_kwargs__)
return self._ensure_assignment_on_copy(ret) return self._ensure_assignment_on_copy(ret)
def _update_copy(self: CommandT, kwargs: Dict[str, Any]) -> CommandT: def _update_copy(self, kwargs: Dict[str, Any]) -> Self:
if kwargs: if kwargs:
kw = kwargs.copy() kw = kwargs.copy()
kw.update(self.__original_kwargs__) kw.update(self.__original_kwargs__)
@ -1446,7 +1446,7 @@ class Group(GroupMixin[CogT], Command[CogT, P, T]):
self.invoke_without_command: bool = attrs.pop('invoke_without_command', False) self.invoke_without_command: bool = attrs.pop('invoke_without_command', False)
super().__init__(*args, **attrs) super().__init__(*args, **attrs)
def copy(self: GroupT) -> GroupT: def copy(self) -> Self:
"""Creates a copy of this :class:`Group`. """Creates a copy of this :class:`Group`.
Returns Returns

17
discord/ext/commands/flags.py

@ -66,6 +66,8 @@ __all__ = (
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .context import Context from .context import Context
@ -265,7 +267,7 @@ class FlagsMeta(type):
__commands_flag_prefix__: str __commands_flag_prefix__: str
def __new__( def __new__(
cls: Type[type], cls,
name: str, name: str,
bases: Tuple[type, ...], bases: Tuple[type, ...],
attrs: Dict[str, Any], attrs: Dict[str, Any],
@ -273,7 +275,7 @@ class FlagsMeta(type):
case_insensitive: bool = MISSING, case_insensitive: bool = MISSING,
delimiter: str = MISSING, delimiter: str = MISSING,
prefix: str = MISSING, prefix: str = MISSING,
): ) -> Self:
attrs['__commands_is_flag__'] = True attrs['__commands_is_flag__'] = True
try: try:
@ -432,9 +434,6 @@ async def convert_flag(ctx, argument: str, flag: Flag, annotation: Any = None) -
raise BadFlagArgument(flag) from e raise BadFlagArgument(flag) from e
F = TypeVar('F', bound='FlagConverter')
class FlagConverter(metaclass=FlagsMeta): class FlagConverter(metaclass=FlagsMeta):
"""A converter that allows for a user-friendly flag syntax. """A converter that allows for a user-friendly flag syntax.
@ -481,8 +480,8 @@ class FlagConverter(metaclass=FlagsMeta):
yield (flag.name, getattr(self, flag.attribute)) yield (flag.name, getattr(self, flag.attribute))
@classmethod @classmethod
async def _construct_default(cls: Type[F], ctx: Context) -> F: async def _construct_default(cls, ctx: Context) -> Self:
self: F = cls.__new__(cls) self = cls.__new__(cls)
flags = cls.__commands_flags__ flags = cls.__commands_flags__
for flag in flags.values(): for flag in flags.values():
if callable(flag.default): if callable(flag.default):
@ -547,7 +546,7 @@ class FlagConverter(metaclass=FlagsMeta):
return result return result
@classmethod @classmethod
async def convert(cls: Type[F], ctx: Context, argument: str) -> F: async def convert(cls, ctx: Context, argument: str) -> Self:
"""|coro| """|coro|
The method that actually converters an argument to the flag mapping. The method that actually converters an argument to the flag mapping.
@ -576,7 +575,7 @@ class FlagConverter(metaclass=FlagsMeta):
arguments = cls.parse_flags(argument) arguments = cls.parse_flags(argument)
flags = cls.__commands_flags__ flags = cls.__commands_flags__
self: F = cls.__new__(cls) self = cls.__new__(cls)
for name, flag in flags.items(): for name, flag in flags.items():
try: try:
values = arguments[name] values = arguments[name]

9
discord/flags.py

@ -24,10 +24,14 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Callable, ClassVar, Dict, Generic, Iterator, List, Optional, Tuple, Type, TypeVar, overload from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, overload
from .enums import UserFlags from .enums import UserFlags
if TYPE_CHECKING:
from typing_extensions import Self
__all__ = ( __all__ = (
'SystemChannelFlags', 'SystemChannelFlags',
'MessageFlags', 'MessageFlags',
@ -37,7 +41,6 @@ __all__ = (
'ApplicationFlags', 'ApplicationFlags',
) )
FV = TypeVar('FV', bound='flag_value')
BF = TypeVar('BF', bound='BaseFlags') BF = TypeVar('BF', bound='BaseFlags')
@ -47,7 +50,7 @@ class flag_value:
self.__doc__ = func.__doc__ self.__doc__ = func.__doc__
@overload @overload
def __get__(self: FV, instance: None, owner: Type[BF]) -> FV: def __get__(self, instance: None, owner: Type[BF]) -> Self:
... ...
@overload @overload

5
discord/http.py

@ -59,6 +59,8 @@ from .utils import MISSING
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .ui.view import View from .ui.view import View
from .embeds import Embed from .embeds import Embed
from .mentions import AllowedMentions from .mentions import AllowedMentions
@ -100,7 +102,6 @@ if TYPE_CHECKING:
T = TypeVar('T') T = TypeVar('T')
BE = TypeVar('BE', bound=BaseException) BE = TypeVar('BE', bound=BaseException)
MU = TypeVar('MU', bound='MaybeUnlock')
Response = Coroutine[Any, Any, T] Response = Coroutine[Any, Any, T]
@ -287,7 +288,7 @@ class MaybeUnlock:
self.lock: asyncio.Lock = lock self.lock: asyncio.Lock = lock
self._unlock: bool = True self._unlock: bool = True
def __enter__(self: MU) -> MU: def __enter__(self) -> Self:
return self return self
def defer(self) -> None: def defer(self) -> None:

13
discord/invite.py

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import List, Optional, Type, TypeVar, Union, TYPE_CHECKING from typing import List, Optional, Union, TYPE_CHECKING
from .asset import Asset from .asset import Asset
from .utils import parse_time, snowflake_time, _get_as_snowflake from .utils import parse_time, snowflake_time, _get_as_snowflake
from .object import Object from .object import Object
@ -40,6 +40,8 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .types.invite import ( from .types.invite import (
Invite as InvitePayload, Invite as InvitePayload,
InviteGuild as InviteGuildPayload, InviteGuild as InviteGuildPayload,
@ -205,9 +207,6 @@ class PartialInviteGuild:
return Asset._from_guild_image(self._state, self.id, self._splash, path='splashes') return Asset._from_guild_image(self._state, self.id, self._splash, path='splashes')
I = TypeVar('I', bound='Invite')
class Invite(Hashable): class Invite(Hashable):
r"""Represents a Discord :class:`Guild` or :class:`abc.GuildChannel` invite. r"""Represents a Discord :class:`Guild` or :class:`abc.GuildChannel` invite.
@ -390,7 +389,7 @@ class Invite(Hashable):
self.scheduled_event_id: Optional[int] = self.scheduled_event.id if self.scheduled_event else None self.scheduled_event_id: Optional[int] = self.scheduled_event.id if self.scheduled_event else None
@classmethod @classmethod
def from_incomplete(cls: Type[I], *, state: ConnectionState, data: InvitePayload) -> I: def from_incomplete(cls, *, state: ConnectionState, data: InvitePayload) -> Self:
guild: Optional[Union[Guild, PartialInviteGuild]] guild: Optional[Union[Guild, PartialInviteGuild]]
try: try:
guild_data = data['guild'] guild_data = data['guild']
@ -414,7 +413,7 @@ class Invite(Hashable):
return cls(state=state, data=data, guild=guild, channel=channel) return cls(state=state, data=data, guild=guild, channel=channel)
@classmethod @classmethod
def from_gateway(cls: Type[I], *, state: ConnectionState, data: GatewayInvitePayload) -> I: def from_gateway(cls, *, state: ConnectionState, data: GatewayInvitePayload) -> Self:
guild_id: Optional[int] = _get_as_snowflake(data, 'guild_id') guild_id: Optional[int] = _get_as_snowflake(data, 'guild_id')
guild: Optional[Union[Guild, Object]] = state._get_guild(guild_id) guild: Optional[Union[Guild, Object]] = state._get_guild(guild_id)
channel_id = int(data['channel_id']) channel_id = int(data['channel_id'])
@ -479,7 +478,7 @@ class Invite(Hashable):
url += '?event=' + str(self.scheduled_event_id) url += '?event=' + str(self.scheduled_event_id)
return url return url
def set_scheduled_event(self: I, scheduled_event: Snowflake, /) -> I: def set_scheduled_event(self, scheduled_event: Snowflake, /) -> Self:
"""Sets the scheduled event for this invite. """Sets the scheduled event for this invite.
.. versionadded:: 2.0 .. versionadded:: 2.0

15
discord/member.py

@ -29,7 +29,7 @@ import inspect
import itertools import itertools
import sys import sys
from operator import attrgetter from operator import attrgetter
from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union, overload from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING, Tuple, Union
import discord.abc import discord.abc
@ -49,6 +49,8 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .asset import Asset from .asset import Asset
from .channel import DMChannel, VoiceChannel, StageChannel from .channel import DMChannel, VoiceChannel, StageChannel
from .flags import PublicUserFlags from .flags import PublicUserFlags
@ -203,9 +205,6 @@ def flatten_user(cls):
return cls return cls
M = TypeVar('M', bound='Member')
@flatten_user @flatten_user
class Member(discord.abc.Messageable, _UserTag): class Member(discord.abc.Messageable, _UserTag):
"""Represents a Discord member to a :class:`Guild`. """Represents a Discord member to a :class:`Guild`.
@ -329,7 +328,7 @@ class Member(discord.abc.Messageable, _UserTag):
return hash(self._user) return hash(self._user)
@classmethod @classmethod
def _from_message(cls: Type[M], *, message: Message, data: MemberPayload) -> M: def _from_message(cls, *, message: Message, data: MemberPayload) -> Self:
author = message.author author = message.author
data['user'] = author._to_minimal_user_json() # type: ignore data['user'] = author._to_minimal_user_json() # type: ignore
return cls(data=data, guild=message.guild, state=message._state) # type: ignore return cls(data=data, guild=message.guild, state=message._state) # type: ignore
@ -343,7 +342,7 @@ class Member(discord.abc.Messageable, _UserTag):
self.timed_out_until = utils.parse_time(data.get('communication_disabled_until')) self.timed_out_until = utils.parse_time(data.get('communication_disabled_until'))
@classmethod @classmethod
def _try_upgrade(cls: Type[M], *, data: UserWithMemberPayload, guild: Guild, state: ConnectionState) -> Union[User, M]: def _try_upgrade(cls, *, data: UserWithMemberPayload, guild: Guild, state: ConnectionState) -> Union[User, Self]:
# A User object with a 'member' key # A User object with a 'member' key
try: try:
member_data = data.pop('member') member_data = data.pop('member')
@ -354,8 +353,8 @@ class Member(discord.abc.Messageable, _UserTag):
return cls(data=member_data, guild=guild, state=state) # type: ignore return cls(data=member_data, guild=guild, state=state) # type: ignore
@classmethod @classmethod
def _copy(cls: Type[M], member: M) -> M: def _copy(cls, member: Self) -> Self:
self: M = cls.__new__(cls) # to bypass __init__ self = cls.__new__(cls) # to bypass __init__
self._roles = utils.SnowflakeList(member._roles, is_sorted=True) self._roles = utils.SnowflakeList(member._roles, is_sorted=True)
self.joined_at = member.joined_at self.joined_at = member.joined_at

10
discord/mentions.py

@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
from typing import Type, TypeVar, Union, List, TYPE_CHECKING, Any, Union from typing import Union, List, TYPE_CHECKING, Any, Union
# fmt: off # fmt: off
__all__ = ( __all__ = (
@ -32,6 +32,8 @@ __all__ = (
# fmt: on # fmt: on
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .types.message import AllowedMentions as AllowedMentionsPayload from .types.message import AllowedMentions as AllowedMentionsPayload
from .abc import Snowflake from .abc import Snowflake
@ -49,8 +51,6 @@ class _FakeBool:
default: Any = _FakeBool() default: Any = _FakeBool()
A = TypeVar('A', bound='AllowedMentions')
class AllowedMentions: class AllowedMentions:
"""A class that represents what mentions are allowed in a message. """A class that represents what mentions are allowed in a message.
@ -98,7 +98,7 @@ class AllowedMentions:
self.replied_user = replied_user self.replied_user = replied_user
@classmethod @classmethod
def all(cls: Type[A]) -> A: def all(cls) -> Self:
"""A factory method that returns a :class:`AllowedMentions` with all fields explicitly set to ``True`` """A factory method that returns a :class:`AllowedMentions` with all fields explicitly set to ``True``
.. versionadded:: 1.5 .. versionadded:: 1.5
@ -106,7 +106,7 @@ class AllowedMentions:
return cls(everyone=True, users=True, roles=True, replied_user=True) return cls(everyone=True, users=True, roles=True, replied_user=True)
@classmethod @classmethod
def none(cls: Type[A]) -> A: def none(cls) -> Self:
"""A factory method that returns a :class:`AllowedMentions` with all fields set to ``False`` """A factory method that returns a :class:`AllowedMentions` with all fields set to ``False``
.. versionadded:: 1.5 .. versionadded:: 1.5

9
discord/message.py

@ -41,8 +41,6 @@ from typing import (
ClassVar, ClassVar,
Optional, Optional,
overload, overload,
TypeVar,
Type,
) )
from . import utils from . import utils
@ -65,6 +63,8 @@ from .threads import Thread
from .channel import PartialMessageable from .channel import PartialMessageable
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .types.message import ( from .types.message import (
Message as MessagePayload, Message as MessagePayload,
Attachment as AttachmentPayload, Attachment as AttachmentPayload,
@ -93,7 +93,6 @@ if TYPE_CHECKING:
from .role import Role from .role import Role
from .ui.view import View from .ui.view import View
MR = TypeVar('MR', bound='MessageReference')
EmojiInputType = Union[Emoji, PartialEmoji, str] EmojiInputType = Union[Emoji, PartialEmoji, str]
__all__ = ( __all__ = (
@ -425,7 +424,7 @@ class MessageReference:
self.fail_if_not_exists: bool = fail_if_not_exists self.fail_if_not_exists: bool = fail_if_not_exists
@classmethod @classmethod
def with_state(cls: Type[MR], state: ConnectionState, data: MessageReferencePayload) -> MR: def with_state(cls, state: ConnectionState, data: MessageReferencePayload) -> Self:
self = cls.__new__(cls) self = cls.__new__(cls)
self.message_id = utils._get_as_snowflake(data, 'message_id') self.message_id = utils._get_as_snowflake(data, 'message_id')
self.channel_id = int(data.pop('channel_id')) self.channel_id = int(data.pop('channel_id'))
@ -436,7 +435,7 @@ class MessageReference:
return self return self
@classmethod @classmethod
def from_message(cls: Type[MR], message: Message, *, fail_if_not_exists: bool = True) -> MR: def from_message(cls, message: Message, *, fail_if_not_exists: bool = True) -> Self:
"""Creates a :class:`MessageReference` from an existing :class:`~discord.Message`. """Creates a :class:`MessageReference` from an existing :class:`~discord.Message`.
.. versionadded:: 1.6 .. versionadded:: 1.6

20
discord/partial_emoji.py

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict, Optional, TYPE_CHECKING, Type, TypeVar, Union from typing import Any, Dict, Optional, TYPE_CHECKING, Union
import re import re
from .asset import Asset, AssetMixin from .asset import Asset, AssetMixin
@ -37,6 +37,8 @@ __all__ = (
# fmt: on # fmt: on
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .state import ConnectionState from .state import ConnectionState
from datetime import datetime from datetime import datetime
from .types.message import PartialEmoji as PartialEmojiPayload from .types.message import PartialEmoji as PartialEmojiPayload
@ -51,9 +53,6 @@ class _EmojiTag:
raise NotImplementedError raise NotImplementedError
PE = TypeVar('PE', bound='PartialEmoji')
class PartialEmoji(_EmojiTag, AssetMixin): class PartialEmoji(_EmojiTag, AssetMixin):
"""Represents a "partial" emoji. """Represents a "partial" emoji.
@ -106,7 +105,7 @@ class PartialEmoji(_EmojiTag, AssetMixin):
self._state: Optional[ConnectionState] = None self._state: Optional[ConnectionState] = None
@classmethod @classmethod
def from_dict(cls: Type[PE], data: Union[PartialEmojiPayload, Dict[str, Any]]) -> PE: def from_dict(cls, data: Union[PartialEmojiPayload, Dict[str, Any]]) -> Self:
return cls( return cls(
animated=data.get('animated', False), animated=data.get('animated', False),
id=utils._get_as_snowflake(data, 'id'), id=utils._get_as_snowflake(data, 'id'),
@ -114,7 +113,7 @@ class PartialEmoji(_EmojiTag, AssetMixin):
) )
@classmethod @classmethod
def from_str(cls: Type[PE], value: str) -> PE: def from_str(cls, value: str) -> Self:
"""Converts a Discord string representation of an emoji to a :class:`PartialEmoji`. """Converts a Discord string representation of an emoji to a :class:`PartialEmoji`.
The formats accepted are: The formats accepted are:
@ -161,8 +160,13 @@ class PartialEmoji(_EmojiTag, AssetMixin):
@classmethod @classmethod
def with_state( def with_state(
cls: Type[PE], state: ConnectionState, *, name: str, animated: bool = False, id: Optional[int] = None cls,
) -> PE: state: ConnectionState,
*,
name: str,
animated: bool = False,
id: Optional[int] = None,
) -> Self:
self = cls(name=name, animated=animated, id=id) self = cls(name=name, animated=animated, id=id)
self._state = state self._state = state
return self return self

31
discord/permissions.py

@ -32,6 +32,9 @@ __all__ = (
'PermissionOverwrite', 'PermissionOverwrite',
) )
if TYPE_CHECKING:
from typing_extensions import Self
# A permission alias works like a regular flag but is marked # A permission alias works like a regular flag but is marked
# So the PermissionOverwrite knows to work with it # So the PermissionOverwrite knows to work with it
class permission_alias(alias_flag_value): class permission_alias(alias_flag_value):
@ -47,9 +50,6 @@ def make_permission_alias(alias: str) -> Callable[[Callable[[Any], int]], permis
return decorator return decorator
P = TypeVar('P', bound='Permissions')
@fill_with_flags() @fill_with_flags()
class Permissions(BaseFlags): class Permissions(BaseFlags):
"""Wraps up the Discord permission value. """Wraps up the Discord permission value.
@ -139,20 +139,20 @@ class Permissions(BaseFlags):
__gt__ = is_strict_superset __gt__ = is_strict_superset
@classmethod @classmethod
def none(cls: Type[P]) -> P: def none(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
permissions set to ``False``.""" permissions set to ``False``."""
return cls(0) return cls(0)
@classmethod @classmethod
def all(cls: Type[P]) -> P: def all(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
permissions set to ``True``. permissions set to ``True``.
""" """
return cls(0b11111111111111111111111111111111111111111) return cls(0b11111111111111111111111111111111111111111)
@classmethod @classmethod
def all_channel(cls: Type[P]) -> P: def all_channel(cls) -> Self:
"""A :class:`Permissions` with all channel-specific permissions set to """A :class:`Permissions` with all channel-specific permissions set to
``True`` and the guild-specific ones set to ``False``. The guild-specific ``True`` and the guild-specific ones set to ``False``. The guild-specific
permissions are currently: permissions are currently:
@ -178,7 +178,7 @@ class Permissions(BaseFlags):
return cls(0b111110110110011111101111111111101010001) return cls(0b111110110110011111101111111111101010001)
@classmethod @classmethod
def general(cls: Type[P]) -> P: def general(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"General" permissions from the official Discord UI set to ``True``. "General" permissions from the official Discord UI set to ``True``.
@ -191,7 +191,7 @@ class Permissions(BaseFlags):
return cls(0b01110000000010000000010010110000) return cls(0b01110000000010000000010010110000)
@classmethod @classmethod
def membership(cls: Type[P]) -> P: def membership(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Membership" permissions from the official Discord UI set to ``True``. "Membership" permissions from the official Discord UI set to ``True``.
@ -200,7 +200,7 @@ class Permissions(BaseFlags):
return cls(0b10000000000001100000000000000000000000111) return cls(0b10000000000001100000000000000000000000111)
@classmethod @classmethod
def text(cls: Type[P]) -> P: def text(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Text" permissions from the official Discord UI set to ``True``. "Text" permissions from the official Discord UI set to ``True``.
@ -215,13 +215,13 @@ class Permissions(BaseFlags):
return cls(0b111110010000000000001111111100001000000) return cls(0b111110010000000000001111111100001000000)
@classmethod @classmethod
def voice(cls: Type[P]) -> P: def voice(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Voice" permissions from the official Discord UI set to ``True``.""" "Voice" permissions from the official Discord UI set to ``True``."""
return cls(0b1000000000000011111100000000001100000000) return cls(0b1000000000000011111100000000001100000000)
@classmethod @classmethod
def stage(cls: Type[P]) -> P: def stage(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Stage Channel" permissions from the official Discord UI set to ``True``. "Stage Channel" permissions from the official Discord UI set to ``True``.
@ -230,7 +230,7 @@ class Permissions(BaseFlags):
return cls(1 << 32) return cls(1 << 32)
@classmethod @classmethod
def stage_moderator(cls: Type[P]) -> P: def stage_moderator(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Stage Moderator" permissions from the official Discord UI set to ``True``. "Stage Moderator" permissions from the official Discord UI set to ``True``.
@ -239,7 +239,7 @@ class Permissions(BaseFlags):
return cls(0b100000001010000000000000000000000) return cls(0b100000001010000000000000000000000)
@classmethod @classmethod
def advanced(cls: Type[P]) -> P: def advanced(cls) -> Self:
"""A factory method that creates a :class:`Permissions` with all """A factory method that creates a :class:`Permissions` with all
"Advanced" permissions from the official Discord UI set to ``True``. "Advanced" permissions from the official Discord UI set to ``True``.
@ -570,9 +570,6 @@ class Permissions(BaseFlags):
return 1 << 40 return 1 << 40
PO = TypeVar('PO', bound='PermissionOverwrite')
def _augment_from_permissions(cls): def _augment_from_permissions(cls):
cls.VALID_NAMES = set(Permissions.VALID_FLAGS) cls.VALID_NAMES = set(Permissions.VALID_FLAGS)
aliases = set() aliases = set()
@ -721,7 +718,7 @@ class PermissionOverwrite:
return allow, deny return allow, deny
@classmethod @classmethod
def from_pair(cls: Type[PO], allow: Permissions, deny: Permissions) -> PO: def from_pair(cls, allow: Permissions, deny: Permissions) -> Self:
"""Creates an overwrite from an allow/deny pair of :class:`Permissions`.""" """Creates an overwrite from an allow/deny pair of :class:`Permissions`."""
ret = cls() ret = cls()
for key, value in allow: for key, value in allow:

9
discord/player.py

@ -36,7 +36,7 @@ import sys
import re import re
import io import io
from typing import Any, Callable, Generic, IO, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union from typing import Any, Callable, Generic, IO, Optional, TYPE_CHECKING, Tuple, TypeVar, Union
from .enums import SpeakingState from .enums import SpeakingState
from .errors import ClientException from .errors import ClientException
@ -45,11 +45,12 @@ from .oggparse import OggStream
from .utils import MISSING from .utils import MISSING
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .voice_client import VoiceClient from .voice_client import VoiceClient
AT = TypeVar('AT', bound='AudioSource') AT = TypeVar('AT', bound='AudioSource')
FT = TypeVar('FT', bound='FFmpegOpusAudio')
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
@ -402,12 +403,12 @@ class FFmpegOpusAudio(FFmpegAudio):
@classmethod @classmethod
async def from_probe( async def from_probe(
cls: Type[FT], cls,
source: str, source: str,
*, *,
method: Optional[Union[str, Callable[[str, str], Tuple[Optional[str], Optional[int]]]]] = None, method: Optional[Union[str, Callable[[str, str], Tuple[Optional[str], Optional[int]]]]] = None,
**kwargs: Any, **kwargs: Any,
) -> FT: ) -> Self:
"""|coro| """|coro|
A factory method that creates a :class:`FFmpegOpusAudio` after probing A factory method that creates a :class:`FFmpegOpusAudio` after probing

15
discord/role.py

@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict, List, Optional, TypeVar, Union, overload, TYPE_CHECKING from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
from .asset import Asset from .asset import Asset
from .permissions import Permissions from .permissions import Permissions
@ -37,6 +37,8 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
import datetime import datetime
from .types.role import ( from .types.role import (
Role as RolePayload, Role as RolePayload,
@ -101,9 +103,6 @@ class RoleTags:
) )
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`.
@ -212,7 +211,7 @@ class Role(Hashable):
def __repr__(self) -> str: 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: R, other: R) -> bool: def __lt__(self, other: Any) -> 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
@ -233,16 +232,16 @@ class Role(Hashable):
return False return False
def __le__(self: R, other: R) -> bool: def __le__(self, other: Any) -> 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: R, other: R) -> bool: def __gt__(self, other: Any) -> bool:
return Role.__lt__(other, self) return Role.__lt__(other, self)
def __ge__(self: R, other: R) -> bool: def __ge__(self, other: Any) -> bool:
r = Role.__lt__(self, other) r = Role.__lt__(self, other)
if r is NotImplemented: if r is NotImplemented:
return NotImplemented return NotImplemented

8
discord/shard.py

@ -43,15 +43,13 @@ from .errors import (
from .enums import Status from .enums import Status
from typing import TYPE_CHECKING, Any, Callable, Tuple, Type, Optional, List, Dict, TypeVar from typing import TYPE_CHECKING, Any, Callable, Tuple, Type, Optional, List, Dict
if TYPE_CHECKING: if TYPE_CHECKING:
from .gateway import DiscordWebSocket from .gateway import DiscordWebSocket
from .activity import BaseActivity from .activity import BaseActivity
from .enums import Status from .enums import Status
EI = TypeVar('EI', bound='EventItem')
__all__ = ( __all__ = (
'AutoShardedClient', 'AutoShardedClient',
'ShardInfo', 'ShardInfo',
@ -77,12 +75,12 @@ class EventItem:
self.shard: Optional['Shard'] = shard self.shard: Optional['Shard'] = shard
self.error: Optional[Exception] = error self.error: Optional[Exception] = error
def __lt__(self: EI, other: EI) -> bool: def __lt__(self, other: Any) -> bool:
if not isinstance(other, EventItem): if not isinstance(other, EventItem):
return NotImplemented return NotImplemented
return self.type < other.type return self.type < other.type
def __eq__(self: EI, other: EI) -> bool: def __eq__(self, other: Any) -> bool:
if not isinstance(other, EventItem): if not isinstance(other, EventItem):
return NotImplemented return NotImplemented
return self.type == other.type return self.type == other.type

1
discord/state.py

@ -82,7 +82,6 @@ if TYPE_CHECKING:
from .types import gateway as gw from .types import gateway as gw
T = TypeVar('T') T = TypeVar('T')
CS = TypeVar('CS', bound='ConnectionState')
Channel = Union[GuildChannel, VocalGuildChannel, PrivateChannel, PartialMessageable] Channel = Union[GuildChannel, VocalGuildChannel, PrivateChannel, PartialMessageable]

7
discord/ui/button.py

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Callable, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union from typing import Callable, Optional, TYPE_CHECKING, Tuple, TypeVar, Union
import inspect import inspect
import os import os
@ -40,10 +40,11 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .view import View from .view import View
from ..emoji import Emoji from ..emoji import Emoji
B = TypeVar('B', bound='Button')
V = TypeVar('V', bound='View', covariant=True) V = TypeVar('V', bound='View', covariant=True)
@ -196,7 +197,7 @@ class Button(Item[V]):
self._underlying.emoji = None self._underlying.emoji = None
@classmethod @classmethod
def from_component(cls: Type[B], button: ButtonComponent) -> B: def from_component(cls, button: ButtonComponent) -> Self:
return cls( return cls(
style=button.style, style=button.style,
label=button.label, label=button.label,

5
discord/ui/select.py

@ -43,13 +43,14 @@ __all__ = (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from .view import View from .view import View
from ..types.components import SelectMenu as SelectMenuPayload from ..types.components import SelectMenu as SelectMenuPayload
from ..types.interactions import ( from ..types.interactions import (
MessageComponentInteractionData, MessageComponentInteractionData,
) )
S = TypeVar('S', bound='Select')
V = TypeVar('V', bound='View', covariant=True) V = TypeVar('V', bound='View', covariant=True)
@ -272,7 +273,7 @@ class Select(Item[V]):
self._selected_values = data.get('values', []) self._selected_values = data.get('values', [])
@classmethod @classmethod
def from_component(cls: Type[S], component: SelectMenu) -> S: def from_component(cls, component: SelectMenu) -> Self:
return cls( return cls(
custom_id=component.custom_id, custom_id=component.custom_id,
placeholder=component.placeholder, placeholder=component.placeholder,

7
discord/ui/text_input.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
import os import os
from typing import TYPE_CHECKING, Optional, Tuple, Type, TypeVar from typing import TYPE_CHECKING, Optional, Tuple, TypeVar
from ..components import TextInput as TextInputComponent from ..components import TextInput as TextInputComponent
from ..enums import ComponentType, TextStyle from ..enums import ComponentType, TextStyle
@ -33,6 +33,8 @@ from ..utils import MISSING
from .item import Item from .item import Item
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from ..types.components import TextInput as TextInputPayload from ..types.components import TextInput as TextInputPayload
from ..types.interactions import ModalSubmitTextInputInteractionData as ModalSubmitTextInputInteractionDataPayload from ..types.interactions import ModalSubmitTextInputInteractionData as ModalSubmitTextInputInteractionDataPayload
from .view import View from .view import View
@ -45,7 +47,6 @@ __all__ = (
# fmt: on # fmt: on
V = TypeVar('V', bound='View', covariant=True) V = TypeVar('V', bound='View', covariant=True)
TI = TypeVar('TI', bound='TextInput')
class TextInput(Item[V]): class TextInput(Item[V]):
@ -210,7 +211,7 @@ class TextInput(Item[V]):
self._value = data.get('value', None) self._value = data.get('value', None)
@classmethod @classmethod
def from_component(cls: Type[TI], component: TextInputComponent) -> TI: def from_component(cls, component: TextInputComponent) -> Self:
return cls( return cls(
label=component.label, label=component.label,
style=component.style, style=component.style,

8
discord/user.py

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict, List, Optional, Union, Type, TypeVar, TYPE_CHECKING from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union
import discord.abc import discord.abc
from .asset import Asset from .asset import Asset
@ -34,6 +34,8 @@ from .flags import PublicUserFlags
from .utils import snowflake_time, _bytes_to_base64_data, MISSING from .utils import snowflake_time, _bytes_to_base64_data, MISSING
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self
from datetime import datetime from datetime import datetime
from .channel import DMChannel from .channel import DMChannel
@ -52,8 +54,6 @@ __all__ = (
'ClientUser', 'ClientUser',
) )
BU = TypeVar('BU', bound='BaseUser')
class _UserTag: class _UserTag:
__slots__ = () __slots__ = ()
@ -120,7 +120,7 @@ class BaseUser(_UserTag):
self.system = data.get('system', False) self.system = data.get('system', False)
@classmethod @classmethod
def _copy(cls: Type[BU], user: BU) -> BU: def _copy(cls, user: Self) -> Self:
self = cls.__new__(cls) # bypass __init__ self = cls.__new__(cls) # bypass __init__
self.name = user.name self.name = user.name

2
discord/webhook/sync.py

@ -37,7 +37,7 @@ import time
import re import re
from urllib.parse import quote as urlquote from urllib.parse import quote as urlquote
from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union, overload from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING, Tuple, Union, overload
import weakref import weakref
from .. import utils from .. import utils

Loading…
Cancel
Save