Make on_command_error recognise custom error handlers (#2458)

Adds detection of custom error handlers to the global error handler.

Adds documentation of the updated behaviour.

Closes #2276.
This commit is contained in:
DiscordLiz 2019-02-22 04:12:00 -05:00 committed by Toby Harradine
parent cf18b601e2
commit c70a44e0fe
2 changed files with 49 additions and 3 deletions

View File

@ -397,6 +397,45 @@ class Command(CogCommandMixin, commands.Command):
break break
return old_rule, new_rule return old_rule, new_rule
async def error(self, coro):
"""
A decorator that registers a coroutine as a local error handler.
A local error handler is an :func:`.on_command_error` event limited to
a single command.
The on_command_error event is still dispatched
for commands with a dedicated error handler.
Red's global error handler will ignore commands with a registered error handler.
To have red handle specific errors with the default behavior,
call ``Red.on_command_error`` with ``unhandled_by_cog`` set to True.
For example:
.. code-block:: python
@a_command.error
async def a_command_error_handler(self, ctx, error):
if isisntance(error, MyErrrorType):
self.log_exception(error)
else:
await ctx.bot.on_command_error(ctx, error, unhandled_by_cog=True)
Parameters
-----------
coro : :term:`coroutine function`
The coroutine to register as the local error handler.
Raises
-------
discord.ClientException
The coroutine is not actually a coroutine.
"""
return await super().error(coro)
class GroupMixin(discord.ext.commands.GroupMixin): class GroupMixin(discord.ext.commands.GroupMixin):
"""Mixin for `Group` and `Red` classes. """Mixin for `Group` and `Red` classes.

View File

@ -161,7 +161,15 @@ def init_events(bot, cli_flags):
bot.color = discord.Colour(await bot.db.color()) bot.color = discord.Colour(await bot.db.color())
@bot.event @bot.event
async def on_command_error(ctx, error): async def on_command_error(ctx, error, unhandled_by_cog=False):
if not unhandled_by_cog:
if hasattr(ctx.command, "on_error"):
return
if ctx.cog and hasattr(ctx.cog, f"_{ctx.cog.__class__.__name__}__error"):
return
if isinstance(error, commands.MissingRequiredArgument): if isinstance(error, commands.MissingRequiredArgument):
await ctx.send_help() await ctx.send_help()
elif isinstance(error, commands.ConversionFailure): elif isinstance(error, commands.ConversionFailure):
@ -189,8 +197,7 @@ def init_events(bot, cli_flags):
traceback.format_exception(type(error), error, error.__traceback__) traceback.format_exception(type(error), error, error.__traceback__)
) )
bot._last_exception = exception_log bot._last_exception = exception_log
if not hasattr(ctx.cog, "_{0.command.cog_name}__error".format(ctx)): await ctx.send(inline(message))
await ctx.send(inline(message))
elif isinstance(error, commands.CommandNotFound): elif isinstance(error, commands.CommandNotFound):
fuzzy_commands = await fuzzy_command_search(ctx) fuzzy_commands = await fuzzy_command_search(ctx)
if not fuzzy_commands: if not fuzzy_commands: