Skip to content

Commit 7e7b3ce

Browse files
committed
register all error handlers in the CommandErrorManager class
The purpose is to register the handlers in one place, which will allow us to delegate the choosing of the right handler & handling to the manager
1 parent 6553f03 commit 7e7b3ce

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from .abc import AbstractCommandErrorHandler
2+
from .manager import CommandErrorManager
23

3-
__all__ = ["AbstractCommandErrorHandler"]
4+
__all__ = ["AbstractCommandErrorHandler", "CommandErrorManager"]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from collections.abc import Callable
2+
from typing import NoReturn
3+
4+
from discord import Interaction
5+
from discord.ext.commands import Context
6+
7+
from pydis_core.utils.error_handling.commands import AbstractCommandErrorHandler
8+
from pydis_core.utils.logging import get_logger
9+
10+
log = get_logger(__name__)
11+
12+
13+
class CommandErrorManager:
14+
"""A class that registers error handlers and handles all command related errors."""
15+
16+
def __init__(self, default: AbstractCommandErrorHandler):
17+
self._handlers = []
18+
self._registered_handlers = set()
19+
self._default = default
20+
21+
async def handle_error(
22+
self,
23+
error: Exception,
24+
context_or_interaction: Context | Interaction
25+
) -> None:
26+
"""
27+
Handle a Discord exception.
28+
29+
Iterate through available handlers by registration order, and choose the first one capable of handling
30+
the error as determined by `should_handle_error`; there is no priority system.
31+
"""
32+
for handler in self._handlers + [self._default]:
33+
if await handler.should_handle_error(error):
34+
callback = self._get_callback(handler, context_or_interaction)
35+
await callback(context_or_interaction, error)
36+
break
37+
38+
def register_handler(self, handler: AbstractCommandErrorHandler) -> None:
39+
"""Register a command error handler."""
40+
handler_name = type(handler).__name__
41+
if handler_name in self._registered_handlers:
42+
log.info(f"Skipping registration of command error handler {handler_name!r} as it's already registered.")
43+
return
44+
45+
self._handlers.append(handler)
46+
self._registered_handlers.add(handler_name)
47+
48+
@staticmethod
49+
def _get_callback(
50+
handler: AbstractCommandErrorHandler,
51+
context_or_interaction: Context | Interaction
52+
) -> Callable[[Context, Exception], NoReturn] | Callable[[Interaction, Exception], NoReturn] | None:
53+
"""Get the handling callback that will be used."""
54+
if isinstance(context_or_interaction, Context):
55+
return handler.handle_text_command_error
56+
if isinstance(context_or_interaction, Interaction):
57+
return handler.handle_app_command_error
58+
raise ValueError(f"Expected Context or Interaction, got {type(context_or_interaction).__name__}")

0 commit comments

Comments
 (0)