diff --git a/changelog/1017.feature.rst b/changelog/1017.feature.rst new file mode 100644 index 0000000000..e0c55f0553 --- /dev/null +++ b/changelog/1017.feature.rst @@ -0,0 +1 @@ +Add typing overloads to :meth:`Client.wait_for` for every :class:`Event` value, allowing for correct typing of the ``check`` parameter and the return value. diff --git a/disnake/_event_data.py b/disnake/_event_data.py new file mode 100644 index 0000000000..685ea725c3 --- /dev/null +++ b/disnake/_event_data.py @@ -0,0 +1,399 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from typing import Dict, List, Optional, Tuple + +from .enums import Event + + +class EventData: + def __init__( + self, + *, + arg_types: List[str], + self_type: Optional[str] = None, + event_only: bool = False, + ) -> None: + self.arg_types: Tuple[str, ...] = tuple(arg_types) + """Type names of event arguments, e.g. `("Guild", "User")`.""" + + self.self_type: Optional[str] = self_type + """The annotation for the `self` parameter, used for bot-only events.""" + + self.event_only: bool = event_only + """Whether the event can only be used through `@event`, and not with listeners.""" + + +EVENT_DATA: Dict[Event, EventData] = { + Event.connect: EventData( + arg_types=[], + ), + Event.disconnect: EventData( + arg_types=[], + ), + # FIXME: figure out how to specify varargs for these two if we ever add overloads for @event + Event.error: EventData( + arg_types=[], + event_only=True, + ), + Event.gateway_error: EventData( + arg_types=[], + event_only=True, + ), + Event.ready: EventData( + arg_types=[], + ), + Event.resumed: EventData( + arg_types=[], + ), + Event.shard_connect: EventData( + arg_types=["int"], + ), + Event.shard_disconnect: EventData( + arg_types=["int"], + ), + Event.shard_ready: EventData( + arg_types=["int"], + ), + Event.shard_resumed: EventData( + arg_types=["int"], + ), + Event.socket_event_type: EventData( + arg_types=["str"], + ), + Event.socket_raw_receive: EventData( + arg_types=["str"], + ), + Event.socket_raw_send: EventData( + arg_types=["Union[str, bytes]"], + ), + Event.guild_channel_create: EventData( + arg_types=["GuildChannel"], + ), + Event.guild_channel_update: EventData( + arg_types=["GuildChannel", "GuildChannel"], + ), + Event.guild_channel_delete: EventData( + arg_types=["GuildChannel"], + ), + Event.guild_channel_pins_update: EventData( + arg_types=["Union[GuildChannel, Thread]", "Optional[datetime]"], + ), + Event.invite_create: EventData( + arg_types=["Invite"], + ), + Event.invite_delete: EventData( + arg_types=["Invite"], + ), + Event.private_channel_update: EventData( + arg_types=["GroupChannel", "GroupChannel"], + ), + Event.private_channel_pins_update: EventData( + arg_types=["PrivateChannel", "Optional[datetime]"], + ), + Event.webhooks_update: EventData( + arg_types=["GuildChannel"], + ), + Event.thread_create: EventData( + arg_types=["Thread"], + ), + Event.thread_update: EventData( + arg_types=["Thread", "Thread"], + ), + Event.thread_delete: EventData( + arg_types=["Thread"], + ), + Event.thread_join: EventData( + arg_types=["Thread"], + ), + Event.thread_remove: EventData( + arg_types=["Thread"], + ), + Event.thread_member_join: EventData( + arg_types=["ThreadMember"], + ), + Event.thread_member_remove: EventData( + arg_types=["ThreadMember"], + ), + Event.raw_thread_member_remove: EventData( + arg_types=["RawThreadMemberRemoveEvent"], + ), + Event.raw_thread_update: EventData( + arg_types=["Thread"], + ), + Event.raw_thread_delete: EventData( + arg_types=["RawThreadDeleteEvent"], + ), + Event.guild_join: EventData( + arg_types=["Guild"], + ), + Event.guild_remove: EventData( + arg_types=["Guild"], + ), + Event.guild_update: EventData( + arg_types=["Guild", "Guild"], + ), + Event.guild_available: EventData( + arg_types=["Guild"], + ), + Event.guild_unavailable: EventData( + arg_types=["Guild"], + ), + Event.guild_role_create: EventData( + arg_types=["Role"], + ), + Event.guild_role_delete: EventData( + arg_types=["Role"], + ), + Event.guild_role_update: EventData( + arg_types=["Role", "Role"], + ), + Event.guild_emojis_update: EventData( + arg_types=["Guild", "Sequence[Emoji]", "Sequence[Emoji]"], + ), + Event.guild_stickers_update: EventData( + arg_types=["Guild", "Sequence[GuildSticker]", "Sequence[GuildSticker]"], + ), + Event.guild_integrations_update: EventData( + arg_types=["Guild"], + ), + Event.guild_scheduled_event_create: EventData( + arg_types=["GuildScheduledEvent"], + ), + Event.guild_scheduled_event_update: EventData( + arg_types=["GuildScheduledEvent", "GuildScheduledEvent"], + ), + Event.guild_scheduled_event_delete: EventData( + arg_types=["GuildScheduledEvent"], + ), + Event.guild_scheduled_event_subscribe: EventData( + arg_types=["GuildScheduledEvent", "Union[Member, User]"], + ), + Event.guild_scheduled_event_unsubscribe: EventData( + arg_types=["GuildScheduledEvent", "Union[Member, User]"], + ), + Event.raw_guild_scheduled_event_subscribe: EventData( + arg_types=["RawGuildScheduledEventUserActionEvent"], + ), + Event.raw_guild_scheduled_event_unsubscribe: EventData( + arg_types=["RawGuildScheduledEventUserActionEvent"], + ), + Event.application_command_permissions_update: EventData( + arg_types=["GuildApplicationCommandPermissions"], + ), + Event.automod_action_execution: EventData( + arg_types=["AutoModActionExecution"], + ), + Event.automod_rule_create: EventData( + arg_types=["AutoModRule"], + ), + Event.automod_rule_update: EventData( + arg_types=["AutoModRule"], + ), + Event.automod_rule_delete: EventData( + arg_types=["AutoModRule"], + ), + Event.audit_log_entry_create: EventData( + arg_types=["AuditLogEntry"], + ), + Event.integration_create: EventData( + arg_types=["Integration"], + ), + Event.integration_update: EventData( + arg_types=["Integration"], + ), + Event.raw_integration_delete: EventData( + arg_types=["RawIntegrationDeleteEvent"], + ), + Event.member_join: EventData( + arg_types=["Member"], + ), + Event.member_remove: EventData( + arg_types=["Member"], + ), + Event.member_update: EventData( + arg_types=["Member", "Member"], + ), + Event.raw_member_remove: EventData( + arg_types=["RawGuildMemberRemoveEvent"], + ), + Event.raw_member_update: EventData( + arg_types=["Member"], + ), + Event.member_ban: EventData( + arg_types=["Guild", "Union[User, Member]"], + ), + Event.member_unban: EventData( + arg_types=["Guild", "User"], + ), + Event.presence_update: EventData( + arg_types=["Member", "Member"], + ), + Event.user_update: EventData( + arg_types=["User", "User"], + ), + Event.voice_state_update: EventData( + arg_types=["Member", "VoiceState", "VoiceState"], + ), + Event.voice_channel_effect: EventData( + arg_types=["GuildChannel", "Member", "VoiceChannelEffect"], + ), + Event.raw_voice_channel_effect: EventData( + arg_types=["RawVoiceChannelEffectEvent"], + ), + Event.stage_instance_create: EventData( + arg_types=["StageInstance"], + ), + Event.stage_instance_delete: EventData( + arg_types=["StageInstance", "StageInstance"], + ), + Event.stage_instance_update: EventData( + arg_types=["StageInstance"], + ), + Event.application_command: EventData( + arg_types=["ApplicationCommandInteraction[Self]"], + ), + Event.application_command_autocomplete: EventData( + arg_types=["ApplicationCommandInteraction[Self]"], + ), + Event.button_click: EventData( + arg_types=["MessageInteraction[Self]"], + ), + Event.dropdown: EventData( + arg_types=["MessageInteraction[Self]"], + ), + Event.interaction: EventData( + arg_types=["Interaction[Self]"], + ), + Event.message_interaction: EventData( + arg_types=["MessageInteraction[Self]"], + ), + Event.modal_submit: EventData( + arg_types=["ModalInteraction[Self]"], + ), + Event.message: EventData( + arg_types=["Message"], + ), + Event.message_edit: EventData( + arg_types=["Message", "Message"], + ), + Event.message_delete: EventData( + arg_types=["Message"], + ), + Event.bulk_message_delete: EventData( + arg_types=["List[Message]"], + ), + Event.poll_vote_add: EventData( + arg_types=["Member", "PollAnswer"], + ), + Event.poll_vote_remove: EventData( + arg_types=["Member", "PollAnswer"], + ), + Event.raw_message_edit: EventData( + arg_types=["RawMessageUpdateEvent"], + ), + Event.raw_message_delete: EventData( + arg_types=["RawMessageDeleteEvent"], + ), + Event.raw_bulk_message_delete: EventData( + arg_types=["RawBulkMessageDeleteEvent"], + ), + Event.raw_poll_vote_add: EventData( + arg_types=["RawPollVoteActionEvent"], + ), + Event.raw_poll_vote_remove: EventData( + arg_types=["RawPollVoteActionEvent"], + ), + Event.reaction_add: EventData( + arg_types=["Reaction", "Union[Member, User]"], + ), + Event.reaction_remove: EventData( + arg_types=["Reaction", "Union[Member, User]"], + ), + Event.reaction_clear: EventData( + arg_types=["Message", "List[Reaction]"], + ), + Event.reaction_clear_emoji: EventData( + arg_types=["Reaction"], + ), + Event.raw_presence_update: EventData( + arg_types=["RawPresenceUpdateEvent"], + ), + Event.raw_reaction_add: EventData( + arg_types=["RawReactionActionEvent"], + ), + Event.raw_reaction_remove: EventData( + arg_types=["RawReactionActionEvent"], + ), + Event.raw_reaction_clear: EventData( + arg_types=["RawReactionClearEvent"], + ), + Event.raw_reaction_clear_emoji: EventData( + arg_types=["RawReactionClearEmojiEvent"], + ), + Event.typing: EventData( + arg_types=["Union[Messageable, ForumChannel]", "Union[User, Member]", "datetime"], + ), + Event.raw_typing: EventData( + arg_types=["RawTypingEvent"], + ), + Event.entitlement_create: EventData( + arg_types=["Entitlement"], + ), + Event.entitlement_update: EventData( + arg_types=["Entitlement"], + ), + Event.entitlement_delete: EventData( + arg_types=["Entitlement"], + ), + # bot-only: + Event.command: EventData( + arg_types=["commands.Context[AnyPrefixBotT]"], + self_type="AnyPrefixBotT", + ), + Event.command_completion: EventData( + arg_types=["commands.Context[AnyPrefixBotT]"], + self_type="AnyPrefixBotT", + ), + Event.command_error: EventData( + arg_types=["commands.Context[AnyPrefixBotT]", "commands.CommandError"], + self_type="AnyPrefixBotT", + ), + Event.slash_command: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.slash_command_completion: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.slash_command_error: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]", "commands.CommandError"], + self_type="AnyBotT", + ), + Event.user_command: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.user_command_completion: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.user_command_error: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]", "commands.CommandError"], + self_type="AnyBotT", + ), + Event.message_command: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.message_command_completion: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]"], + self_type="AnyBotT", + ), + Event.message_command_error: EventData( + arg_types=["ApplicationCommandInteraction[AnyBotT]", "commands.CommandError"], + self_type="AnyBotT", + ), +} diff --git a/disnake/client.py b/disnake/client.py index 990e19c201..4d53ebcd6f 100644 --- a/disnake/client.py +++ b/disnake/client.py @@ -72,30 +72,73 @@ from .state import ConnectionState from .sticker import GuildSticker, StandardSticker, StickerPack, _sticker_factory from .template import Template -from .threads import Thread +from .threads import Thread, ThreadMember from .ui.view import View from .user import ClientUser, User -from .utils import MISSING, deprecated +from .utils import MISSING, _generated, _overload_with_events, deprecated from .voice_client import VoiceClient from .voice_region import VoiceRegion from .webhook import Webhook from .widget import Widget if TYPE_CHECKING: - from typing_extensions import NotRequired + from typing_extensions import NotRequired, Self - from .abc import GuildChannel, PrivateChannel, Snowflake, SnowflakeTime + from disnake.ext import commands + + from .abc import GuildChannel, Messageable, PrivateChannel, Snowflake, SnowflakeTime from .app_commands import APIApplicationCommand, MessageCommand, SlashCommand, UserCommand from .asset import AssetBytes - from .channel import DMChannel - from .member import Member + from .audit_logs import AuditLogEntry + from .automod import AutoModActionExecution, AutoModRule + from .channel import DMChannel, ForumChannel, GroupChannel, VoiceChannelEffect + from .guild_scheduled_event import GuildScheduledEvent + from .integrations import Integration + from .interactions import ( + ApplicationCommandInteraction, + Interaction, + MessageInteraction, + ModalInteraction, + ) + from .member import Member, VoiceState from .message import Message + from .poll import PollAnswer + from .raw_models import ( + RawBulkMessageDeleteEvent, + RawGuildMemberRemoveEvent, + RawGuildScheduledEventUserActionEvent, + RawIntegrationDeleteEvent, + RawMessageDeleteEvent, + RawMessageUpdateEvent, + RawPollVoteActionEvent, + RawPresenceUpdateEvent, + RawReactionActionEvent, + RawReactionClearEmojiEvent, + RawReactionClearEvent, + RawThreadDeleteEvent, + RawThreadMemberRemoveEvent, + RawTypingEvent, + RawVoiceChannelEffectEvent, + ) + from .reaction import Reaction + from .role import Role from .types.application_role_connection import ( ApplicationRoleConnectionMetadata as ApplicationRoleConnectionMetadataPayload, ) from .types.gateway import SessionStartLimit as SessionStartLimitPayload from .voice_client import VoiceProtocol + AnyPrefixBot = Union[commands.Bot, commands.AutoShardedBot] + AnyBot = Union[ + AnyPrefixBot, + commands.InteractionBot, + commands.AutoShardedInteractionBot, + ] + # we can't use `typing.Self` when the `self: AnyBot` parameter is annotated, + # so go back to the old way of using a TypeVar for those overloads + AnyPrefixBotT = TypeVar("AnyPrefixBotT", bound=AnyPrefixBot) + AnyBotT = TypeVar("AnyBotT", bound=AnyBot) + __all__ = ( "Client", @@ -1703,13 +1746,1324 @@ async def wait_until_first_connect(self) -> None: """ await self._first_connect.wait() + @overload + @_generated + def wait_for( + self, + event: Literal[Event.connect, "connect"], + *, + check: Optional[Callable[[], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, None]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.disconnect, "disconnect"], + *, + check: Optional[Callable[[], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, None]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.ready, "ready"], + *, + check: Optional[Callable[[], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, None]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.resumed, "resumed"], + *, + check: Optional[Callable[[], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, None]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.shard_connect, "shard_connect"], + *, + check: Optional[Callable[[int], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, int]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.shard_disconnect, "shard_disconnect"], + *, + check: Optional[Callable[[int], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, int]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.shard_ready, "shard_ready"], + *, + check: Optional[Callable[[int], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, int]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.shard_resumed, "shard_resumed"], + *, + check: Optional[Callable[[int], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, int]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.socket_event_type, "socket_event_type"], + *, + check: Optional[Callable[[str], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, str]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.socket_raw_receive, "socket_raw_receive"], + *, + check: Optional[Callable[[str], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, str]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.socket_raw_send, "socket_raw_send"], + *, + check: Optional[Callable[[Union[str, bytes]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Union[str, bytes]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_channel_create, "guild_channel_create"], + *, + check: Optional[Callable[[GuildChannel], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildChannel]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_channel_update, "guild_channel_update"], + *, + check: Optional[Callable[[GuildChannel, GuildChannel], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GuildChannel, GuildChannel]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_channel_delete, "guild_channel_delete"], + *, + check: Optional[Callable[[GuildChannel], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildChannel]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_channel_pins_update, "guild_channel_pins_update"], + *, + check: Optional[Callable[[Union[GuildChannel, Thread], Optional[datetime]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Union[GuildChannel, Thread], Optional[datetime]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.invite_create, "invite_create"], + *, + check: Optional[Callable[[Invite], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Invite]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.invite_delete, "invite_delete"], + *, + check: Optional[Callable[[Invite], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Invite]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.private_channel_update, "private_channel_update"], + *, + check: Optional[Callable[[GroupChannel, GroupChannel], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GroupChannel, GroupChannel]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.private_channel_pins_update, "private_channel_pins_update"], + *, + check: Optional[Callable[[PrivateChannel, Optional[datetime]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[PrivateChannel, Optional[datetime]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.webhooks_update, "webhooks_update"], + *, + check: Optional[Callable[[GuildChannel], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildChannel]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_create, "thread_create"], + *, + check: Optional[Callable[[Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Thread]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_update, "thread_update"], + *, + check: Optional[Callable[[Thread, Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Thread, Thread]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_delete, "thread_delete"], + *, + check: Optional[Callable[[Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Thread]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_join, "thread_join"], + *, + check: Optional[Callable[[Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Thread]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_remove, "thread_remove"], + *, + check: Optional[Callable[[Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Thread]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_member_join, "thread_member_join"], + *, + check: Optional[Callable[[ThreadMember], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ThreadMember]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.thread_member_remove, "thread_member_remove"], + *, + check: Optional[Callable[[ThreadMember], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ThreadMember]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_thread_member_remove, "raw_thread_member_remove"], + *, + check: Optional[Callable[[RawThreadMemberRemoveEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawThreadMemberRemoveEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_thread_update, "raw_thread_update"], + *, + check: Optional[Callable[[Thread], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Thread]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_thread_delete, "raw_thread_delete"], + *, + check: Optional[Callable[[RawThreadDeleteEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawThreadDeleteEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_join, "guild_join"], + *, + check: Optional[Callable[[Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Guild]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_remove, "guild_remove"], + *, + check: Optional[Callable[[Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Guild]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_update, "guild_update"], + *, + check: Optional[Callable[[Guild, Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Guild, Guild]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_available, "guild_available"], + *, + check: Optional[Callable[[Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Guild]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_unavailable, "guild_unavailable"], + *, + check: Optional[Callable[[Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Guild]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_role_create, "guild_role_create"], + *, + check: Optional[Callable[[Role], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Role]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_role_delete, "guild_role_delete"], + *, + check: Optional[Callable[[Role], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Role]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_role_update, "guild_role_update"], + *, + check: Optional[Callable[[Role, Role], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Role, Role]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_emojis_update, "guild_emojis_update"], + *, + check: Optional[Callable[[Guild, Sequence[Emoji], Sequence[Emoji]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Guild, Sequence[Emoji], Sequence[Emoji]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_stickers_update, "guild_stickers_update"], + *, + check: Optional[ + Callable[[Guild, Sequence[GuildSticker], Sequence[GuildSticker]], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Guild, Sequence[GuildSticker], Sequence[GuildSticker]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_integrations_update, "guild_integrations_update"], + *, + check: Optional[Callable[[Guild], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Guild]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_scheduled_event_create, "guild_scheduled_event_create"], + *, + check: Optional[Callable[[GuildScheduledEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildScheduledEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_scheduled_event_update, "guild_scheduled_event_update"], + *, + check: Optional[Callable[[GuildScheduledEvent, GuildScheduledEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GuildScheduledEvent, GuildScheduledEvent]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_scheduled_event_delete, "guild_scheduled_event_delete"], + *, + check: Optional[Callable[[GuildScheduledEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildScheduledEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.guild_scheduled_event_subscribe, "guild_scheduled_event_subscribe"], + *, + check: Optional[Callable[[GuildScheduledEvent, Union[Member, User]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GuildScheduledEvent, Union[Member, User]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[ + Event.guild_scheduled_event_unsubscribe, "guild_scheduled_event_unsubscribe" + ], + *, + check: Optional[Callable[[GuildScheduledEvent, Union[Member, User]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GuildScheduledEvent, Union[Member, User]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[ + Event.raw_guild_scheduled_event_subscribe, "raw_guild_scheduled_event_subscribe" + ], + *, + check: Optional[Callable[[RawGuildScheduledEventUserActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawGuildScheduledEventUserActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[ + Event.raw_guild_scheduled_event_unsubscribe, "raw_guild_scheduled_event_unsubscribe" + ], + *, + check: Optional[Callable[[RawGuildScheduledEventUserActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawGuildScheduledEventUserActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[ + Event.application_command_permissions_update, "application_command_permissions_update" + ], + *, + check: Optional[Callable[[GuildApplicationCommandPermissions], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, GuildApplicationCommandPermissions]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.automod_action_execution, "automod_action_execution"], + *, + check: Optional[Callable[[AutoModActionExecution], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, AutoModActionExecution]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.automod_rule_create, "automod_rule_create"], + *, + check: Optional[Callable[[AutoModRule], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, AutoModRule]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.automod_rule_update, "automod_rule_update"], + *, + check: Optional[Callable[[AutoModRule], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, AutoModRule]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.automod_rule_delete, "automod_rule_delete"], + *, + check: Optional[Callable[[AutoModRule], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, AutoModRule]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.audit_log_entry_create, "audit_log_entry_create"], + *, + check: Optional[Callable[[AuditLogEntry], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, AuditLogEntry]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.integration_create, "integration_create"], + *, + check: Optional[Callable[[Integration], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Integration]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.integration_update, "integration_update"], + *, + check: Optional[Callable[[Integration], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Integration]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_integration_delete, "raw_integration_delete"], + *, + check: Optional[Callable[[RawIntegrationDeleteEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawIntegrationDeleteEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.member_join, "member_join"], + *, + check: Optional[Callable[[Member], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Member]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.member_remove, "member_remove"], + *, + check: Optional[Callable[[Member], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Member]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.member_update, "member_update"], + *, + check: Optional[Callable[[Member, Member], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Member, Member]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_member_remove, "raw_member_remove"], + *, + check: Optional[Callable[[RawGuildMemberRemoveEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawGuildMemberRemoveEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_member_update, "raw_member_update"], + *, + check: Optional[Callable[[Member], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Member]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.member_ban, "member_ban"], + *, + check: Optional[Callable[[Guild, Union[User, Member]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Guild, Union[User, Member]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.member_unban, "member_unban"], + *, + check: Optional[Callable[[Guild, User], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Guild, User]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.presence_update, "presence_update"], + *, + check: Optional[Callable[[Member, Member], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Member, Member]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.user_update, "user_update"], + *, + check: Optional[Callable[[User, User], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[User, User]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.voice_state_update, "voice_state_update"], + *, + check: Optional[Callable[[Member, VoiceState, VoiceState], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Member, VoiceState, VoiceState]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.voice_channel_effect, "voice_channel_effect"], + *, + check: Optional[Callable[[GuildChannel, Member, VoiceChannelEffect], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[GuildChannel, Member, VoiceChannelEffect]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_voice_channel_effect, "raw_voice_channel_effect"], + *, + check: Optional[Callable[[RawVoiceChannelEffectEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawVoiceChannelEffectEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.stage_instance_create, "stage_instance_create"], + *, + check: Optional[Callable[[StageInstance], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, StageInstance]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.stage_instance_delete, "stage_instance_delete"], + *, + check: Optional[Callable[[StageInstance, StageInstance], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[StageInstance, StageInstance]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.stage_instance_update, "stage_instance_update"], + *, + check: Optional[Callable[[StageInstance], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, StageInstance]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.application_command, "application_command"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.application_command_autocomplete, "application_command_autocomplete"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.button_click, "button_click"], + *, + check: Optional[Callable[[MessageInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, MessageInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.dropdown, "dropdown"], + *, + check: Optional[Callable[[MessageInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, MessageInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.interaction, "interaction"], + *, + check: Optional[Callable[[Interaction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Interaction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.message_interaction, "message_interaction"], + *, + check: Optional[Callable[[MessageInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, MessageInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.modal_submit, "modal_submit"], + *, + check: Optional[Callable[[ModalInteraction[Self]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ModalInteraction[Self]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.message, "message"], + *, + check: Optional[Callable[[Message], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Message]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.message_edit, "message_edit"], + *, + check: Optional[Callable[[Message, Message], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Message, Message]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.message_delete, "message_delete"], + *, + check: Optional[Callable[[Message], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Message]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.bulk_message_delete, "bulk_message_delete"], + *, + check: Optional[Callable[[List[Message]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, List[Message]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.poll_vote_add, "poll_vote_add"], + *, + check: Optional[Callable[[Member, PollAnswer], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Member, PollAnswer]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.poll_vote_remove, "poll_vote_remove"], + *, + check: Optional[Callable[[Member, PollAnswer], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Member, PollAnswer]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_message_edit, "raw_message_edit"], + *, + check: Optional[Callable[[RawMessageUpdateEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawMessageUpdateEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_message_delete, "raw_message_delete"], + *, + check: Optional[Callable[[RawMessageDeleteEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawMessageDeleteEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_bulk_message_delete, "raw_bulk_message_delete"], + *, + check: Optional[Callable[[RawBulkMessageDeleteEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawBulkMessageDeleteEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_poll_vote_add, "raw_poll_vote_add"], + *, + check: Optional[Callable[[RawPollVoteActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawPollVoteActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_poll_vote_remove, "raw_poll_vote_remove"], + *, + check: Optional[Callable[[RawPollVoteActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawPollVoteActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.reaction_add, "reaction_add"], + *, + check: Optional[Callable[[Reaction, Union[Member, User]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Reaction, Union[Member, User]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.reaction_remove, "reaction_remove"], + *, + check: Optional[Callable[[Reaction, Union[Member, User]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Reaction, Union[Member, User]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.reaction_clear, "reaction_clear"], + *, + check: Optional[Callable[[Message, List[Reaction]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[Message, List[Reaction]]]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.reaction_clear_emoji, "reaction_clear_emoji"], + *, + check: Optional[Callable[[Reaction], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Reaction]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_presence_update, "raw_presence_update"], + *, + check: Optional[Callable[[RawPresenceUpdateEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawPresenceUpdateEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_reaction_add, "raw_reaction_add"], + *, + check: Optional[Callable[[RawReactionActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawReactionActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_reaction_remove, "raw_reaction_remove"], + *, + check: Optional[Callable[[RawReactionActionEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawReactionActionEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_reaction_clear, "raw_reaction_clear"], + *, + check: Optional[Callable[[RawReactionClearEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawReactionClearEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_reaction_clear_emoji, "raw_reaction_clear_emoji"], + *, + check: Optional[Callable[[RawReactionClearEmojiEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawReactionClearEmojiEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.typing, "typing"], + *, + check: Optional[ + Callable[[Union[Messageable, ForumChannel], Union[User, Member], datetime], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[ + Any, Any, Tuple[Union[Messageable, ForumChannel], Union[User, Member], datetime] + ]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.raw_typing, "raw_typing"], + *, + check: Optional[Callable[[RawTypingEvent], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, RawTypingEvent]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.entitlement_create, "entitlement_create"], + *, + check: Optional[Callable[[Entitlement], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Entitlement]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.entitlement_update, "entitlement_update"], + *, + check: Optional[Callable[[Entitlement], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Entitlement]: + ... + + @overload + @_generated + def wait_for( + self, + event: Literal[Event.entitlement_delete, "entitlement_delete"], + *, + check: Optional[Callable[[Entitlement], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Entitlement]: + ... + + @overload + @_generated + def wait_for( + self: AnyPrefixBotT, + event: Literal[Event.command, "command"], + *, + check: Optional[Callable[[commands.Context[AnyPrefixBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, commands.Context[AnyPrefixBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyPrefixBotT, + event: Literal[Event.command_completion, "command_completion"], + *, + check: Optional[Callable[[commands.Context[AnyPrefixBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, commands.Context[AnyPrefixBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyPrefixBotT, + event: Literal[Event.command_error, "command_error"], + *, + check: Optional[ + Callable[[commands.Context[AnyPrefixBotT], commands.CommandError], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[commands.Context[AnyPrefixBotT], commands.CommandError]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.slash_command, "slash_command"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.slash_command_completion, "slash_command_completion"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.slash_command_error, "slash_command_error"], + *, + check: Optional[ + Callable[[ApplicationCommandInteraction[AnyBotT], commands.CommandError], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[ApplicationCommandInteraction[AnyBotT], commands.CommandError]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.user_command, "user_command"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.user_command_completion, "user_command_completion"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.user_command_error, "user_command_error"], + *, + check: Optional[ + Callable[[ApplicationCommandInteraction[AnyBotT], commands.CommandError], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[ApplicationCommandInteraction[AnyBotT], commands.CommandError]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.message_command, "message_command"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.message_command_completion, "message_command_completion"], + *, + check: Optional[Callable[[ApplicationCommandInteraction[AnyBotT]], bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, ApplicationCommandInteraction[AnyBotT]]: + ... + + @overload + @_generated + def wait_for( + self: AnyBotT, + event: Literal[Event.message_command_error, "message_command_error"], + *, + check: Optional[ + Callable[[ApplicationCommandInteraction[AnyBotT], commands.CommandError], bool] + ] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Tuple[ApplicationCommandInteraction[AnyBotT], commands.CommandError]]: + ... + + # fallback for custom events + + @overload + @_overload_with_events + def wait_for( + self, + event: str, + *, + check: Optional[Callable[..., bool]] = None, + timeout: Optional[float] = None, + ) -> Coroutine[Any, Any, Any]: + ... + def wait_for( self, event: Union[str, Event], *, check: Optional[Callable[..., bool]] = None, timeout: Optional[float] = None, - ) -> Any: + ) -> Coroutine[Any, Any, Any]: """|coro| Waits for a WebSocket event to be dispatched. diff --git a/disnake/interactions/base.py b/disnake/interactions/base.py index 09795285d4..49932dc423 100644 --- a/disnake/interactions/base.py +++ b/disnake/interactions/base.py @@ -69,7 +69,6 @@ from ..app_commands import Choices from ..client import Client from ..embeds import Embed - from ..ext.commands import AutoShardedBot, Bot from ..file import File from ..mentions import AllowedMentions from ..poll import Poll @@ -87,8 +86,6 @@ from .message import MessageInteraction from .modal import ModalInteraction - AnyBot = Union[Bot, AutoShardedBot] - MISSING: Any = utils.MISSING diff --git a/disnake/utils.py b/disnake/utils.py index 07754afafc..6ce759a946 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -1503,13 +1503,15 @@ def assert_never(arg: Never, /) -> None: pass -# n.b. This must be imported and used as @ _overload_with_permissions (without the space) -# this is used by the libcst parser and has no runtime purpose -# it is merely a marker not unlike pytest.mark -def _overload_with_permissions(func: T) -> T: +# n.b. These must be imported and used as @. +# This is used by the libcst parser and has no runtime purpose; +# it is merely a marker not unlike pytest.mark. +def _noop_decorator(func: T) -> T: return func # this is used as a marker for functions or classes that were created by codemodding -def _generated(func: T) -> T: - return func +_generated = _noop_decorator + +_overload_with_permissions = _noop_decorator +_overload_with_events = _noop_decorator diff --git a/scripts/codemods/combined.py b/scripts/codemods/combined.py index a3cd957d01..e6b5c90ffa 100644 --- a/scripts/codemods/combined.py +++ b/scripts/codemods/combined.py @@ -5,11 +5,12 @@ import libcst as cst from libcst import codemod -from . import overloads_no_missing, typed_flags, typed_permissions +from . import overloads_no_missing, typed_events, typed_flags, typed_permissions from .base import NoMetadataWrapperMixin CODEMODS = [ overloads_no_missing.EllipsisOverloads, + typed_events.EventTypings, typed_flags.FlagTypings, typed_permissions.PermissionTypings, ] diff --git a/scripts/codemods/typed_events.py b/scripts/codemods/typed_events.py new file mode 100644 index 0000000000..30aae626c2 --- /dev/null +++ b/scripts/codemods/typed_events.py @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +import types +from typing import List, Optional, cast + +import libcst as cst +import libcst.matchers as m + +from disnake import Event +from disnake._event_data import EVENT_DATA, EventData + +from .base import BaseCodemodCommand + + +def get_param(func: cst.FunctionDef, name: str) -> cst.Param: + results = m.findall(func.params, m.Param(m.Name(name))) + assert len(results) == 1 + return cast(cst.Param, results[0]) + + +class EventTypings(BaseCodemodCommand): + DESCRIPTION: str = "Adds overloads for library events." + CHECK_MARKER: str = "@_overload_with_events" + + flag_classes: List[str] + imported_module: types.ModuleType + + def visit_FunctionDef(self, node: cst.FunctionDef) -> Optional[bool]: + # don't recurse into the body of a function + return False + + def leave_FunctionDef(self, _: cst.FunctionDef, node: cst.FunctionDef): + decorators = [ + deco.decorator.value + for deco in node.decorators + if not isinstance(deco.decorator, cst.Call) + ] + if "_generated" in decorators: + # remove generated methods + return cst.RemovalSentinel.REMOVE + if "_overload_with_events" not in decorators: + # ignore + return node + + if node.name.value == "wait_for": + generator = self.generate_wait_for_overload + else: + raise RuntimeError( + f"unknown method '{node.name.value}' with @_overload_with_events decorator" + ) + + # if we're here, we found a @_overload_with_events decorator + new_overloads: List[cst.FunctionDef] = [] + for event in Event: + if not (event_data := EVENT_DATA.get(event)): + raise RuntimeError(f"{event} is missing an EVENT_DATA definition") + if event_data.event_only: + continue + new_overloads.append(generator(node, event, event_data)) + + return cst.FlattenSentinel([*new_overloads, node]) + + def create_empty_overload(self, func: cst.FunctionDef) -> cst.FunctionDef: + return func.with_changes( + body=cst.IndentedBlock([cst.SimpleStatementLine([cst.Expr(cst.Ellipsis())])]), + decorators=[ + cst.Decorator(cst.Name("overload")), + cst.Decorator(cst.Name("_generated")), + ], + leading_lines=(), + ) + + def create_literal(self, event: Event) -> cst.BaseExpression: + return cst.parse_expression( + f'Literal[Event.{event.name}, "{event.value}"]', + config=self.module.config_for_parsing, + ) + + def create_args_list(self, event_data: EventData) -> cst.BaseExpression: + return cst.parse_expression( + f'[{",".join(event_data.arg_types)}]', + config=self.module.config_for_parsing, + ) + + def generate_wait_for_overload( + self, func: cst.FunctionDef, event: Event, event_data: EventData + ) -> cst.FunctionDef: + args = event_data.arg_types + + new_overload = self.create_empty_overload(func) + + # set `event` annotation + new_overload = new_overload.with_deep_changes( + get_param(new_overload, "event"), + annotation=cst.Annotation(self.create_literal(event)), + ) + + # set `check` annotation + callable_annotation = m.findall( + get_param(new_overload, "check"), m.Subscript(m.Name("Callable")) + )[0] + callable_params = m.findall(callable_annotation, m.Ellipsis())[0] + new_overload = cast( + cst.FunctionDef, + new_overload.deep_replace(callable_params, self.create_args_list(event_data)), + ) + + # set return annotation + if len(args) == 0: + new_annotation_str = "None" + elif len(args) == 1: + new_annotation_str = args[0] + else: + new_annotation_str = f'Tuple[{",".join(args)}]' + new_annotation = cst.parse_expression( + f"Coroutine[Any, Any, {new_annotation_str}]", + config=self.module.config_for_parsing, + ) + new_overload = new_overload.with_changes(returns=cst.Annotation(new_annotation)) + + # set `self` annotation as a workaround for overloads in subclasses + if event_data.self_type: + new_overload = new_overload.with_deep_changes( + get_param(new_overload, "self"), + annotation=cst.Annotation(cst.Name(event_data.self_type)), + ) + + return new_overload diff --git a/test_bot/cogs/modals.py b/test_bot/cogs/modals.py index c5d514a25c..13c84bddf2 100644 --- a/test_bot/cogs/modals.py +++ b/test_bot/cogs/modals.py @@ -65,7 +65,7 @@ async def create_tag_low(self, inter: disnake.AppCmdInter[commands.Bot]) -> None modal_inter: disnake.ModalInteraction = await self.bot.wait_for( "modal_submit", - check=lambda i: i.custom_id == "create_tag2" and i.author.id == inter.author.id, # type: ignore # unknown parameter type + check=lambda i: i.custom_id == "create_tag2" and i.author.id == inter.author.id, ) embed = disnake.Embed(title="Tag Creation") diff --git a/tests/test_events.py b/tests/test_events.py index 15cc467151..fa4952195e 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -1,7 +1,9 @@ # SPDX-License-Identifier: MIT -from typing import Any + +from typing import Any, Coroutine import pytest +from typing_extensions import assert_type import disnake from disnake import Event @@ -50,6 +52,30 @@ def test_wait_for(client_or_bot: disnake.Client, event) -> None: coro.close() # close coroutine to avoid warning +def _test_typing_wait_for(client: disnake.Client, bot: commands.Bot) -> None: + expected_type = Coroutine[Any, Any, disnake.Guild] + + # valid enum event + _ = assert_type(client.wait_for(Event.guild_join), expected_type) + _ = assert_type(client.wait_for(Event.guild_join, check=lambda g: True), expected_type) + + # valid str event + _ = assert_type(client.wait_for("guild_join"), expected_type) + _ = assert_type(client.wait_for("guild_join", check=lambda g: True), expected_type) + + # invalid check type + _ = client.wait_for(Event.guild_join, check=lambda: True) # type: ignore + # n.b. this one isn't ideal, but there's no way to prevent type-checkers from using the fallback in this case + _ = assert_type(client.wait_for("guild_join", check=lambda: True), Coroutine[Any, Any, Any]) + + # bot-specific events + _ = client.wait_for(Event.slash_command_error) # type: ignore # this should error + _ = assert_type( + bot.wait_for(Event.slash_command), + Coroutine[Any, Any, disnake.ApplicationCommandInteraction[commands.Bot]], + ) + + # Client.add_listener / Client.remove_listener