mirror of
https://github.com/stoatchat/python-client-sdk.git
synced 2026-07-01 20:44:04 -04:00
add Literal converter and rejig command client
This commit is contained in:
@@ -6,3 +6,4 @@ dist
|
||||
docs/_build
|
||||
.vscode
|
||||
.env
|
||||
.mypy_cache
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,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__)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,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)]
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user