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

11
discord/channel.py

@ -37,8 +37,6 @@ from typing import (
Optional,
TYPE_CHECKING,
Tuple,
Type,
TypeVar,
Union,
overload,
)
@ -69,6 +67,8 @@ __all__ = (
)
if TYPE_CHECKING:
from typing_extensions import Self
from .types.threads import ThreadArchiveDuration
from .role import Role
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
DMC = TypeVar('DMC', bound='DMChannel')
class DMChannel(discord.abc.Messageable, Hashable):
"""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}>'
@classmethod
def _from_message(cls: Type[DMC], state: ConnectionState, channel_id: int) -> DMC:
self: DMC = cls.__new__(cls)
def _from_message(cls, state: ConnectionState, channel_id: int) -> Self:
self = cls.__new__(cls)
self._state = state
self.id = channel_id
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
DEALINGS IN THE SOFTWARE.
"""
from __future__ import annotations
import colorsys
import random
from typing import (
TYPE_CHECKING,
Any,
Callable,
Optional,
Tuple,
Type,
TypeVar,
Union,
)
if TYPE_CHECKING:
from typing_extensions import Self
__all__ = (
'Colour',
'Color',
)
CT = TypeVar('CT', bound='Colour')
class Colour:
"""Represents a Discord role colour. This class is similar
@ -125,23 +128,23 @@ class Colour:
return (self.r, self.g, self.b)
@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."""
return cls((r << 16) + (g << 8) + b)
@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."""
rgb = colorsys.hsv_to_rgb(h, s, v)
return cls.from_rgb(*(int(x * 255) for x in rgb))
@classmethod
def default(cls: Type[CT]) -> CT:
def default(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0``."""
return cls(0)
@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.
.. note::
@ -162,17 +165,17 @@ class Colour:
return cls.from_hsv(rand.random(), 1, 1)
@classmethod
def teal(cls: Type[CT]) -> CT:
def teal(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x1abc9c``."""
return cls(0x1ABC9C)
@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``."""
return cls(0x11806A)
@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``.
.. versionadded:: 2.0
@ -180,67 +183,67 @@ class Colour:
return cls(0x57F287)
@classmethod
def green(cls: Type[CT]) -> CT:
def green(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x2ecc71``."""
return cls(0x2ECC71)
@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``."""
return cls(0x1F8B4C)
@classmethod
def blue(cls: Type[CT]) -> CT:
def blue(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x3498db``."""
return cls(0x3498DB)
@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``."""
return cls(0x206694)
@classmethod
def purple(cls: Type[CT]) -> CT:
def purple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x9b59b6``."""
return cls(0x9B59B6)
@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``."""
return cls(0x71368A)
@classmethod
def magenta(cls: Type[CT]) -> CT:
def magenta(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe91e63``."""
return cls(0xE91E63)
@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``."""
return cls(0xAD1457)
@classmethod
def gold(cls: Type[CT]) -> CT:
def gold(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xf1c40f``."""
return cls(0xF1C40F)
@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``."""
return cls(0xC27C0E)
@classmethod
def orange(cls: Type[CT]) -> CT:
def orange(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe67e22``."""
return cls(0xE67E22)
@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``."""
return cls(0xA84300)
@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``.
.. versionadded:: 2.0
@ -248,60 +251,60 @@ class Colour:
return cls(0xED4245)
@classmethod
def red(cls: Type[CT]) -> CT:
def red(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xe74c3c``."""
return cls(0xE74C3C)
@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``."""
return cls(0x992D22)
@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``."""
return cls(0x95A5A6)
lighter_gray = lighter_grey
lighter_gray: Callable[[Type[Self]], Self] = lighter_grey
@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``."""
return cls(0x607D8B)
dark_gray = dark_grey
dark_gray: Callable[[Type[Self]], Self] = dark_grey
@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``."""
return cls(0x979C9F)
light_gray = light_grey
light_gray: Callable[[Type[Self]], Self] = light_grey
@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``."""
return cls(0x546E7A)
darker_gray = darker_grey
darker_gray: Callable[[Type[Self]], Self] = darker_grey
@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``."""
return cls(0x7289DA)
@classmethod
def blurple(cls: Type[CT]) -> CT:
def blurple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x5865F2``."""
return cls(0x5865F2)
@classmethod
def greyple(cls: Type[CT]) -> CT:
def greyple(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0x99aab5``."""
return cls(0x99AAB5)
@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``.
This will appear transparent on Discord's dark theme.
@ -310,7 +313,7 @@ class Colour:
return cls(0x36393F)
@classmethod
def fuchsia(cls: Type[CT]) -> CT:
def fuchsia(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xEB459E``.
.. versionadded:: 2.0
@ -318,7 +321,7 @@ class Colour:
return cls(0xEB459E)
@classmethod
def yellow(cls: Type[CT]) -> CT:
def yellow(cls) -> Self:
"""A factory method that returns a :class:`Colour` with a value of ``0xFEE75C``.
.. versionadded:: 2.0

10
discord/components.py

@ -24,12 +24,14 @@ DEALINGS IN THE SOFTWARE.
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 .utils import get_slots, MISSING
from .partial_emoji import PartialEmoji, _EmojiTag
if TYPE_CHECKING:
from typing_extensions import Self
from .types.components import (
Component as ComponentPayload,
ButtonComponent as ButtonComponentPayload,
@ -50,8 +52,6 @@ __all__ = (
'TextInput',
)
C = TypeVar('C', bound='Component')
class Component:
"""Represents a Discord Bot UI Kit Component.
@ -82,8 +82,8 @@ class Component:
return f'<{self.__class__.__name__} {attrs}>'
@classmethod
def _raw_construct(cls: Type[C], **kwargs) -> C:
self: C = cls.__new__(cls)
def _raw_construct(cls, **kwargs) -> Self:
self = cls.__new__(cls)
for slot in get_slots(cls):
try:
value = kwargs[slot]

32
discord/embeds.py

@ -25,7 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations
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 .colour import Colour
@ -66,10 +66,10 @@ class EmbedProxy:
return EmptyEmbed
E = TypeVar('E', bound='Embed')
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')
MaybeEmpty = Union[T, _EmptyEmbed]
@ -207,7 +207,7 @@ class Embed:
self.timestamp = timestamp
@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
format that Discord expects it to be in.
@ -223,7 +223,7 @@ class Embed:
The dictionary to convert into an embed.
"""
# 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
@ -263,7 +263,7 @@ class Embed:
return self
def copy(self: E) -> E:
def copy(self) -> Self:
"""Returns a shallow copy of the embed."""
return self.__class__.from_dict(self.to_dict())
@ -347,7 +347,7 @@ class Embed:
# Lying to the type checker for better developer UX.
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.
This function returns the class instance to allow for fluent-style
@ -370,7 +370,7 @@ class Embed:
return self
def remove_footer(self: E) -> E:
def remove_footer(self) -> Self:
"""Clears embed's footer information.
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.
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.
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.
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.
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.
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.
This function returns the class instance to allow for fluent-style
@ -536,7 +536,7 @@ class Embed:
return self
def remove_author(self: E) -> E:
def remove_author(self) -> Self:
"""Clears embed's author information.
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.
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.
This function returns the class instance to allow for fluent-style
@ -591,7 +591,7 @@ class Embed:
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.
This function returns the class instance to allow for fluent-style
@ -652,7 +652,7 @@ class Embed:
except (AttributeError, IndexError):
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.
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
DEALINGS IN THE SOFTWARE.
"""
from __future__ import annotations
import types
from collections import namedtuple
@ -61,6 +62,9 @@ __all__ = (
'EventStatus',
)
if TYPE_CHECKING:
from typing_extensions import Self
def _create_value_cls(name: str, comparable: bool):
# 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_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 = {}
member_mapping = {}
member_names = []

23
discord/ext/commands/bot.py

@ -45,6 +45,8 @@ from .help import HelpCommand, DefaultHelpCommand
from .cog import Cog
if TYPE_CHECKING:
from typing_extensions import Self
import importlib.machinery
from discord.message import Message
@ -934,14 +936,27 @@ class BotBase(GroupMixin):
return ret
@overload
async def get_context(self: BT, message: Message) -> Context[BT]:
async def get_context(
self,
message: Message,
) -> Context[Self]: # type: ignore
...
@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|
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
``cls`` parameter.
"""
if cls is MISSING:
cls = Context # type: ignore
view = StringView(message.content)
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
if TYPE_CHECKING:
from typing_extensions import Self
from .bot import BotBase
from .context import Context
from .core import Command
@ -40,7 +42,6 @@ __all__ = (
'Cog',
)
CogT = TypeVar('CogT', bound='Cog')
FuncT = TypeVar('FuncT', bound=Callable[..., Any])
MISSING: Any = discord.utils.MISSING
@ -111,7 +112,7 @@ class CogMeta(type):
__cog_commands__: List[Command]
__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
attrs['__cog_name__'] = kwargs.pop('name', name)
attrs['__cog_settings__'] = kwargs.pop('command_attrs', {})
@ -190,10 +191,10 @@ class Cog(metaclass=CogMeta):
__cog_name__: ClassVar[str]
__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]]]
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
# since we modify them to inject `self` to them.
# To do this, we need to interfere with the Cog creation process.
@ -220,7 +221,7 @@ class Cog(metaclass=CogMeta):
return self
def get_commands(self) -> List[Command]:
def get_commands(self) -> List[Command[Self, Any, Any]]:
r"""
Returns
--------
@ -248,7 +249,7 @@ class Cog(metaclass=CogMeta):
def description(self, description: str) -> None:
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.
Yields
@ -418,7 +419,7 @@ class Cog(metaclass=CogMeta):
"""
pass
def _inject(self: CogT, bot: BotBase) -> CogT:
def _inject(self, bot: BotBase) -> Self:
cls = self.__class__
# 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 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
import time
import asyncio
@ -35,6 +35,8 @@ from ...abc import PrivateChannel
from .errors import MaxConcurrencyReached
if TYPE_CHECKING:
from typing_extensions import Self
from ...message import Message
__all__ = (
@ -45,9 +47,6 @@ __all__ = (
'MaxConcurrency',
)
C = TypeVar('C', bound='CooldownMapping')
MC = TypeVar('MC', bound='MaxConcurrency')
class BucketType(Enum):
default = 0
@ -221,7 +220,7 @@ class CooldownMapping:
return self._type
@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)
def _bucket_key(self, msg: Message) -> Any:
@ -356,7 +355,7 @@ class MaxConcurrency:
if not isinstance(per, BucketType):
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)
def __repr__(self) -> str:

12
discord/ext/commands/core.py

@ -56,7 +56,7 @@ from .context import Context
if TYPE_CHECKING:
from typing_extensions import Concatenate, ParamSpec, TypeGuard
from typing_extensions import Concatenate, ParamSpec, TypeGuard, Self
from discord.message import Message
@ -292,7 +292,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
"""
__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
# we have a complete original copy of **kwargs even for classes that
# mess with it by popping before delegating to the subclass __init__.
@ -498,7 +498,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
else:
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._after_invoke = self._after_invoke
if self.checks != other.checks:
@ -515,7 +515,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
pass
return other
def copy(self: CommandT) -> CommandT:
def copy(self) -> Self:
"""Creates a copy of this command.
Returns
@ -526,7 +526,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
ret = self.__class__(self.callback, **self.__original_kwargs__)
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:
kw = kwargs.copy()
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)
super().__init__(*args, **attrs)
def copy(self: GroupT) -> GroupT:
def copy(self) -> Self:
"""Creates a copy of this :class:`Group`.
Returns

17
discord/ext/commands/flags.py

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

9
discord/flags.py

@ -24,10 +24,14 @@ DEALINGS IN THE SOFTWARE.
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
if TYPE_CHECKING:
from typing_extensions import Self
__all__ = (
'SystemChannelFlags',
'MessageFlags',
@ -37,7 +41,6 @@ __all__ = (
'ApplicationFlags',
)
FV = TypeVar('FV', bound='flag_value')
BF = TypeVar('BF', bound='BaseFlags')
@ -47,7 +50,7 @@ class flag_value:
self.__doc__ = func.__doc__
@overload
def __get__(self: FV, instance: None, owner: Type[BF]) -> FV:
def __get__(self, instance: None, owner: Type[BF]) -> Self:
...
@overload

5
discord/http.py

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

13
discord/invite.py

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
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 .utils import parse_time, snowflake_time, _get_as_snowflake
from .object import Object
@ -40,6 +40,8 @@ __all__ = (
)
if TYPE_CHECKING:
from typing_extensions import Self
from .types.invite import (
Invite as InvitePayload,
InviteGuild as InviteGuildPayload,
@ -205,9 +207,6 @@ class PartialInviteGuild:
return Asset._from_guild_image(self._state, self.id, self._splash, path='splashes')
I = TypeVar('I', bound='Invite')
class Invite(Hashable):
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
@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]]
try:
guild_data = data['guild']
@ -414,7 +413,7 @@ class Invite(Hashable):
return cls(state=state, data=data, guild=guild, channel=channel)
@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: Optional[Union[Guild, Object]] = state._get_guild(guild_id)
channel_id = int(data['channel_id'])
@ -479,7 +478,7 @@ class Invite(Hashable):
url += '?event=' + str(self.scheduled_event_id)
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.
.. versionadded:: 2.0

15
discord/member.py

@ -29,7 +29,7 @@ import inspect
import itertools
import sys
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
@ -49,6 +49,8 @@ __all__ = (
)
if TYPE_CHECKING:
from typing_extensions import Self
from .asset import Asset
from .channel import DMChannel, VoiceChannel, StageChannel
from .flags import PublicUserFlags
@ -203,9 +205,6 @@ def flatten_user(cls):
return cls
M = TypeVar('M', bound='Member')
@flatten_user
class Member(discord.abc.Messageable, _UserTag):
"""Represents a Discord member to a :class:`Guild`.
@ -329,7 +328,7 @@ class Member(discord.abc.Messageable, _UserTag):
return hash(self._user)
@classmethod
def _from_message(cls: Type[M], *, message: Message, data: MemberPayload) -> M:
def _from_message(cls, *, message: Message, data: MemberPayload) -> Self:
author = message.author
data['user'] = author._to_minimal_user_json() # 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'))
@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
try:
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
@classmethod
def _copy(cls: Type[M], member: M) -> M:
self: M = cls.__new__(cls) # to bypass __init__
def _copy(cls, member: Self) -> Self:
self = cls.__new__(cls) # to bypass __init__
self._roles = utils.SnowflakeList(member._roles, is_sorted=True)
self.joined_at = member.joined_at

10
discord/mentions.py

@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE.
"""
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
__all__ = (
@ -32,6 +32,8 @@ __all__ = (
# fmt: on
if TYPE_CHECKING:
from typing_extensions import Self
from .types.message import AllowedMentions as AllowedMentionsPayload
from .abc import Snowflake
@ -49,8 +51,6 @@ class _FakeBool:
default: Any = _FakeBool()
A = TypeVar('A', bound='AllowedMentions')
class AllowedMentions:
"""A class that represents what mentions are allowed in a message.
@ -98,7 +98,7 @@ class AllowedMentions:
self.replied_user = replied_user
@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``
.. versionadded:: 1.5
@ -106,7 +106,7 @@ class AllowedMentions:
return cls(everyone=True, users=True, roles=True, replied_user=True)
@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``
.. versionadded:: 1.5

9
discord/message.py

@ -41,8 +41,6 @@ from typing import (
ClassVar,
Optional,
overload,
TypeVar,
Type,
)
from . import utils
@ -65,6 +63,8 @@ from .threads import Thread
from .channel import PartialMessageable
if TYPE_CHECKING:
from typing_extensions import Self
from .types.message import (
Message as MessagePayload,
Attachment as AttachmentPayload,
@ -93,7 +93,6 @@ if TYPE_CHECKING:
from .role import Role
from .ui.view import View
MR = TypeVar('MR', bound='MessageReference')
EmojiInputType = Union[Emoji, PartialEmoji, str]
__all__ = (
@ -425,7 +424,7 @@ class MessageReference:
self.fail_if_not_exists: bool = fail_if_not_exists
@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.message_id = utils._get_as_snowflake(data, 'message_id')
self.channel_id = int(data.pop('channel_id'))
@ -436,7 +435,7 @@ class MessageReference:
return self
@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`.
.. versionadded:: 1.6

20
discord/partial_emoji.py

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

31
discord/permissions.py

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

9
discord/player.py

@ -36,7 +36,7 @@ import sys
import re
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 .errors import ClientException
@ -45,11 +45,12 @@ from .oggparse import OggStream
from .utils import MISSING
if TYPE_CHECKING:
from typing_extensions import Self
from .voice_client import VoiceClient
AT = TypeVar('AT', bound='AudioSource')
FT = TypeVar('FT', bound='FFmpegOpusAudio')
_log = logging.getLogger(__name__)
@ -402,12 +403,12 @@ class FFmpegOpusAudio(FFmpegAudio):
@classmethod
async def from_probe(
cls: Type[FT],
cls,
source: str,
*,
method: Optional[Union[str, Callable[[str, str], Tuple[Optional[str], Optional[int]]]]] = None,
**kwargs: Any,
) -> FT:
) -> Self:
"""|coro|
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 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 .permissions import Permissions
@ -37,6 +37,8 @@ __all__ = (
)
if TYPE_CHECKING:
from typing_extensions import Self
import datetime
from .types.role import (
Role as RolePayload,
@ -101,9 +103,6 @@ class RoleTags:
)
R = TypeVar('R', bound='Role')
class Role(Hashable):
"""Represents a Discord role in a :class:`Guild`.
@ -212,7 +211,7 @@ class Role(Hashable):
def __repr__(self) -> str:
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):
return NotImplemented
@ -233,16 +232,16 @@ class Role(Hashable):
return False
def __le__(self: R, other: R) -> bool:
def __le__(self, other: Any) -> bool:
r = Role.__lt__(other, self)
if r is NotImplemented:
return NotImplemented
return not r
def __gt__(self: R, other: R) -> bool:
def __gt__(self, other: Any) -> bool:
return Role.__lt__(other, self)
def __ge__(self: R, other: R) -> bool:
def __ge__(self, other: Any) -> bool:
r = Role.__lt__(self, other)
if r is NotImplemented:
return NotImplemented

8
discord/shard.py

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

1
discord/state.py

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

7
discord/ui/button.py

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

5
discord/ui/select.py

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

7
discord/ui/text_input.py

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

8
discord/user.py

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

2
discord/webhook/sync.py

@ -37,7 +37,7 @@ import time
import re
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
from .. import utils

Loading…
Cancel
Save