diff --git a/redbot/core/commands/commands.py b/redbot/core/commands/commands.py index 4f12d2577..bd20554be 100644 --- a/redbot/core/commands/commands.py +++ b/redbot/core/commands/commands.py @@ -397,6 +397,45 @@ class Command(CogCommandMixin, commands.Command): break 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): """Mixin for `Group` and `Red` classes. diff --git a/redbot/core/events.py b/redbot/core/events.py index 2ef362d66..f641c6d54 100644 --- a/redbot/core/events.py +++ b/redbot/core/events.py @@ -161,7 +161,15 @@ def init_events(bot, cli_flags): bot.color = discord.Colour(await bot.db.color()) @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): await ctx.send_help() elif isinstance(error, commands.ConversionFailure): @@ -189,8 +197,7 @@ def init_events(bot, cli_flags): traceback.format_exception(type(error), error, error.__traceback__) ) 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): fuzzy_commands = await fuzzy_command_search(ctx) if not fuzzy_commands: