Skip to content

Commit 2929091

Browse files
authored
feat: on_command_error event (#949)
* feat: on_command_error event * docs: document on_command_error
1 parent 19a2eb6 commit 2929091

File tree

3 files changed

+40
-20
lines changed

3 files changed

+40
-20
lines changed

docs/events.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ There are several different internal events:
5454
- ``on_start``
5555
- ``on_interaction``
5656
- ``on_command``
57+
- ``on_command_error``
5758
- ``on_component``
5859
- ``on_autocomplete``
5960
- ``on_modal``
@@ -100,6 +101,16 @@ Using this event, you will have to manually check everything, from name to wheth
100101
options or anything else - everything will be in the raw context and you will have to search for it
101102

102103

104+
Event: ``on_command_error``
105+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
106+
This event fires when the following conditions are met:
107+
108+
1. There is an error in the command (or subcommand within the command)
109+
2. There is no error callback assigned to that command
110+
111+
The function takes in two arguments, one of the type ``CommandContext``, and the other contains the error.
112+
113+
103114
Event: ``on_component``
104115
^^^^^^^^^^^^^^^^^^^^^^
105116
This event fires on any Component used (for now, those are Buttons and Select Menus).

interactions/client/bot.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,11 @@ def __resolve_commands(self) -> None:
456456
if cmd.resolved:
457457
continue
458458

459+
cmd.listener = self._websocket._dispatch
460+
459461
if cmd.default_scope and self._default_scope:
460462
cmd.scope = (
461-
cmd.scope.extend(cmd.default_scope)
463+
cmd.scope.extend(self._default_scope)
462464
if isinstance(cmd.scope, list)
463465
else self._default_scope
464466
)

interactions/client/models/command.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from ..enums import ApplicationCommandType, Locale, OptionType, PermissionType
1616

1717
if TYPE_CHECKING:
18+
from ...api.dispatch import Listener
1819
from ..bot import Extension
1920
from ..context import CommandContext
2021

@@ -396,7 +397,8 @@ class Command(DictSerializerMixin):
396397
:ivar Dict[str, Union[Callable[..., Awaitable], str]] autocompletions: The dictionary of autocompletions for the command.
397398
:ivar Optional[str] recent_group: The name of the group most recently utilized.
398399
:ivar bool resolved: Whether the command is synced. Defaults to ``False``.
399-
:ivar Extension extension: The extension that the command belongs to, if any.
400+
:ivar Optional[Extension] extension: The extension that the command belongs to, if any.
401+
:ivar Optional[Listener] listener: The listener, used for dispatching command errors.
400402
"""
401403

402404
coro: Callable[..., Awaitable] = field()
@@ -419,7 +421,8 @@ class Command(DictSerializerMixin):
419421
recent_group: Optional[str] = field(default=None, init=False)
420422
error_callback: Optional[Callable[..., Awaitable]] = field(default=None, init=False)
421423
resolved: bool = field(default=False, init=False)
422-
extension: "Extension" = field(default=None, init=False)
424+
extension: Optional["Extension"] = field(default=None, init=False)
425+
listener: Optional["Listener"] = field(default=None, init=False)
423426

424427
def __attrs_post_init__(self) -> None:
425428
if self.name is MISSING:
@@ -837,17 +840,19 @@ async def __call(
837840
except CancelledError:
838841
pass
839842
except Exception as e:
840-
if not self.error_callback:
841-
raise e
842-
843-
num_params = len(signature(self.error_callback).parameters)
843+
if self.error_callback:
844+
num_params = len(signature(self.error_callback).parameters)
844845

845-
if num_params == (3 if self.extension else 2):
846-
await self.error_callback(ctx, e)
847-
elif num_params == (4 if self.extension else 3):
848-
await self.error_callback(ctx, e, _res)
846+
if num_params == (3 if self.extension else 2):
847+
await self.error_callback(ctx, e)
848+
elif num_params == (4 if self.extension else 3):
849+
await self.error_callback(ctx, e, _res)
850+
else:
851+
await self.error_callback(ctx, e, _res, *args, **kwargs)
852+
elif self.listener and "on_command_error" in self.listener.events:
853+
self.listener.dispatch("on_command_error", ctx, e)
849854
else:
850-
await self.error_callback(ctx, e, _res, *args, **kwargs)
855+
raise e
851856

852857
return StopCommand
853858

@@ -888,15 +893,17 @@ async def wrapper(ctx: "CommandContext", *args, **kwargs):
888893
except CancelledError:
889894
pass
890895
except Exception as e:
891-
if self.has_subcommands or not self.error_callback:
892-
raise e
893-
894-
num_params = len(signature(self.error_callback).parameters)
895-
896-
if num_params == (3 if self.extension else 2):
897-
await self.error_callback(ctx, e)
896+
if self.error_callback:
897+
num_params = len(signature(self.error_callback).parameters)
898+
899+
if num_params == (3 if self.extension else 2):
900+
await self.error_callback(ctx, e)
901+
else:
902+
await self.error_callback(ctx, e, *args, **kwargs)
903+
elif self.listener and "on_command_error" in self.listener.events:
904+
self.listener.dispatch("on_command_error", ctx, e)
898905
else:
899-
await self.error_callback(ctx, e, *args, **kwargs)
906+
raise e
900907

901908
return StopCommand
902909

0 commit comments

Comments
 (0)