diff --git a/discord/client.py b/discord/client.py index 250e9da1..b09791a9 100644 --- a/discord/client.py +++ b/discord/client.py @@ -595,7 +595,7 @@ class Client: async def start(self, token: str, *, reconnect: bool = True) -> None: """|coro| - A shorthand coroutine for :meth:`login` + :meth:`connect`. + A shorthand coroutine for :meth:`login` + :meth:`setup` + :meth:`connect`. Raises ------- @@ -603,8 +603,19 @@ class Client: An unexpected keyword argument was received. """ await self.login(token) + await self.setup() await self.connect(reconnect=reconnect) + async def setup(self) -> Any: + """|coro| + + A coroutine to be called to setup the bot, by default this is blank. + + To perform asynchronous setup after the bot is logged in but before + it has connected to the Websocket, overwrite this coroutine. + """ + pass + def run(self, *args: Any, **kwargs: Any) -> None: """A blocking call that abstracts away the event loop initialisation from you. diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py index 46ccdee4..faf6f989 100644 --- a/discord/ext/commands/bot.py +++ b/discord/ext/commands/bot.py @@ -28,6 +28,7 @@ from __future__ import annotations import asyncio import collections import collections.abc +from discord.http import HTTPClient import inspect import importlib.util @@ -166,7 +167,7 @@ class BotBase(GroupMixin): if not (message_commands or slash_commands): raise TypeError("Both message_commands and slash_commands are disabled.") elif slash_commands: - self.slash_command_guild = options['slash_command_guild'] + self.slash_command_guild = options.get('slash_command_guild', None) if help_command is _default: self.help_command = DefaultHelpCommand() @@ -183,6 +184,15 @@ class BotBase(GroupMixin): for event in self.extra_events.get(ev, []): self._schedule_event(event, ev, *args, **kwargs) # type: ignore + async def _create_application_commands(self, application_id: int, http: HTTPClient): + commands = [scmd for cmd in self.commands if not cmd.hidden and (scmd := cmd.to_application_command()) is not None] + + if self.slash_command_guild is None: + await http.bulk_upsert_global_commands(application_id, payload=commands) + else: + await http.bulk_upsert_guild_commands(application_id, self.slash_command_guild, payload=commands) + + @discord.utils.copy_doc(discord.Client.close) async def close(self) -> None: for extension in tuple(self.__extensions): @@ -1211,23 +1221,20 @@ class Bot(BotBase, discord.Client): .. versionadded:: 1.7 """ - # Needs to be moved to somewhere else, preferably BotBase - async def login(self, token: str) -> None: - await super().login(token=token) - await self._ready_commands() - - async def _ready_commands(self): + async def setup(self): if not self.slash_commands: return application = self.application_id or (await self.application_info()).id - commands = [scmd for cmd in self.commands if not cmd.hidden and (scmd := cmd.to_application_command()) is not None] - - await self.http.bulk_upsert_guild_commands(application, self.slash_command_guild, payload=commands) - + await self._create_application_commands(application, self.http) class AutoShardedBot(BotBase, discord.AutoShardedClient): """This is similar to :class:`.Bot` except that it is inherited from :class:`discord.AutoShardedClient` instead. """ - pass + async def setup(self): + if not self.slash_commands: + return + + application = self.application_id or (await self.application_info()).id + await self._create_application_commands(application, self.http)