diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py index 03c69167a..df82efe2e 100644 --- a/discord/ext/commands/core.py +++ b/discord/ext/commands/core.py @@ -212,7 +212,7 @@ class Command: self.instance = instance return self - async def do_conversion(self, ctx, converter, argument): + async def do_conversion(self, ctx, converter, argument, param): if converter is bool: return _convert_to_bool(argument) @@ -224,21 +224,36 @@ class Command: if module.startswith('discord.') and not module.endswith('converter'): converter = getattr(converters, converter.__name__ + 'Converter') - if inspect.isclass(converter): - if issubclass(converter, converters.Converter): - instance = converter() - ret = await instance.convert(ctx, argument) - return ret - else: - method = getattr(converter, 'convert', None) - if method is not None and inspect.ismethod(method): - ret = await method(ctx, argument) + try: + if inspect.isclass(converter): + if issubclass(converter, converters.Converter): + instance = converter() + ret = await instance.convert(ctx, argument) return ret - elif isinstance(converter, converters.Converter): - ret = await converter.convert(ctx, argument) - return ret + else: + method = getattr(converter, 'convert', None) + if method is not None and inspect.ismethod(method): + ret = await method(ctx, argument) + return ret + elif isinstance(converter, converters.Converter): + ret = await converter.convert(ctx, argument) + return ret + except CommandError as e: + raise e + except Exception as e: + raise ConversionError(converter) from e + + try: + return converter(argument) + except CommandError as e: + raise e + except Exception as e: + try: + name = converter.__name__ + except AttributeError: + name = converter.__class__.__name__ - return converter(argument) + raise BadArgument('Converting to "{}" failed for parameter "{}".'.format(name, param.name)) from e def _get_converter(self, param): converter = param.annotation @@ -268,17 +283,7 @@ class Command: else: argument = quoted_word(view) - try: - return (await self.do_conversion(ctx, converter, argument)) - except CommandError as e: - raise e - except Exception as e: - try: - name = converter.__name__ - except AttributeError: - name = converter.__class__.__name__ - - raise BadArgument('Converting to "{}" failed for parameter "{}".'.format(name, param.name)) from e + return (await self.do_conversion(ctx, converter, argument, param)) @property def clean_params(self): diff --git a/discord/ext/commands/errors.py b/discord/ext/commands/errors.py index 209073c2a..4b3c22930 100644 --- a/discord/ext/commands/errors.py +++ b/discord/ext/commands/errors.py @@ -30,7 +30,7 @@ __all__ = [ 'CommandError', 'MissingRequiredArgument', 'BadArgument', 'NoPrivateMessage', 'CheckFailure', 'CommandNotFound', 'DisabledCommand', 'CommandInvokeError', 'TooManyArguments', 'UserInputError', 'CommandOnCooldown', 'NotOwner', - 'MissingPermissions', 'BotMissingPermissions'] + 'MissingPermissions', 'BotMissingPermissions', 'ConversionError'] class CommandError(DiscordException): """The base exception type for all command related errors. @@ -49,6 +49,19 @@ class CommandError(DiscordException): else: super().__init__(*args) +class ConversionError(CommandError): + """Exception raised when a Converter class raises non-CommandError. + + Attributes + ---------- + converter: :class:`discord.ext.commands.Converter` + The converter that failed. + + This inherits from :exc:`.CommandError`. + """ + def __init__(self, converter): + self.converter = converter + class UserInputError(CommandError): """The base exception type for errors that involve errors regarding user input. diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst index 0f61be2f7..d983d1f1e 100644 --- a/docs/ext/commands/api.rst +++ b/docs/ext/commands/api.rst @@ -187,6 +187,9 @@ Errors .. autoexception:: discord.ext.commands.CommandError :members: +.. autoexception:: discord.ext.commands.ConversionError + :members: + .. autoexception:: discord.ext.commands.MissingRequiredArgument :members: