mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-20 16:00:29 +00:00
Raise special CommandSyncFailure during sync for better errors
This is parsed from the error to allow for users to better debug what exactly is causing the issue in sync.
This commit is contained in:
parent
a9025ca3d1
commit
1fa7d7e402
@ -26,9 +26,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, TYPE_CHECKING, List, Optional, Union
|
||||
|
||||
|
||||
from ..enums import AppCommandOptionType, AppCommandType, Locale
|
||||
from ..errors import DiscordException
|
||||
from ..errors import DiscordException, HTTPException, _flatten_error_dict
|
||||
|
||||
__all__ = (
|
||||
'AppCommandError',
|
||||
@ -47,6 +46,7 @@ __all__ = (
|
||||
'BotMissingPermissions',
|
||||
'CommandOnCooldown',
|
||||
'MissingApplicationID',
|
||||
'CommandSyncFailure',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -56,6 +56,8 @@ if TYPE_CHECKING:
|
||||
from ..types.snowflake import Snowflake, SnowflakeList
|
||||
from .checks import Cooldown
|
||||
|
||||
CommandTypes = Union[Command[Any, ..., Any], Group, ContextMenu]
|
||||
|
||||
APP_ID_NOT_FOUND = (
|
||||
'Client does not have an application_id set. Either the function was called before on_ready '
|
||||
'was called or application_id was not passed to the Client constructor.'
|
||||
@ -444,3 +446,58 @@ class MissingApplicationID(AppCommandError):
|
||||
|
||||
def __init__(self, message: Optional[str] = None):
|
||||
super().__init__(message or APP_ID_NOT_FOUND)
|
||||
|
||||
|
||||
def _get_command_error(index: str, inner: Any, commands: List[CommandTypes], messages: List[str]) -> None:
|
||||
# Top level errors are:
|
||||
# <number>: { <key>: <error> }
|
||||
# The dicts could be nested, e.g.
|
||||
# <number>: { <key>: { <second>: <error> } }
|
||||
# Luckily, this is already handled by the flatten_error_dict utility
|
||||
if not index.isdigit():
|
||||
errors = _flatten_error_dict(inner, index)
|
||||
messages.extend(f'In {k}: {v}' for k, v in errors.items())
|
||||
return
|
||||
|
||||
idx = int(index)
|
||||
try:
|
||||
command = commands[idx]
|
||||
except IndexError:
|
||||
errors = _flatten_error_dict(inner, index)
|
||||
messages.extend(f'In {k}: {v}' for k, v in errors.items())
|
||||
return
|
||||
|
||||
callback = getattr(command, 'callback', None)
|
||||
class_name = command.__class__.__name__
|
||||
if callback:
|
||||
messages.append(f'In {class_name} {command.qualified_name!r} defined in {callback.__qualname__!r}')
|
||||
else:
|
||||
messages.append(f'In {class_name} {command.qualified_name!r} defined in module {command.module!r}')
|
||||
|
||||
errors = _flatten_error_dict(inner)
|
||||
messages.extend(f' {k}: {v}' for k, v in errors.items())
|
||||
|
||||
|
||||
class CommandSyncFailure(AppCommandError, HTTPException):
|
||||
"""An exception raised when :meth:`CommandTree.sync` failed.
|
||||
|
||||
This provides syncing failures in a slightly more readable format.
|
||||
|
||||
This inherits from :exc:`~discord.app_commands.AppCommandError`
|
||||
and :exc:`~discord.HTTPException`.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
||||
def __init__(self, child: HTTPException, commands: List[CommandTypes]) -> None:
|
||||
# Consume the child exception and make it seem as if we are that exception
|
||||
self.__dict__.update(child.__dict__)
|
||||
|
||||
messages = [f'Failed to upload commands to Discord (HTTP status {self.status}, error code {self.code})']
|
||||
|
||||
if self._errors:
|
||||
for index, inner in self._errors.items():
|
||||
_get_command_error(index, inner, commands, messages)
|
||||
|
||||
# Equivalent to super().__init__(...) but skips other constructors
|
||||
self.args = ('\n'.join(messages),)
|
||||
|
@ -56,10 +56,11 @@ from .errors import (
|
||||
CommandNotFound,
|
||||
CommandSignatureMismatch,
|
||||
CommandLimitReached,
|
||||
CommandSyncFailure,
|
||||
MissingApplicationID,
|
||||
)
|
||||
from .translator import Translator, locale_str
|
||||
from ..errors import ClientException
|
||||
from ..errors import ClientException, HTTPException
|
||||
from ..enums import AppCommandType, InteractionType
|
||||
from ..utils import MISSING, _get_as_snowflake, _is_submodule
|
||||
|
||||
@ -1034,6 +1035,10 @@ class CommandTree(Generic[ClientT]):
|
||||
-------
|
||||
HTTPException
|
||||
Syncing the commands failed.
|
||||
CommandSyncFailure
|
||||
Syncing the commands failed due to a user related error, typically because
|
||||
the command has invalid data. This is equivalent to an HTTP status code of
|
||||
400.
|
||||
Forbidden
|
||||
The client does not have the ``applications.commands`` scope in the guild.
|
||||
MissingApplicationID
|
||||
@ -1058,10 +1063,15 @@ class CommandTree(Generic[ClientT]):
|
||||
else:
|
||||
payload = [command.to_dict() for command in commands]
|
||||
|
||||
if guild is None:
|
||||
data = await self._http.bulk_upsert_global_commands(self.client.application_id, payload=payload)
|
||||
else:
|
||||
data = await self._http.bulk_upsert_guild_commands(self.client.application_id, guild.id, payload=payload)
|
||||
try:
|
||||
if guild is None:
|
||||
data = await self._http.bulk_upsert_global_commands(self.client.application_id, payload=payload)
|
||||
else:
|
||||
data = await self._http.bulk_upsert_guild_commands(self.client.application_id, guild.id, payload=payload)
|
||||
except HTTPException as e:
|
||||
if e.status == 400:
|
||||
raise CommandSyncFailure(e, commands) from None
|
||||
raise
|
||||
|
||||
return [AppCommand(data=d, state=self._state) for d in data]
|
||||
|
||||
|
@ -121,6 +121,7 @@ class HTTPException(DiscordException):
|
||||
self.code = message.get('code', 0)
|
||||
base = message.get('message', '')
|
||||
errors = message.get('errors')
|
||||
self._errors: Optional[Dict[str, Any]] = errors
|
||||
if errors:
|
||||
errors = _flatten_error_dict(errors)
|
||||
helpful = '\n'.join('In %s: %s' % t for t in errors.items())
|
||||
|
@ -4724,4 +4724,5 @@ Exception Hierarchy
|
||||
- :exc:`Forbidden`
|
||||
- :exc:`NotFound`
|
||||
- :exc:`DiscordServerError`
|
||||
- :exc:`app_commands.CommandSyncFailure`
|
||||
- :exc:`RateLimited`
|
||||
|
@ -721,6 +721,9 @@ Exceptions
|
||||
.. autoexception:: discord.app_commands.MissingApplicationID
|
||||
:members:
|
||||
|
||||
.. autoexception:: discord.app_commands.CommandSyncFailure
|
||||
:members:
|
||||
|
||||
Exception Hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -743,3 +746,6 @@ Exception Hierarchy
|
||||
- :exc:`~discord.app_commands.CommandSignatureMismatch`
|
||||
- :exc:`~discord.app_commands.CommandNotFound`
|
||||
- :exc:`~discord.app_commands.MissingApplicationID`
|
||||
- :exc:`~discord.app_commands.CommandSyncFailure`
|
||||
- :exc:`~discord.HTTPException`
|
||||
- :exc:`~discord.app_commands.CommandSyncFailure`
|
||||
|
Loading…
x
Reference in New Issue
Block a user