[commands] Separate view parsing errors from BadArgument.
This causes them to be raised from a new exception named ArgumentParsingError with 3 children for ease with i18n. This is technically a breaking change since it no longer derives from BadArgument, though catching UserInputError will prevent this change from affecting the user.
This commit is contained in:
		| @@ -32,7 +32,9 @@ __all__ = ['CommandError', 'MissingRequiredArgument', 'BadArgument', | ||||
|            'DisabledCommand', 'CommandInvokeError', 'TooManyArguments', | ||||
|            'UserInputError', 'CommandOnCooldown', 'NotOwner', | ||||
|            'MissingPermissions', 'BotMissingPermissions', 'ConversionError', | ||||
|            'BadUnionArgument'] | ||||
|            'BadUnionArgument', 'ArgumentParsingError', | ||||
|            'UnexpectedQuoteError', 'InvalidEndOfQuotedStringError', | ||||
|            'ExpectedClosingQuoteError', ] | ||||
|  | ||||
| class CommandError(DiscordException): | ||||
|     r"""The base exception type for all command related errors. | ||||
| @@ -229,3 +231,55 @@ class BadUnionArgument(UserInputError): | ||||
|             fmt = ' or '.join(to_string) | ||||
|  | ||||
|         super().__init__('Could not convert "{0.name}" into {1}.'.format(param, fmt)) | ||||
|  | ||||
| class ArgumentParsingError(UserInputError): | ||||
|     """An exception raised when the parser fails to parse a user's input. | ||||
|  | ||||
|     This derives from :exc:`UserInputError`. There are child classes | ||||
|     that implement more granular parsing errors for i18n purposes. | ||||
|     """ | ||||
|     pass | ||||
|  | ||||
| class UnexpectedQuoteError(ArgumentParsingError): | ||||
|     """An exception raised when the parser encounters a quote mark inside a non-quoted string. | ||||
|  | ||||
|     This derives from :exc:`ArgumentParsingError`. | ||||
|  | ||||
|     Attributes | ||||
|     ------------ | ||||
|     quote: :class:`str` | ||||
|         The quote mark that was found inside the non-quoted string. | ||||
|     """ | ||||
|     def __init__(self, quote): | ||||
|         self.quote = quote | ||||
|         super().__init__('Unexpected quote mark, {0!r}, in non-quoted string'.format(quote)) | ||||
|  | ||||
| class InvalidEndOfQuotedStringError(ArgumentParsingError): | ||||
|     """An exception raised when a space is expected after the closing quote in a string | ||||
|     but a different character is found. | ||||
|  | ||||
|     This derives from :exc:`ArgumentParsingError`. | ||||
|  | ||||
|     Attributes | ||||
|     ----------- | ||||
|     char: :class:`str` | ||||
|         The character found instead of the expected string. | ||||
|     """ | ||||
|     def __init__(self, char): | ||||
|         self.char = char | ||||
|         super().__init__('Expected space after closing quotation but received {0!r}'.format(char)) | ||||
|  | ||||
| class ExpectedClosingQuoteError(ArgumentParsingError): | ||||
|     """An exception raised when a quote character is expected but not found. | ||||
|  | ||||
|     This derives from :exc:`ArgumentParsingError`. | ||||
|  | ||||
|     Attributes | ||||
|     ----------- | ||||
|     close_quote: :class:`str` | ||||
|         The quote character expected. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, close_quote): | ||||
|         self.close_quote = close_quote | ||||
|         super().__init__('Expected closing {}.'.format(close_quote)) | ||||
|   | ||||
| @@ -24,7 +24,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE. | ||||
| """ | ||||
|  | ||||
| from .errors import BadArgument | ||||
| from .errors import UnexpectedQuoteError, InvalidEndOfQuotedStringError, ExpectedClosingQuoteError | ||||
|  | ||||
| class StringView: | ||||
|     def __init__(self, buffer): | ||||
| @@ -151,7 +151,7 @@ def quoted_word(view): | ||||
|         if not current: | ||||
|             if is_quoted: | ||||
|                 # unexpected EOF | ||||
|                 raise BadArgument('Expected closing {}.'.format(close_quote)) | ||||
|                 raise ExpectedClosingQuoteError(close_quote) | ||||
|             return ''.join(result) | ||||
|  | ||||
|         # currently we accept strings in the format of "hello world" | ||||
| @@ -162,7 +162,7 @@ def quoted_word(view): | ||||
|                 # string ends with \ and no character after it | ||||
|                 if is_quoted: | ||||
|                     # if we're quoted then we're expecting a closing quote | ||||
|                     raise BadArgument('Expected closing {}.'.format(close_quote)) | ||||
|                     raise ExpectedClosingQuoteError(close_quote) | ||||
|                 # if we aren't then we just let it through | ||||
|                 return ''.join(result) | ||||
|  | ||||
| @@ -177,14 +177,14 @@ def quoted_word(view): | ||||
|  | ||||
|         if not is_quoted and current in _all_quotes: | ||||
|             # we aren't quoted | ||||
|             raise BadArgument('Unexpected quote mark in non-quoted string') | ||||
|             raise UnexpectedQuoteError(current) | ||||
|  | ||||
|         # closing quote | ||||
|         if is_quoted and current == close_quote: | ||||
|             next_char = view.get() | ||||
|             valid_eof = not next_char or next_char.isspace() | ||||
|             if not valid_eof: | ||||
|                 raise BadArgument('Expected space after closing quotation') | ||||
|                 raise InvalidEndOfQuotedStringError(next_char) | ||||
|  | ||||
|             # we're quoted so it's okay | ||||
|             return ''.join(result) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user