Skip to content

Instantly share code, notes, and snippets.

@leonhard-s
Created September 28, 2019 18:39
Show Gist options
  • Save leonhard-s/ece426c2315834f5e0b4af600181b25e to your computer and use it in GitHub Desktop.
Save leonhard-s/ece426c2315834f5e0b4af600181b25e to your computer and use it in GitHub Desktop.
Adds standardised attributes to BadArgument exceptions in discord.py
"""Adds standardised attributes to BadArgument exceptions in discord.py.
The default `BadArgument` exception does not have any extra arguments,
and the error messages generated are too different to easily convert
into user-facing error messages.
This extension fixes that by capturing any `BadArgument` exceptions
raised and re-raising them with three extra arguments:
* argument {str} -- The string that could not be converted
* annotation {Any} -- The object the argument was annotated with
* type_name {str} -- A formatted name of the target type
The `type_name` argument will generally return the name of the class.
If the class name ends in "Converter", this suffix is stripped off.
"""
import inspect
from typing import Any
from discord.ext import commands
async def _inject_argument_info(self, ctx: commands.Context,
converter: commands.Converter, argument: str,
param: inspect.Parameter) -> Any:
"""Add argument and converter info to `BadArgument` exceptions.
This method is a replacement for the original `_actual_conversion`
method of the `commands.Command` class. It forwards the call to the
original method, but injects any `commands.BadArgument` exceptions
raised with additional attributes to facilitate error message
generation.
"""
# NOTE: This method forwards the call to the original _actual_conversion
# method. Whenever a BadArgument exception is raised, it is injected with
# useful arguments before being re-raised.
# This should be more-or-less invisible to any other modules, aside from
# the additional call and the injected arguments.
try:
return await self._original_actual_conversion(ctx, converter,
argument, param)
except commands.BadArgument as err:
err.argument = argument
err.annotation = param.annotation
# Remove the "Converter"-suffix of object-specific converters. This
# turns "MemberConverter" into "Member", etc.
err.type_name = param.annotation.__name__.split('Converter')[:-1]
raise err
def setup(bot: commands.Bot) -> None:
"""Entry point for the bot extension loader."""
cmd_cls = commands.Command
# Store the original converter
cmd_cls._original_actual_conversion = cmd_cls._actual_conversion
# Add the BadArgument attribute injector
cmd_cls._actual_conversion = _inject_argument_info
def teardown(bot: commands.Bot) -> None:
"""Clean-up utility when unloading the extension."""
cmd_cls = commands.Command
# Restore the original converter
cmd_cls._actual_conversion = cmd_cls._original_actual_conversion
# Remove the backup
del cmd_cls._original_actual_conversion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment