From 91fde98739494964c35c69d0776019ba3fbbf079 Mon Sep 17 00:00:00 2001 From: Zomatree Date: Wed, 10 Nov 2021 16:55:24 +0000 Subject: [PATCH] add more advance converters --- revolt/ext/commands/command.py | 37 +++++++++++++++++++++---------- revolt/ext/commands/converters.py | 20 +++++++++++++++++ revolt/ext/commands/view.py | 10 +++++++++ 3 files changed, 55 insertions(+), 12 deletions(-) create mode 100755 revolt/ext/commands/converters.py diff --git a/revolt/ext/commands/command.py b/revolt/ext/commands/command.py index f7c4a5c..214727c 100755 --- a/revolt/ext/commands/command.py +++ b/revolt/ext/commands/command.py @@ -1,12 +1,12 @@ from __future__ import annotations import traceback -from typing import TYPE_CHECKING, Any, Callable, Coroutine, Optional +from typing import TYPE_CHECKING, Annotated, Any, Callable, Coroutine, Optional, Union, get_args, get_origin import revolt import inspect from contextlib import suppress -from revolt.utils import copy_doc +from revolt.utils import copy_doc, maybe_coroutine if TYPE_CHECKING: from .context import Context @@ -84,20 +84,33 @@ class Command: traceback.print_exception(type(error), error, error.__traceback__) @staticmethod - async def convert_argument(arg: str, parameter: inspect.Parameter, context: Context): + def extract_type(t): + if origin := get_origin(t): + if origin is Annotated: + return get_args(t)[1] + + return t + + @classmethod + async def convert_argument(cls, arg: str, parameter: inspect.Parameter, context: Context): if annot := parameter.annotation: - func = getattr(annot, "__convert__", None) + if annot is str: # no converting is needed - its already a string + return arg - if func: - output = func(context, arg) - else: - output = annot(arg) + if origin := get_origin(annot): + if origin is Union: + for converter in get_args(annot): - if inspect.isawaitable(output): - output = await output - - return output + try: + return await maybe_coroutine(converter, arg, context) + except: + if converter is None: + context.view.undo() + return None + elif origin is Annotated: + converter: Callable[[str, Context], Any] = get_args(annot)[1] # the typehint affects the other if statement somehow + return await maybe_coroutine(converter, arg, context) else: return arg diff --git a/revolt/ext/commands/converters.py b/revolt/ext/commands/converters.py new file mode 100755 index 0000000..10ec929 --- /dev/null +++ b/revolt/ext/commands/converters.py @@ -0,0 +1,20 @@ +from typing import Annotated + +class ConverterError(Exception): + """Raised when a converter fails""" + +class BadBoolArgument(ConverterError): + """Raised when the bool converter fails""" + +IntConverter = Annotated[int, lambda arg, _: int(arg)] + +def bool_converter(arg: str, _): + lowered = arg.lower() + if lowered in ["yes", "true", "ye", "y", "1", "on", "enable"]: + return True + elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'): + return False + else: + raise BadBoolArgument(lowered) + +BoolConverter = Annotated[bool, bool_converter] diff --git a/revolt/ext/commands/view.py b/revolt/ext/commands/view.py index 4893665..30fe0c2 100755 --- a/revolt/ext/commands/view.py +++ b/revolt/ext/commands/view.py @@ -4,6 +4,11 @@ from .errors import NoClosingQuote class StringView: def __init__(self, string: str): self.value = iter(string) + self.temp = "" + self.should_undo = False + + def undo(self): + self.should_undo = True def next_char(self) -> str: return next(self.value) @@ -12,6 +17,10 @@ class StringView: return "".join(self.value) def get_next_word(self) -> str: + if self.should_undo: + self.should_undo = False + return self.temp + char = self.next_char() temp = [] @@ -35,5 +44,6 @@ class StringView: pass output = "".join(temp) + self.temp = output return output