add Literal converter and rejig command client

This commit is contained in:
Zomatree
2021-11-13 23:53:21 +00:00
parent c874017a6b
commit e5d65b9400
9 changed files with 126 additions and 26 deletions
+1
View File
@@ -6,3 +6,4 @@ dist
docs/_build
.vscode
.env
.mypy_cache
+65 -4
View File
@@ -4,9 +4,9 @@ API Reference
===============
CommandsMixin
~~~~~~~~~~~~~
.. autoclass:: revolt.ext.commands.CommandsMixin
CommandsClient
~~~~~~~~~~~~~~~
.. autoclass:: revolt.ext.commands.CommandsClient
:members:
Context
@@ -19,11 +19,72 @@ Command
.. autoclass:: revolt.ext.commands.Command
:members:
command
~~~~~~~~
.. autodecorator:: revolt.ext.commands.command
check
~~~~~~
.. autodecorator:: revolt.ext.commands.check
is_bot_owner
~~~~~~~~~~~~~
.. autodecorator:: revolt.ext.commands.is_bot_owner
is_server_owner
~~~~~~~~~~~~~~~~
.. autodecorator:: revolt.ext.commands.is_server_owner
Exceptions
===========
CommandError
~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.CommandError
:members:
CommandNotFound
~~~~~~~~~~~~~~~~
.. autoclass:: revolt.ext.commands.CommandNotFound
.. autoexception:: revolt.ext.commands.CommandNotFound
:members:
NoClosingQuote
~~~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.NoClosingQuote
:members:
CheckError
~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.CheckError
:members:
NotBotOwner
~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.NotBotOwner
:members:
NotServerOwner
~~~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.NotServerOwner
:members:
ServerOnly
~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.ServerOnly
:members:
ConverterError
~~~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.ConverterError
:members:
InvalidLiteralArgument
~~~~~~~~~~~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.InvalidLiteralArgument
:members:
BadBoolArgument
~~~~~~~~~~~~~~~~
.. autoexception:: revolt.ext.commands.BadBoolArgument
:members:
+1 -1
View File
@@ -6,7 +6,7 @@ import revolt
from revolt.ext import commands
class Client(commands.CommandsMixin, revolt.Client):
class Client(commands.CommandsClient):
async def get_prefix(self, message: revolt.Message):
return "!"
+1 -1
View File
@@ -1,5 +1,5 @@
from .command import *
from .context import *
from .errors import *
from .mixin import *
from .client import *
from .checks import *
@@ -14,7 +14,7 @@ from .errors import CommandNotFound, CheckError
__all__ = (
"CommandsMeta",
"CommandsMixin"
"CommandsClient"
)
quote_regex = re.compile(r"[\"']")
@@ -40,11 +40,10 @@ class CommandsMeta(type):
return self
class CommandsMixin(metaclass=CommandsMeta):
class CommandsClient(revolt.Client, metaclass=CommandsMeta):
"""Main class that adds commands, this class should be subclassed along with `revolt.Client`."""
_commands: list[Command]
dispatch: Callable[..., None]
def __init__(self, *args, **kwargs):
self.all_commands: dict[str, Command] = {}
@@ -142,7 +141,7 @@ class CommandsMixin(metaclass=CommandsMeta):
if not content:
return
view = StringView(content)
view = self.get_view(message)(content)
try:
command_name = view.get_next_word()
@@ -154,10 +153,10 @@ class CommandsMixin(metaclass=CommandsMeta):
try:
command = self.get_command(command_name)
except KeyError:
context = context_cls(None, command_name, view, message)
context = context_cls(None, command_name, view, message, self)
return self.dispatch("command_error", context, CommandNotFound(command_name))
context = context_cls(command, command_name, view, message)
context = context_cls(command, command_name, view, message, self)
try:
self.dispatch("command", context)
@@ -175,7 +174,6 @@ class CommandsMixin(metaclass=CommandsMeta):
except Exception as e:
self.dispatch("command_error", context, e)
@staticmethod
async def on_command_error(ctx: Context, error: Exception):
traceback.print_exception(type(error), error, error.__traceback__)
+11 -1
View File
@@ -1,12 +1,13 @@
from __future__ import annotations
import traceback
from typing import TYPE_CHECKING, Annotated, Any, Callable, Coroutine, Optional, Union, get_args, get_origin
from typing import TYPE_CHECKING, Annotated, Any, Callable, Coroutine, Literal, Optional, Union, get_args, get_origin
import revolt
import inspect
from contextlib import suppress
from revolt.utils import copy_doc, maybe_coroutine
from .errors import InvalidLiteralArgument
if TYPE_CHECKING:
from .context import Context
@@ -111,6 +112,15 @@ class Command:
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)
elif origin is Literal:
if arg in get_args(annot):
return arg
else:
raise InvalidLiteralArgument(arg)
else:
annot: Callable[..., Any]
return await maybe_coroutine(annot, arg, context)
else:
return arg
+6 -2
View File
@@ -9,6 +9,7 @@ from .command import Command
if TYPE_CHECKING:
from .view import StringView
from .client import CommandsClient
__all__ = (
"Context",
@@ -35,17 +36,20 @@ class Context(revolt.Messageable):
The positional arguments being passed to the command
kwargs: dict[:class:`str`, Any]
The keyword arguments being passed to the command
client: :class:`CommandsClient`
The revolt client
"""
__slots__ = ("command", "invoked_with", "args", "message", "server", "channel", "author", "view", "kwargs", "state")
__slots__ = ("command", "invoked_with", "args", "message", "server", "channel", "author", "view", "kwargs", "state", "client")
def _get_channel_id(self) -> str:
return self.channel.id
def __init__(self, command: Optional[Command], invoked_with: str, view: StringView, message: revolt.Message):
def __init__(self, command: Optional[Command], invoked_with: str, view: StringView, message: revolt.Message, client: CommandsClient):
self.command = command
self.invoked_with = invoked_with
self.view = view
self.message = message
self.client = client
self.args = []
self.kwargs = {}
self.server = message.server
+1 -6
View File
@@ -1,10 +1,5 @@
from typing import Annotated
class ConverterError(Exception):
"""Raised when a converter fails"""
class BadBoolArgument(ConverterError):
"""Raised when the bool converter fails"""
from .errors import BadBoolArgument
IntConverter = Annotated[int, lambda arg, _: int(arg)]
+35 -4
View File
@@ -1,9 +1,22 @@
from revolt import RevoltError
__all__ = (
"CommandError",
"CommandNotFound",
"NoClosingQuote"
"NoClosingQuote",
"CheckError",
"NotBotOwner",
"NotServerOwner",
"ServerOnly",
"ConverterError",
"InvalidLiteralArgument",
"BadBoolArgument"
)
class CommandNotFound(Exception):
class CommandError(RevoltError):
"""base error for all command's related errors"""
class CommandNotFound(CommandError):
"""Raised when a command isnt found.
Parameters
@@ -16,8 +29,26 @@ class CommandNotFound(Exception):
def __init__(self, command_name: str):
self.command_name = command_name
class NoClosingQuote(Exception):
class NoClosingQuote(CommandError):
"""Raised when there is no closing quote for a command argument"""
class CheckError(Exception):
class CheckError(CommandError):
"""Raised when a check fails for a command"""
class NotBotOwner(CheckError):
"""Raised when the `is_bot_owner` check fails"""
class NotServerOwner(CheckError):
"""Raised when the `is_server_owner` check fails"""
class ServerOnly(CheckError):
"""Raised when a check requires the command to be ran in a server"""
class ConverterError(CommandError):
"""Base class for all converter errors"""
class InvalidLiteralArgument(ConverterError):
"""Raised when the argument is not a valid literal argument"""
class BadBoolArgument(ConverterError):
"""Raised when the bool converter fails"""