diff --git a/cogs/add_users_to_threads_and_channels.py b/cogs/add_users_to_threads_and_channels.py index 792685d57..5c57dba9e 100644 --- a/cogs/add_users_to_threads_and_channels.py +++ b/cogs/add_users_to_threads_and_channels.py @@ -167,7 +167,7 @@ async def add_users_or_roles_with_ping( @capture_guild_does_not_exist_error async def on_thread_create(self, thread: discord.Thread) -> None: """Add users to a thread when it is created.""" - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent committee_role: discord.Role = await self.bot.committee_role committee_elect_role: discord.Role = await self.bot.committee_elect_role @@ -183,10 +183,10 @@ async def on_thread_create(self, thread: discord.Thread) -> None: users_or_roles=(committee_role, committee_elect_role), channel_or_thread=thread ) - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="add-users-to-channel", description="Adds selected users to a channel or thread." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to add to the channel.", input_type=str, @@ -194,7 +194,7 @@ async def on_thread_create(self, thread: discord.Thread) -> None: required=True, parameter_name="user_id_str", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="silent", description="Whether the users being added should be pinged or not.", input_type=bool, @@ -203,7 +203,7 @@ async def on_thread_create(self, thread: discord.Thread) -> None: ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def add_user_to_channel( # type: ignore[misc] + async def add_user_to_channel( self, ctx: "TeXBotApplicationContext", user_id_str: str, @@ -237,11 +237,11 @@ async def add_user_to_channel( # type: ignore[misc] ephemeral=True, ) - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="add-role-to-channel", description="Adds the selected role and it's users to a channel or thread.", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="role", description="The role to add to the channel.", input_type=str, @@ -249,7 +249,7 @@ async def add_user_to_channel( # type: ignore[misc] required=True, parameter_name="role_id_str", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="silent", description="Whether the users being added should be pinged or not.", input_type=bool, @@ -258,7 +258,7 @@ async def add_user_to_channel( # type: ignore[misc] ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def add_role_to_channel( # type: ignore[misc] + async def add_role_to_channel( self, ctx: "TeXBotApplicationContext", role_id_str: str, diff --git a/cogs/annual_handover_and_reset.py b/cogs/annual_handover_and_reset.py index c0b09d39f..355babbe9 100644 --- a/cogs/annual_handover_and_reset.py +++ b/cogs/annual_handover_and_reset.py @@ -29,13 +29,13 @@ class CommitteeHandoverCommandCog(TeXBotBaseCog): """Cog class that defines the "/committee-handover" command.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="committee-handover", description="Initiates the annual Discord handover procedure for new committee.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def committee_handover(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def committee_handover(self, ctx: "TeXBotApplicationContext") -> None: """ Definition & callback response of the "committee_handover" command. @@ -48,7 +48,7 @@ async def committee_handover(self, ctx: "TeXBotApplicationContext") -> None: # To do this, TeX-Bot will need to hold a role above that of the "Committee" role. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild committee_role: discord.Role = await self.bot.committee_role committee_elect_role: discord.Role = await self.bot.committee_elect_role @@ -177,13 +177,13 @@ class AnnualRolesResetCommandCog(TeXBotBaseCog): } ) - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="annual-roles-reset", description="Removes the @Member role and academic year roles from all users.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def annual_roles_reset(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def annual_roles_reset(self, ctx: "TeXBotApplicationContext") -> None: """ Definition & callback response of the "annual_roles_reset" command. @@ -191,7 +191,7 @@ async def annual_roles_reset(self, ctx: "TeXBotApplicationContext") -> None: # from any user that has them and subsequently deletes all instances of the GroupMadeMember database model. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild member_role: discord.Role = await self.bot.member_role @@ -266,13 +266,13 @@ async def annual_roles_reset(self, ctx: "TeXBotApplicationContext") -> None: # class AnnualYearChannelsIncrementCommandCog(TeXBotBaseCog): """Cog class that defines the "/increment-year-channels" command.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="increment-year-channels", description="Increments the year channels, archiving and creating channels as needed.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def increment_year_channels(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def increment_year_channels(self, ctx: "TeXBotApplicationContext") -> None: """ Definition and callback response of the "increment_year_channels" command. @@ -282,7 +282,7 @@ async def increment_year_channels(self, ctx: "TeXBotApplicationContext") -> None - Renames the current "first-years" channel to "second-years" - Creates a new "first-years" channel """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild guest_role: discord.Role = await self.bot.guest_role INCREMENT_YEAR_CHANNELS_AUDIT_MESSAGE: Final[str] = ( diff --git a/cogs/archive.py b/cogs/archive.py index 2f7c4d743..dc4f251a7 100644 --- a/cogs/archive.py +++ b/cogs/archive.py @@ -97,10 +97,10 @@ async def autocomplete_get_non_archived_channels( ) } - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="archive-category", description="Archives the selected category." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="category", description="The category to archive.", input_type=str, @@ -110,7 +110,7 @@ async def autocomplete_get_non_archived_channels( required=True, parameter_name="str_category_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="allow-archivist-access", description="Whether to allow archivists to access the category.", input_type=bool, @@ -119,7 +119,7 @@ async def autocomplete_get_non_archived_channels( ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def archive_category( # type: ignore[misc] + async def archive_category( self, ctx: "TeXBotApplicationContext", str_category_id: str, @@ -132,7 +132,7 @@ async def archive_category( # type: ignore[misc] have the "Archivist" role. This can be overridden via a boolean parameter to allow for committee channels to be archived with the same command but not be visible. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild archivist_role: discord.Role = await self.bot.archivist_role @@ -190,10 +190,10 @@ async def archive_category( # type: ignore[misc] content=f":white_check_mark: Category '{category.name}' successfully archived." ) - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="archive-channel", description="Archives the selected channel." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="channel", description="The channel to archive.", input_type=str, @@ -201,7 +201,7 @@ async def archive_category( # type: ignore[misc] required=True, parameter_name="str_channel_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="category", description="The category to move the channel to.", input_type=str, @@ -211,7 +211,7 @@ async def archive_category( # type: ignore[misc] ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def archive_channel( # type: ignore[misc] + async def archive_channel( self, ctx: "TeXBotApplicationContext", str_channel_id: str, str_category_id: str ) -> None: """ @@ -220,7 +220,7 @@ async def archive_channel( # type: ignore[misc] The "archive-channel" command moves the channel into the selected category and syncs the permissions to the category's permissions. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild if not re.fullmatch(r"\A\d{17,20}\Z", str_channel_id): diff --git a/cogs/check_su_platform_authorisation.py b/cogs/check_su_platform_authorisation.py index 28db87445..c57012a8e 100644 --- a/cogs/check_su_platform_authorisation.py +++ b/cogs/check_su_platform_authorisation.py @@ -182,13 +182,13 @@ async def get_su_platform_organisations(self) -> "Iterable[str]": class CheckSUPlatformAuthorisationCommandCog(CheckSUPlatformAuthorisationBaseCog): """Cog class that defines the "/check-su-platform-authorisation" command.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="check-su-platform-authorisation", description="Checks the authorisation held by the SU platform access cookie.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def check_su_platform_authorisation(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def check_su_platform_authorisation(self, ctx: "TeXBotApplicationContext") -> None: """ Definition of the "check_su_platform_authorisation" command. diff --git a/cogs/committee_actions_tracking.py b/cogs/committee_actions_tracking.py index 95eed962b..9b295337e 100644 --- a/cogs/committee_actions_tracking.py +++ b/cogs/committee_actions_tracking.py @@ -204,14 +204,14 @@ async def autocomplete_get_action_status( @committee_actions.command( name="create", description="Adds a new action with the specified description." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="description", description="The description of the action to assign.", input_type=str, required=True, parameter_name="action_description", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to assign the action to.", input_type=str, @@ -266,7 +266,7 @@ async def create( @committee_actions.command( name="update-status", description="Update the status of the provided action." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="action", description="The action to mark as completed.", input_type=str, @@ -274,7 +274,7 @@ async def create( required=True, parameter_name="action_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="status", description="The desired status of the action.", input_type=str, @@ -338,7 +338,7 @@ async def update_status( # NOTE: Committee role check is not present because no @committee_actions.command( name="update-description", description="Update the description of the provided action." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="action", description="The action to mark as completed.", input_type=str, @@ -346,7 +346,7 @@ async def update_status( # NOTE: Committee role check is not present because no required=True, parameter_name="action_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="description", description="The description to be used for the action", input_type=str, @@ -400,7 +400,7 @@ async def update_description( name="action-random-user", description="Creates an action object with the specified description and random user.", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="description", description="The description to be used for the action", input_type=str, @@ -463,7 +463,7 @@ async def action_random_user( name="action-all-committee", description="Creates an action with the description for every committee member", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="description", description="The description to be used for the actions", input_type=str, @@ -528,7 +528,7 @@ async def action_all_committee( @committee_actions.command( name="list", description="Lists all actions for a specified user" ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to list actions for.", input_type=str, @@ -537,14 +537,14 @@ async def action_all_committee( default=None, parameter_name="action_member_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="ping", description="Triggers whether the message pings users or not.", input_type=bool, default=False, required=False, ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="status", description="The desired status of the action.", input_type=str, @@ -647,7 +647,7 @@ async def list_user_actions( # NOTE: Committee role check is not present becaus @committee_actions.command( name="reassign", description="Reassign the specified action to another user." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="action", description="The action to reassign.", input_type=str, @@ -655,7 +655,7 @@ async def list_user_actions( # NOTE: Committee role check is not present becaus required=True, parameter_name="action_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to list actions for.", input_type=str, @@ -724,14 +724,14 @@ async def reassign_action( return @committee_actions.command(name="list-all", description="List all current actions.") - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="ping", description="Triggers whether the message pings users or not.", input_type=bool, default=False, required=False, ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="status-filter", description="The filter to apply to the status of actions.", input_type=str, @@ -795,7 +795,7 @@ async def list_all_actions( @committee_actions.command( name="delete", description="Deletes the specified action from the database completely." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="action", description="The action to delete.", input_type=str, @@ -841,13 +841,13 @@ async def delete_action(self, ctx: "TeXBotApplicationContext", action_id: str) - class CommitteeActionsTrackingContextCommandsCog(CommitteeActionsTrackingBaseCog): """Cog class to define the actions tracking message context commands.""" - @discord.message_command( # type: ignore[no-untyped-call, misc] + @discord.message_command( name="Action Message Author", description="Creates a new action for the message author using the message content.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def action_message_author( # type: ignore[misc] + async def action_message_author( self, ctx: "TeXBotApplicationContext", message: discord.Message ) -> None: """ diff --git a/cogs/edit_message.py b/cogs/edit_message.py index 5f240f083..e5b2a2069 100644 --- a/cogs/edit_message.py +++ b/cogs/edit_message.py @@ -43,11 +43,11 @@ async def autocomplete_get_text_channels( return await TeXBotBaseCog.autocomplete_get_text_channels(ctx) - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="edit-message", description="Edits a message sent by TeX-Bot to the value supplied.", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="channel", description="The channel that the message, you wish to edit, is in.", input_type=str, @@ -55,7 +55,7 @@ async def autocomplete_get_text_channels( required=True, parameter_name="str_channel_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="message_id", input_type=str, description="The ID of the message you wish to edit.", @@ -64,7 +64,7 @@ async def autocomplete_get_text_channels( min_length=17, parameter_name="str_message_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="text", input_type=str, description="The new text you want the message to say.", @@ -75,7 +75,7 @@ async def autocomplete_get_text_channels( ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def edit_message( # type: ignore[misc] + async def edit_message( self, ctx: "TeXBotApplicationContext", str_channel_id: str, @@ -87,7 +87,7 @@ async def edit_message( # type: ignore[misc] The "write_roles" command edits a message sent by TeX-Bot to the value supplied. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild if not re.fullmatch(r"\A\d{17,20}\Z", str_channel_id): diff --git a/cogs/everest.py b/cogs/everest.py index d7947f347..70dfe3123 100644 --- a/cogs/everest.py +++ b/cogs/everest.py @@ -59,8 +59,9 @@ def __str__(self) -> str: class EverestCommandCog(TeXBotBaseCog): """Cog class that defines the "/everest" command and its call-back method.""" + @staticmethod async def autocomplete_get_course_years( - self, ctx: "TeXBotAutocompleteContext" + ctx: "TeXBotAutocompleteContext", ) -> "AbstractSet[discord.OptionChoice] | AbstractSet[int] | AbstractSet[str]": """Autocomplete for the course year option.""" try: @@ -85,10 +86,10 @@ async def autocomplete_get_course_years( case _CourseTypes.M_SCI: return {1, 2, 3, 4} - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="everest", description="How many steps of everest is your assignment worth?" ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="course-type", description="The type of your university course.", input_type=str, @@ -99,7 +100,7 @@ async def autocomplete_get_course_years( required=True, parameter_name="raw_course_type", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="course-year", description="The current year of your university course.", input_type=int, @@ -107,7 +108,7 @@ async def autocomplete_get_course_years( required=True, parameter_name="course_year", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="percentage-of-module", description="The percentage of the module that the assignment is worth.", input_type=float, @@ -120,7 +121,7 @@ async def autocomplete_get_course_years( required=True, parameter_name="percentage_of_module", ) - async def everest( # type: ignore[misc] + async def everest( self, ctx: "TeXBotApplicationContext", raw_course_type: str, diff --git a/cogs/induct.py b/cogs/induct.py index 04284ee9b..9c90633a1 100644 --- a/cogs/induct.py +++ b/cogs/induct.py @@ -50,7 +50,7 @@ async def on_member_update(self, before: discord.Member, after: discord.Member) These post-induction actions are only applied to users that have just been inducted as a guest into your group's Discord guild. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild if before.guild != main_guild or after.guild != main_guild or before.bot or after.bot: @@ -183,7 +183,7 @@ async def _perform_induction( silent: bool, ) -> None: """Perform the actual process of inducting a member by giving them the Guest role.""" - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild guest_role: discord.Role = await self.bot.guest_role @@ -304,13 +304,13 @@ async def autocomplete_get_members( discord.OptionChoice(name=member.name, value=str(member.id)) for member in members } - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="induct", description=( "Gives a user the @Guest role, then sends a message in #general saying hello." ), ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to induct.", input_type=str, @@ -318,7 +318,7 @@ async def autocomplete_get_members( required=True, parameter_name="str_induct_member_id", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="silent", description="Triggers whether a message is sent or not.", input_type=bool, @@ -327,7 +327,7 @@ async def autocomplete_get_members( ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def induct( # type: ignore[misc] + async def induct( self, ctx: "TeXBotApplicationContext", str_induct_member_id: str, *, silent: bool ) -> None: """ @@ -351,10 +351,10 @@ async def induct( # type: ignore[misc] class InductContextCommandsCog(BaseInductCog): """Cog class to define the context-menu induction commands and their call-back methods.""" - @discord.user_command(name="Induct User") # type: ignore[no-untyped-call, misc] + @discord.user_command(name="Induct User") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def non_silent_user_induct( # type: ignore[misc] + async def non_silent_user_induct( self, ctx: "TeXBotApplicationContext", member: discord.Member ) -> None: """ @@ -367,10 +367,10 @@ async def non_silent_user_induct( # type: ignore[misc] """ await self._perform_induction(ctx, member, silent=False) - @discord.user_command(name="Silently Induct User") # type: ignore[no-untyped-call, misc] + @discord.user_command(name="Silently Induct User") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def silent_user_induct( # type: ignore[misc] + async def silent_user_induct( self, ctx: "TeXBotApplicationContext", member: discord.Member ) -> None: """ @@ -383,10 +383,10 @@ async def silent_user_induct( # type: ignore[misc] """ await self._perform_induction(ctx, member, silent=True) - @discord.message_command(name="Induct Message Author") # type: ignore[no-untyped-call, misc] + @discord.message_command(name="Induct Message Author") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def non_silent_message_induct( # type: ignore[misc] + async def non_silent_message_induct( self, ctx: "TeXBotApplicationContext", message: discord.Message ) -> None: """ @@ -418,13 +418,13 @@ async def non_silent_message_induct( # type: ignore[misc] class EnsureMembersInductedCommandCog(TeXBotBaseCog): """Cog class that defines the "/ensure-members-inducted" command and call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="ensure-members-inducted", description="Ensures all users with the @Member role also have the @Guest role.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def ensure_members_inducted(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def ensure_members_inducted(self, ctx: "TeXBotApplicationContext") -> None: """ Definition & callback response of the "ensure_members_inducted" command. @@ -432,7 +432,7 @@ async def ensure_members_inducted(self, ctx: "TeXBotApplicationContext") -> None within your group's Discord guild that have the "Member" role have also been given the "Guest" role. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild member_role: discord.Role = await self.bot.member_role guest_role: discord.Role = await self.bot.guest_role diff --git a/cogs/invite_link.py b/cogs/invite_link.py index 99aa79da4..5c273d022 100644 --- a/cogs/invite_link.py +++ b/cogs/invite_link.py @@ -18,10 +18,10 @@ class InviteLinkCommandCog(TeXBotBaseCog): """Cog class that defines the "/invite-link" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="invite-link", description="Display the invite link to this server." ) - async def invite_link(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def invite_link(self, ctx: "TeXBotApplicationContext") -> None: """Definition & callback response of the "invite_link" command.""" discord_invite_url: str | None = settings["CUSTOM_DISCORD_INVITE_URL"] diff --git a/cogs/kill.py b/cogs/kill.py index 5d8a5308e..aafa01609 100644 --- a/cogs/kill.py +++ b/cogs/kill.py @@ -46,12 +46,10 @@ async def cancel_shutdown_button_callback( # type: ignore[misc] class KillCommandCog(TeXBotBaseCog): """Cog class that defines the "/kill" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] - name="kill", description="Shutdown TeX-Bot." - ) + @discord.slash_command(name="kill", description="Shutdown TeX-Bot.") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def kill(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def kill(self, ctx: "TeXBotApplicationContext") -> None: """ Definition & callback response of the "kill" command. diff --git a/cogs/make_applicant.py b/cogs/make_applicant.py index f286b35de..3feec3eda 100644 --- a/cogs/make_applicant.py +++ b/cogs/make_applicant.py @@ -36,7 +36,7 @@ async def _perform_make_applicant( self, ctx: "TeXBotApplicationContext", applicant_member: discord.Member ) -> None: """Perform the actual process of making the user into a group-applicant.""" - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = ctx.bot.main_guild applicant_role: discord.Role = await ctx.bot.applicant_role guest_role: discord.Role = await ctx.bot.guest_role @@ -163,11 +163,11 @@ async def autocomplete_get_members( discord.OptionChoice(name=member.name, value=str(member.id)) for member in members } - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="make-applicant", description="Gives the user @Applicant role and removes the @Guest role if present.", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to make an Applicant.", input_type=str, @@ -177,7 +177,7 @@ async def autocomplete_get_members( ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def make_applicant( # type: ignore[misc] + async def make_applicant( self, ctx: "TeXBotApplicationContext", str_applicant_member_id: str ) -> None: """ @@ -201,10 +201,10 @@ async def make_applicant( # type: ignore[misc] class MakeApplicantContextCommandsCog(BaseMakeApplicantCog): """Cog class that defines the context menu make-applicant commands.""" - @discord.user_command(name="Make Applicant") # type: ignore[no-untyped-call, misc] + @discord.user_command(name="Make Applicant") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def user_make_applicant( # type: ignore[misc] + async def user_make_applicant( self, ctx: "TeXBotApplicationContext", member: discord.Member ) -> None: """ @@ -216,10 +216,10 @@ async def user_make_applicant( # type: ignore[misc] """ await self._perform_make_applicant(ctx, member) - @discord.message_command(name="Make Message Author Applicant") # type: ignore[no-untyped-call, misc] + @discord.message_command(name="Make Message Author Applicant") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def message_make_applicant( # type: ignore[misc] + async def message_make_applicant( self, ctx: "TeXBotApplicationContext", message: discord.Message ) -> None: """ diff --git a/cogs/make_member.py b/cogs/make_member.py index ad3ace56b..007a04f8e 100644 --- a/cogs/make_member.py +++ b/cogs/make_member.py @@ -54,14 +54,14 @@ class MakeMemberCommandCog(TeXBotBaseCog): """Cog class that defines the "/make-member" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="make-member", description=( "Gives you the Member role " f"when supplied with an appropriate {_GROUP_MEMBER_ID_ARGUMENT_DESCRIPTIVE_NAME}." ), ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name=_GROUP_MEMBER_ID_ARGUMENT_NAME, description=( f"""Your UoB Student { @@ -90,7 +90,7 @@ class MakeMemberCommandCog(TeXBotBaseCog): parameter_name="raw_group_member_id", ) @CommandChecks.check_interaction_user_in_main_guild - async def make_member( # type: ignore[misc] + async def make_member( self, ctx: "TeXBotApplicationContext", raw_group_member_id: str ) -> None: """ @@ -100,7 +100,7 @@ async def make_member( # type: ignore[misc] has purchased a valid membership to your community group, then gives the member the "Member" role. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent member_role: discord.Role = await self.bot.member_role interaction_member: discord.Member = await ctx.bot.get_main_guild_member(ctx.user) @@ -211,10 +211,10 @@ async def make_member( # type: ignore[misc] class MemberCountCommandCog(TeXBotBaseCog): """Cog class that defines the "/member-count" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="member-count", description="Displays the number of members in the group." ) - async def member_count(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def member_count(self, ctx: "TeXBotApplicationContext") -> None: """Definition & callback response of the "member_count" command.""" await ctx.defer(ephemeral=False) diff --git a/cogs/ping.py b/cogs/ping.py index a92ad6202..fa3d71378 100644 --- a/cogs/ping.py +++ b/cogs/ping.py @@ -19,8 +19,8 @@ class PingCommandCog(TeXBotBaseCog): """Cog class that defines the "/ping" command and its call-back method.""" - @discord.slash_command(name="ping", description="Replies with Pong!") # type: ignore[no-untyped-call, misc] - async def ping(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + @discord.slash_command(name="ping", description="Replies with Pong!") + async def ping(self, ctx: "TeXBotApplicationContext") -> None: """Definition & callback response of the "ping" command.""" await ctx.respond( random.choices( # noqa: S311 diff --git a/cogs/remind_me.py b/cogs/remind_me.py index 78c3db494..3c84dcba9 100644 --- a/cogs/remind_me.py +++ b/cogs/remind_me.py @@ -185,24 +185,24 @@ async def autocomplete_get_delays( # noqa: PLR0912, PLR0915 return {f"{ctx.value}{delay_choice}".casefold() for delay_choice in delay_choices} - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="remind-me", description="Responds with the given message after the specified time.", ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="delay", input_type=str, description="The amount of time to wait before reminding you.", required=True, autocomplete=discord.utils.basic_autocomplete(autocomplete_get_delays), # type: ignore[arg-type] ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="message", input_type=str, description="The message you want to be reminded with.", required=False, ) - async def remind_me( # type: ignore[misc] + async def remind_me( self, ctx: "TeXBotApplicationContext", delay: str, message: str ) -> None: """ diff --git a/cogs/send_get_roles_reminders.py b/cogs/send_get_roles_reminders.py index 6dbc196fb..606f1bfb6 100644 --- a/cogs/send_get_roles_reminders.py +++ b/cogs/send_get_roles_reminders.py @@ -68,7 +68,7 @@ async def send_get_roles_reminders(self) -> None: See README.md for the full list of conditions for when these reminders are sent. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild guest_role: discord.Role = await self.bot.guest_role roles_channel_mention: str = await self.bot.get_mention_string(self.bot.roles_channel) diff --git a/cogs/send_introduction_reminders.py b/cogs/send_introduction_reminders.py index 24e69dadd..720bc6169 100644 --- a/cogs/send_introduction_reminders.py +++ b/cogs/send_introduction_reminders.py @@ -82,7 +82,7 @@ async def send_introduction_reminders(self) -> None: See README.md for the full list of conditions for when these reminders are sent. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild member: discord.Member diff --git a/cogs/source.py b/cogs/source.py index b6de59c79..7d3deda66 100644 --- a/cogs/source.py +++ b/cogs/source.py @@ -17,10 +17,10 @@ class SourceCommandCog(TeXBotBaseCog): """Cog class that defines the "/source" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( description="Displays information about the source code of TeX-Bot." ) - async def source(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def source(self, ctx: "TeXBotApplicationContext") -> None: """Definition & callback response of the "source" command.""" await ctx.respond( ( diff --git a/cogs/stats/__init__.py b/cogs/stats/__init__.py index 5db05ae82..dee8f85ea 100644 --- a/cogs/stats/__init__.py +++ b/cogs/stats/__init__.py @@ -64,7 +64,7 @@ class StatsCommandsCog(TeXBotBaseCog): @stats.command( name="channel", description="Displays the stats for the current/a given channel." ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="channel", description="The channel to display the stats for.", input_type=str, @@ -83,7 +83,7 @@ async def channel_stats( The "channel_stats" command sends a graph of the stats about messages sent in the given channel. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild channel_id: int = ctx.channel_id @@ -153,7 +153,7 @@ async def server_stats(self, ctx: "TeXBotApplicationContext") -> None: The "server_stats" command sends a graph of the stats about messages sent in the whole of your group's Discord guild. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild guest_role: discord.Role = await self.bot.guest_role @@ -232,7 +232,7 @@ async def user_stats(self, ctx: "TeXBotApplicationContext") -> None: The "user_stats" command sends a graph of the stats about messages sent by the given member. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild interaction_member: discord.Member = await self.bot.get_main_guild_member(ctx.user) guest_role: discord.Role = await self.bot.guest_role @@ -311,7 +311,7 @@ async def left_member_stats(self, ctx: "TeXBotApplicationContext") -> None: The "left_member_stats" command sends a graph of the stats about the roles that members had when they left your group's Discord guild. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild await ctx.defer(ephemeral=True) diff --git a/cogs/strike.py b/cogs/strike.py index 295a34aee..3c3b9e131 100644 --- a/cogs/strike.py +++ b/cogs/strike.py @@ -493,7 +493,7 @@ async def get_confirmation_message_channel( async def _confirm_manual_add_strike( # noqa: PLR0915 self, strike_user: discord.User | discord.Member, action: discord.AuditLogAction ) -> None: - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild committee_role: discord.Role = await self.bot.committee_role @@ -738,7 +738,7 @@ async def _confirm_manual_add_strike( # noqa: PLR0915 @capture_guild_does_not_exist_error async def on_member_update(self, before: discord.Member, after: discord.Member) -> None: """Flag manually applied timeout and track strikes accordingly.""" - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild if before.guild != main_guild or after.guild != main_guild or before.bot or after.bot: @@ -767,7 +767,7 @@ async def on_member_update(self, before: discord.Member, after: discord.Member) @capture_guild_does_not_exist_error async def on_member_remove(self, member: discord.Member) -> None: """Flag manually applied kick and track strikes accordingly.""" - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent main_guild: discord.Guild = self.bot.main_guild MEMBER_REMOVED_BECAUSE_OF_MANUALLY_APPLIED_KICK: Final[bool] = bool( @@ -829,14 +829,14 @@ async def autocomplete_get_members( discord.OptionChoice(name=member.name, value=str(member.id)) for member in members } - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="strike", description=( "Gives a user an additional strike, " "then performs the appropriate moderation action." ), ) - @discord.option( # type: ignore[no-untyped-call, misc] + @discord.option( name="user", description="The user to give a strike to.", input_type=str, @@ -846,7 +846,7 @@ async def autocomplete_get_members( ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def strike(self, ctx: "TeXBotApplicationContext", str_strike_member_id: str) -> None: # type: ignore[misc] + async def strike(self, ctx: "TeXBotApplicationContext", str_strike_member_id: str) -> None: """ Definition & callback response of the "strike" command. @@ -864,10 +864,10 @@ async def strike(self, ctx: "TeXBotApplicationContext", str_strike_member_id: st await self._command_perform_strike(ctx, strike_member) - @discord.slash_command( # type: ignore[misc, no-untyped-call] + @discord.slash_command( name="get-strikes", description="Get the number of strikes a user has." ) - @discord.option( # type: ignore[misc, no-untyped-call] + @discord.option( name="user", description="The user to check the number of strikes for.", input_type=str, @@ -877,7 +877,7 @@ async def strike(self, ctx: "TeXBotApplicationContext", str_strike_member_id: st ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def get_strikes( # type: ignore[misc] + async def get_strikes( self, ctx: "TeXBotApplicationContext", str_strike_member_id: str ) -> None: """ @@ -908,10 +908,10 @@ async def get_strikes( # type: ignore[misc] ephemeral=True, ) - @discord.slash_command( # type: ignore[misc, no-untyped-call] + @discord.slash_command( name="decrement-strikes", description="Remove a single strike from a user." ) - @discord.option( # type: ignore[misc, no-untyped-call] + @discord.option( name="user", description="The user to remove a strike from.", input_type=str, @@ -921,7 +921,7 @@ async def get_strikes( # type: ignore[misc] ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def decrement_strikes( # type: ignore[misc] + async def decrement_strikes( self, ctx: "TeXBotApplicationContext", str_strike_member_id: str ) -> None: """ @@ -1070,19 +1070,19 @@ async def _send_message_to_committee( ephemeral=True, ) - @discord.user_command(name="Strike User") # type: ignore[no-untyped-call, misc] + @discord.user_command(name="Strike User") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def user_strike( # type: ignore[misc] + async def user_strike( self, ctx: "TeXBotApplicationContext", member: discord.Member ) -> None: """Call the _strike command, providing the required command arguments.""" await self._command_perform_strike(ctx, strike_member=member) - @discord.message_command(name="Strike Message Author") # type: ignore[no-untyped-call, misc] + @discord.message_command(name="Strike Message Author") @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def strike_message_author( # type: ignore[misc] + async def strike_message_author( self, ctx: "TeXBotApplicationContext", message: discord.Message ) -> None: """Call the _strike command on the message author.""" @@ -1092,13 +1092,13 @@ async def strike_message_author( # type: ignore[misc] await self._send_message_to_committee(ctx, message=message) await self._command_perform_strike(ctx, strike_member=strike_user) - @discord.message_command( # type: ignore[no-untyped-call, misc] + @discord.message_command( name="Send Message to Committee", description="Sends the selected message to the committee channel for discussion.", ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def send_message_to_committee( # type: ignore[misc] + async def send_message_to_committee( self, ctx: "TeXBotApplicationContext", message: discord.Message ) -> None: """Send a copy of the selected message to committee channels for review.""" diff --git a/cogs/write_roles.py b/cogs/write_roles.py index 0b4d540d7..adc41bbd8 100644 --- a/cogs/write_roles.py +++ b/cogs/write_roles.py @@ -18,19 +18,19 @@ class WriteRolesCommandCog(TeXBotBaseCog): """Cog class that defines the "/write-roles" command and its call-back method.""" - @discord.slash_command( # type: ignore[no-untyped-call, misc] + @discord.slash_command( name="write-roles", description="Populates #roles with the correct messages." ) @CommandChecks.check_interaction_user_has_committee_role @CommandChecks.check_interaction_user_in_main_guild - async def write_roles(self, ctx: "TeXBotApplicationContext") -> None: # type: ignore[misc] + async def write_roles(self, ctx: "TeXBotApplicationContext") -> None: """ Definition & callback response of the "write_roles" command. The "write_roles" command populates the "#roles" channel with the correct messages defined in the messages.json file. """ - # NOTE: Shortcut accessors are placed at the top of the function, so that the exceptions they raise are displayed before any further errors may be sent + # NOTE: Shortcut accessors are placed at the top of the function so that the exceptions they raise are displayed before any further errors may be sent roles_channel: discord.TextChannel = await self.bot.roles_channel roles_message: str diff --git a/pyproject.toml b/pyproject.toml index 9d6399a2f..e1c6319b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,7 @@ enable_error_code = [ "unused-awaitable", ] extra_checks = true +mypy_path = "stubs" no_implicit_reexport = true plugins = ["mypy_django_plugin.main"] strict_equality = true @@ -171,9 +172,6 @@ banned-aliases = { "regex" = [ ] } banned-from = ["abc", "re", "regex"] -[tool.ruff.lint.per-file-ignores] -"tests/**/test_*.py" = ["S101"] - [tool.ruff.lint.flake8-self] extend-ignore-names = ["_base_manager", "_default_manager", "_get_wrap_line_width", "_meta"] @@ -189,6 +187,11 @@ known-first-party = ["cogs", "config", "db", "exceptions", "main", "tests", "uti classmethod-decorators = ["typed_classproperties.classproperty"] extend-ignore-names = ["BROKEN_*_MESSAGE", "INVALID_*_MESSAGE", "NO_*_MESSAGE"] +[tool.ruff.lint.per-file-ignores] +"stubs/discord/**/*.pyi" = ["F403"] +"stubs/discord/commands/__init__.pyi" = ["F405"] +"tests/**/test_*.py" = ["S101"] + [tool.ruff.lint.pycodestyle] ignore-overlong-task-comments = true max-doc-length = 95 diff --git a/stubs/discord/__init__.pyi b/stubs/discord/__init__.pyi new file mode 100644 index 000000000..83fa70d4d --- /dev/null +++ b/stubs/discord/__init__.pyi @@ -0,0 +1,86 @@ +from collections.abc import Sequence + +from ._version import * +from .activity import * +from .appinfo import * +from .application_role_connection import * +from .asset import * +from .audit_logs import * +from .automod import * +from .bot import * +from .channel import * +from .client import * +from .cog import * +from .colour import * +from .commands import ( + ApplicationCommand, + ApplicationContext, + AutocompleteContext, + MessageCommand, + Option, + OptionChoice, + SlashCommand, + SlashCommandGroup, + UserCommand, + application_command, + command, + message_command, + option, + slash_command, + user_command, +) +from .components import * +from .embeds import * +from .emoji import * +from .enums import * +from .errors import * +from .file import * +from .flags import * +from .guild import * +from .http import * +from .integrations import * +from .interactions import * +from .invite import * +from .member import * +from .mentions import * +from .message import * +from .monetization import * +from .object import * +from .onboarding import * +from .partial_emoji import * +from .permissions import * +from .player import * +from .poll import * +from .raw_models import * +from .reaction import * +from .role import * +from .scheduled_events import * +from .shard import * +from .stage_instance import * +from .sticker import * +from .team import * +from .template import * +from .threads import * +from .user import * +from .voice_client import * +from .webhook import * +from .welcome_screen import * +from .widget import * + +__all__: Sequence[str] = ( + "ApplicationCommand", + "ApplicationContext", + "AutocompleteContext", + "MessageCommand", + "Option", + "OptionChoice", + "SlashCommand", + "SlashCommandGroup", + "UserCommand", + "application_command", + "command", + "message_command", + "option", + "slash_command", + "user_command", +) diff --git a/stubs/discord/commands/__init__.pyi b/stubs/discord/commands/__init__.pyi new file mode 100644 index 000000000..c9930dec3 --- /dev/null +++ b/stubs/discord/commands/__init__.pyi @@ -0,0 +1,36 @@ +from collections.abc import Sequence + +from discord.commands.context import * +from discord.commands.permissions import * + +from .core import ( + ApplicationCommand, + MessageCommand, + SlashCommand, + SlashCommandGroup, + UserCommand, + application_command, + command, + message_command, + slash_command, + user_command, +) +from .options import Option, OptionChoice, option + +__all__: Sequence[str] = ( + "ApplicationCommand", + "ApplicationContext", + "AutocompleteContext", + "MessageCommand", + "Option", + "OptionChoice", + "SlashCommand", + "SlashCommandGroup", + "UserCommand", + "application_command", + "command", + "message_command", + "option", + "slash_command", + "user_command", +) diff --git a/stubs/discord/commands/core.pyi b/stubs/discord/commands/core.pyi new file mode 100644 index 000000000..e194a0b73 --- /dev/null +++ b/stubs/discord/commands/core.pyi @@ -0,0 +1,48 @@ +from collections.abc import Awaitable, Callable, Sequence + +__all__: Sequence[str] = ( + "ApplicationCommand", + "MessageCommand", + "SlashCommand", + "SlashCommandGroup", + "UserCommand", + "application_command", + "command", + "message_command", + "slash_command", + "user_command", +) + +from typing import override + +def slash_command[**P]( + *, + description: str, + name: str = ..., +) -> Callable[[Callable[P, Awaitable[None]]], SlashCommand]: ... +def user_command[**P]( + *, name: str = ..., description: str = ... +) -> Callable[[Callable[P, Awaitable[None]]], UserCommand]: ... +def message_command[**P]( + *, name: str = ..., description: str = ... +) -> Callable[[Callable[P, Awaitable[None]]], MessageCommand]: ... +def application_command[**P]( + *, description: str, name: str = ... +) -> Callable[[Callable[P, Awaitable[None]]], ApplicationCommand]: ... +def command[**P]( + *, description: str, name: str = ... +) -> Callable[[Callable[P, Awaitable[None]]], ApplicationCommand]: ... + +class ApplicationCommand: + qualified_name: str + +class SlashCommand(ApplicationCommand): ... +class UserCommand(ApplicationCommand): ... +class MessageCommand(ApplicationCommand): ... + +class SlashCommandGroup(ApplicationCommand): + @override + def __init__(self, name: str, description: str) -> None: ... + def command[**P, T: ApplicationCommand]( + self, cls: type[T] = ..., *, name: str, description: str + ) -> Callable[[Callable[P, Awaitable[None]]], T]: ... diff --git a/stubs/discord/commands/options.pyi b/stubs/discord/commands/options.pyi new file mode 100644 index 000000000..accdd0ab5 --- /dev/null +++ b/stubs/discord/commands/options.pyi @@ -0,0 +1,45 @@ +from collections.abc import Awaitable, Callable, Iterable, Sequence +from typing import overload, override + +from discord.commands.context import AutocompleteContext + +__all__: Sequence[str] = ("Option", "OptionChoice", "option") + +class Option: ... + +class OptionChoice: + @override + def __init__(self, name: str, value: str | float) -> None: ... + +@overload +def option[**P, **Q, T, T_context: AutocompleteContext]( + *, + name: str, + description: str, + input_type: type[T], + required: bool = ..., + default: T = ..., + choices: Iterable[OptionChoice] | Iterable[str] | Iterable[int] | Iterable[float] = ..., + parameter_name: str = ..., + autocomplete: Callable[ + [T_context], + Awaitable[Iterable[OptionChoice] | Iterable[str] | Iterable[int] | Iterable[float]], + ] = ..., +) -> Callable[[Callable[P, Awaitable[None]]], Callable[Q, Awaitable[None]]]: ... +@overload +def option[**P, **Q, T_context: AutocompleteContext]( + *, + name: str, + description: str, + input_type: type[str], + parameter_name: str = ..., + default: str = ..., + choices: Iterable[OptionChoice] | Iterable[str] | Iterable[int] | Iterable[float] = ..., + autocomplete: Callable[ + [T_context], + Awaitable[Iterable[OptionChoice] | Iterable[str] | Iterable[int] | Iterable[float]], + ] = ..., + required: bool = ..., + min_length: int = ..., + max_length: int = ..., +) -> Callable[[Callable[P, Awaitable[None]]], Callable[Q, Awaitable[None]]]: ...