diff --git a/revolt/ext/commands/checks.py b/revolt/ext/commands/checks.py index 3c58976..b834cc8 100755 --- a/revolt/ext/commands/checks.py +++ b/revolt/ext/commands/checks.py @@ -9,15 +9,15 @@ from .command import Command from .context import Context from .errors import (MissingPermissionsError, NotBotOwner, NotServerOwner, ServerOnly) -from .utils import ClientT +from .utils import ClientT_D __all__ = ("check", "Check", "is_bot_owner", "is_server_owner", "has_permissions", "has_channel_permissions") T = TypeVar("T", Callable[..., Any], Command, default=Command) -Check = Callable[[Context[ClientT]], Union[Any, Coroutine[Any, Any, Any]]] +Check = Callable[[Context[ClientT_D]], Union[Any, Coroutine[Any, Any, Any]]] -def check(check: Check[ClientT]) -> Callable[[T], T]: +def check(check: Check[ClientT_D]) -> Callable[[T], T]: """A decorator for adding command checks Parameters @@ -27,7 +27,7 @@ def check(check: Check[ClientT]) -> Callable[[T], T]: """ def inner(func: T) -> T: if isinstance(func, Command): - command = cast(Command[ClientT], func) # cant verify generic at runtime so must cast + command = cast(Command[ClientT_D], func) # cant verify generic at runtime so must cast command.checks.append(check) else: checks = getattr(func, "_checks", []) @@ -41,7 +41,7 @@ def check(check: Check[ClientT]) -> Callable[[T], T]: def is_bot_owner() -> Callable[[T], T]: """A command check for limiting the command to only the bot's owner""" @check - def inner(context: Context[ClientT]): + def inner(context: Context[ClientT_D]): if user_id := context.client.user.owner_id: if context.author.id == user_id: return True @@ -56,7 +56,7 @@ def is_bot_owner() -> Callable[[T], T]: def is_server_owner() -> Callable[[T], T]: """A command check for limiting the command to only a server's owner""" @check - def inner(context: Context[ClientT]) -> bool: + def inner(context: Context[ClientT_D]) -> bool: if not context.server_id: raise ServerOnly @@ -69,7 +69,7 @@ def is_server_owner() -> Callable[[T], T]: def has_permissions(**permissions: bool) -> Callable[[T], T]: @check - def inner(context: Context[ClientT]) -> bool: + def inner(context: Context[ClientT_D]) -> bool: author = context.author if not author.has_permissions(**permissions): @@ -81,7 +81,7 @@ def has_permissions(**permissions: bool) -> Callable[[T], T]: def has_channel_permissions(**permissions: bool) -> Callable[[T], T]: @check - def inner(context: Context[ClientT]) -> bool: + def inner(context: Context[ClientT_D]) -> bool: author = context.author if not isinstance(author, revolt.Member): diff --git a/revolt/ext/commands/cog.py b/revolt/ext/commands/cog.py index 5a58533..781f924 100755 --- a/revolt/ext/commands/cog.py +++ b/revolt/ext/commands/cog.py @@ -4,30 +4,34 @@ from typing import Any, Generic, Optional, cast from typing_extensions import Self from .command import Command -from .utils import ClientT +from .utils import ClientT_D __all__ = ("Cog", "CogMeta") -class CogMeta(type, Generic[ClientT]): - _commands: list[Command[ClientT]] +class CogMeta(type, Generic[ClientT_D]): + _commands: list[Command[ClientT_D]] qualified_name: str - def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any], *, qualified_name: Optional[str] = None) -> Self: - commands: list[Command[ClientT]] = [] + def __new__(cls, name: str, bases: tuple[type, ...], attrs: dict[str, Any], *, qualified_name: Optional[str] = None, extras: dict[str, Any] | None = None) -> Self: + commands: list[Command[ClientT_D]] = [] self = super().__new__(cls, name, bases, attrs) + extras = extras or {} for base in reversed(self.__mro__): for value in base.__dict__.values(): if isinstance(value, Command): - commands.append(cast(Command[ClientT], value)) # cant verify generic at runtime so must cast + for key, value in extras.items(): + setattr(value, key, value) + + commands.append(cast(Command[ClientT_D], value)) # cant verify generic at runtime so must cast self._commands = commands self.qualified_name = qualified_name or name return self -class Cog(Generic[ClientT], metaclass=CogMeta): - _commands: list[Command[ClientT]] +class Cog(Generic[ClientT_D], metaclass=CogMeta): + _commands: list[Command[ClientT_D]] qualified_name: str def cog_load(self) -> None: @@ -38,7 +42,7 @@ class Cog(Generic[ClientT], metaclass=CogMeta): """A special method that is called when the cog gets removed.""" pass - def _inject(self, client: ClientT) -> None: + def _inject(self, client: ClientT_D) -> None: client.cogs[self.qualified_name] = self for command in self._commands: @@ -49,7 +53,7 @@ class Cog(Generic[ClientT], metaclass=CogMeta): self.cog_load() - def _uninject(self, client: ClientT) -> None: + def _uninject(self, client: ClientT_D) -> None: for name, command in client.all_commands.copy().items(): if command in self._commands: del client.all_commands[name] @@ -57,5 +61,5 @@ class Cog(Generic[ClientT], metaclass=CogMeta): self.cog_unload() @property - def commands(self) -> list[Command[ClientT]]: + def commands(self) -> list[Command[ClientT_D]]: return self._commands diff --git a/revolt/ext/commands/command.py b/revolt/ext/commands/command.py index 47c7049..8a4d6ff 100755 --- a/revolt/ext/commands/command.py +++ b/revolt/ext/commands/command.py @@ -10,7 +10,7 @@ from typing_extensions import ParamSpec from revolt.utils import maybe_coroutine from .errors import InvalidLiteralArgument, UnionConverterError -from .utils import ClientCoT, evaluate_parameters +from .utils import ClientT_Co_D, evaluate_parameters, ClientT_Co if TYPE_CHECKING: from .checks import Check @@ -26,7 +26,7 @@ __all__: tuple[str, ...] = ( NoneType: type[None] = type(None) P = ParamSpec("P") -class Command(Generic[ClientCoT]): +class Command(Generic[ClientT_Co_D]): """Class for holding info about a command. Parameters @@ -43,8 +43,14 @@ class Command(Generic[ClientCoT]): The cog the command is apart of. usage: Optional[:class:`str`] The usage string for the command + checks: list[Callable] + The list of checks the command has + description: Optional[:class:`str`] + The commands description if it has one + hidden: :class:`bool` + Whether or not the command should be hidden from the help command """ - __slots__ = ("callback", "name", "aliases", "signature", "checks", "parent", "_error_handler", "cog", "description", "usage", "parameters") + __slots__ = ("callback", "name", "aliases", "signature", "checks", "parent", "_error_handler", "cog", "description", "usage", "parameters", "hidden") def __init__(self, callback: Callable[..., Coroutine[Any, Any, Any]], name: str, aliases: list[str], usage: Optional[str] = None): self.callback: Callable[..., Coroutine[Any, Any, Any]] = callback @@ -53,13 +59,14 @@ class Command(Generic[ClientCoT]): self.usage: str | None = usage self.signature: inspect.Signature = inspect.signature(self.callback) self.parameters: list[inspect.Parameter] = evaluate_parameters(self.signature.parameters.values(), getattr(callback, "__globals__", {})) - self.checks: list[Check[ClientCoT]] = getattr(callback, "_checks", []) - self.parent: Optional[Group[ClientCoT]] = None - self.cog: Optional[Cog[ClientCoT]] = None - self._error_handler: Callable[[Any, Context[ClientCoT], Exception], Coroutine[Any, Any, Any]] = type(self)._default_error_handler + self.checks: list[Check[ClientT_Co_D]] = getattr(callback, "_checks", []) + self.parent: Optional[Group[ClientT_Co_D]] = None + self.cog: Optional[Cog[ClientT_Co_D]] = None + self._error_handler: Callable[[Any, Context[ClientT_Co_D], Exception], Coroutine[Any, Any, Any]] = type(self)._default_error_handler self.description: str | None = callback.__doc__ + self.hidden: bool = False - async def invoke(self, context: Context[ClientCoT], *args: Any, **kwargs: Any) -> Any: + async def invoke(self, context: Context[ClientT_Co_D], *args: Any, **kwargs: Any) -> Any: """Runs the command and calls the error handler if the command errors. Parameters @@ -74,7 +81,7 @@ class Command(Generic[ClientCoT]): except Exception as err: return await self._error_handler(self.cog or context.client, context, err) - def __call__(self, context: Context[ClientCoT], *args: Any, **kwargs: Any) -> Any: + def __call__(self, context: Context[ClientT_Co_D], *args: Any, **kwargs: Any) -> Any: return self.invoke(context, *args, **kwargs) def error(self, func: Callable[..., Coroutine[Any, Any, Any]]) -> Callable[..., Coroutine[Any, Any, Any]]: @@ -97,11 +104,11 @@ class Command(Generic[ClientCoT]): self._error_handler = func return func - async def _default_error_handler(self, ctx: Context[ClientCoT], error: Exception): + async def _default_error_handler(self, ctx: Context[ClientT_Co_D], error: Exception): traceback.print_exception(type(error), error, error.__traceback__) @classmethod - async def handle_origin(cls, context: Context[ClientCoT], origin: Any, annotation: Any, arg: str) -> Any: + async def handle_origin(cls, context: Context[ClientT_Co_D], origin: Any, annotation: Any, arg: str) -> Any: if origin is Union: for converter in get_args(annotation): try: @@ -128,7 +135,7 @@ class Command(Generic[ClientCoT]): raise InvalidLiteralArgument(arg) @classmethod - async def convert_argument(cls, arg: str, annotation: Any, context: Context[ClientCoT]) -> Any: + async def convert_argument(cls, arg: str, annotation: Any, context: Context[ClientT_Co_D]) -> Any: if annotation is not inspect.Signature.empty: if annotation is str: # no converting is needed - its already a string return arg @@ -141,7 +148,7 @@ class Command(Generic[ClientCoT]): else: return arg - async def parse_arguments(self, context: Context[ClientCoT]) -> None: + async def parse_arguments(self, context: Context[ClientT_Co_D]) -> None: # please pr if you can think of a better way to do this for parameter in self.parameters[2:]: @@ -214,7 +221,13 @@ class Command(Generic[ClientCoT]): return f"{' '.join(parents[::-1])} {self.name} {' '.join(parameters)}" -def command(*, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: type[Command[ClientCoT]] = Command, usage: Optional[str] = None) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Command[ClientCoT]]: +def command( + *, + name: Optional[str] = None, + aliases: Optional[list[str]] = None, + cls: type[Command[ClientT_Co]] = Command, + usage: Optional[str] = None +) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Command[ClientT_Co]]: """A decorator that turns a function into a :class:`Command`.n Parameters @@ -231,7 +244,7 @@ def command(*, name: Optional[str] = None, aliases: Optional[list[str]] = None, Callable[Callable[..., Coroutine], :class:`Command`] A function that takes the command callback and returns a :class:`Command` """ - def inner(func: Callable[..., Coroutine[Any, Any, Any]]): + def inner(func: Callable[..., Coroutine[Any, Any, Any]]) -> Command[ClientT_Co]: return cls(func, name or func.__name__, aliases or [], usage) return inner diff --git a/revolt/ext/commands/context.py b/revolt/ext/commands/context.py index c32fb5b..8ee1bc9 100755 --- a/revolt/ext/commands/context.py +++ b/revolt/ext/commands/context.py @@ -7,7 +7,7 @@ from revolt.utils import maybe_coroutine from .command import Command from .group import Group -from .utils import ClientCoT +from .utils import ClientT_Co_D if TYPE_CHECKING: from .view import StringView @@ -17,7 +17,7 @@ __all__ = ( "Context", ) -class Context(revolt.Messageable, Generic[ClientCoT]): +class Context(revolt.Messageable, Generic[ClientT_Co_D]): """Stores metadata the commands execution. Attributes @@ -46,12 +46,12 @@ class Context(revolt.Messageable, Generic[ClientCoT]): async def _get_channel_id(self) -> str: return self.channel.id - def __init__(self, command: Optional[Command[ClientCoT]], invoked_with: str, view: StringView, message: revolt.Message, client: ClientCoT): - self.command: Command[ClientCoT] | None = command + def __init__(self, command: Optional[Command[ClientT_Co_D]], invoked_with: str, view: StringView, message: revolt.Message, client: ClientT_Co_D): + self.command: Command[ClientT_Co_D] | None = command self.invoked_with: str = invoked_with self.view: StringView = view self.message: revolt.Message = message - self.client: ClientCoT = client + self.client: ClientT_Co_D = client self.args: list[Any] = [] self.kwargs: dict[str, Any] = {} self.server_id: str | None = message.server_id @@ -100,13 +100,13 @@ class Context(revolt.Messageable, Generic[ClientCoT]): await command.parse_arguments(self) return await command.invoke(self, *self.args, **self.kwargs) - async def can_run(self, command: Optional[Command[ClientCoT]] = None) -> bool: + async def can_run(self, command: Optional[Command[ClientT_Co_D]] = None) -> bool: """Runs all of the commands checks, and returns true if all of them pass""" command = command or self.command return all([await maybe_coroutine(check, self) for check in (command.checks if command else [])]) - async def send_help(self, argument: Command[Any] | Group[Any] | ClientCoT | None = None) -> None: + async def send_help(self, argument: Command[Any] | Group[Any] | ClientT_Co_D | None = None) -> None: argument = argument or self.client command = self.client.get_command("help") diff --git a/revolt/ext/commands/group.py b/revolt/ext/commands/group.py index ba7a22b..35e7f4e 100755 --- a/revolt/ext/commands/group.py +++ b/revolt/ext/commands/group.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Any, Callable, Coroutine, Optional from .command import Command -from .utils import ClientCoT, ClientT +from .utils import ClientT_Co_D, ClientT_D __all__ = ( @@ -11,7 +11,7 @@ __all__ = ( "group" ) -class Group(Command[ClientCoT]): +class Group(Command[ClientT_Co_D]): """Class for holding info about a group command. Parameters @@ -29,10 +29,10 @@ class Group(Command[ClientCoT]): __slots__: tuple[str, ...] = ("subcommands",) def __init__(self, callback: Callable[..., Coroutine[Any, Any, Any]], name: str, aliases: list[str]): - self.subcommands: dict[str, Command[ClientCoT]] = {} + self.subcommands: dict[str, Command[ClientT_Co_D]] = {} super().__init__(callback, name, aliases) - def command(self, *, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: type[Command[ClientCoT]] = Command[ClientCoT]) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Command[ClientCoT]]: + def command(self, *, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: type[Command[ClientT_Co_D]] = Command[ClientT_Co_D]) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Command[ClientT_Co_D]]: """A decorator that turns a function into a :class:`Command` and registers the command as a subcommand. Parameters @@ -61,7 +61,7 @@ class Group(Command[ClientCoT]): return inner - def group(self, *, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: Optional[type[Group[ClientCoT]]] = None) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Group[ClientCoT]]: + def group(self, *, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: Optional[type[Group[ClientT_Co_D]]] = None) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Group[ClientT_Co_D]]: """A decorator that turns a function into a :class:`Group` and registers the command as a subcommand Parameters @@ -96,7 +96,7 @@ class Group(Command[ClientCoT]): return f"" @property - def commands(self) -> list[Command[ClientCoT]]: + def commands(self) -> list[Command[ClientT_Co_D]]: """Gets all commands registered Returns @@ -106,7 +106,7 @@ class Group(Command[ClientCoT]): """ return list(set(self.subcommands.values())) - def get_command(self, name: str) -> Command[ClientCoT]: + def get_command(self, name: str) -> Command[ClientT_Co_D]: """Gets a command. Parameters @@ -121,7 +121,7 @@ class Group(Command[ClientCoT]): """ return self.subcommands[name] - def add_command(self, command: Command[ClientCoT]) -> None: + def add_command(self, command: Command[ClientT_Co_D]) -> None: """Adds a command, this is typically only used for dynamic commands, you should use the `commands.command` decorator for most usecases. Parameters @@ -136,7 +136,7 @@ class Group(Command[ClientCoT]): for alias in command.aliases: self.subcommands[alias] = command - def remove_command(self, name: str) -> Optional[Command[ClientCoT]]: + def remove_command(self, name: str) -> Optional[Command[ClientT_Co_D]]: """Removes a command. Parameters @@ -157,7 +157,7 @@ class Group(Command[ClientCoT]): return command -def group(*, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: type[Group[ClientT]] = Group) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Group[ClientT]]: +def group(*, name: Optional[str] = None, aliases: Optional[list[str]] = None, cls: type[Group[ClientT_D]] = Group) -> Callable[[Callable[..., Coroutine[Any, Any, Any]]], Group[ClientT_D]]: """A decorator that turns a function into a :class:`Group` Parameters diff --git a/revolt/ext/commands/help.py b/revolt/ext/commands/help.py index 5d64111..8e36ebe 100755 --- a/revolt/ext/commands/help.py +++ b/revolt/ext/commands/help.py @@ -9,7 +9,7 @@ from .cog import Cog from .command import Command from .context import Context from .group import Group -from .utils import ClientCoT, ClientT +from .utils import ClientT_Co_D, ClientT_D from revolt import File, Message, Messageable, MessageReply, SendableEmbed @@ -26,30 +26,33 @@ class MessagePayload(TypedDict): attachments: NotRequired[list[File]] replies: NotRequired[list[MessageReply]] -class HelpCommand(ABC, Generic[ClientCoT]): +class HelpCommand(ABC, Generic[ClientT_Co_D]): @abstractmethod - async def create_global_help(self, context: Context[ClientCoT], commands: dict[Optional[Cog[ClientCoT]], list[Command[ClientCoT]]]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_global_help(self, context: Context[ClientT_Co_D], commands: dict[Optional[Cog[ClientT_Co_D]], list[Command[ClientT_Co_D]]]) -> Union[str, SendableEmbed, MessagePayload]: raise NotImplementedError @abstractmethod - async def create_command_help(self, context: Context[ClientCoT], command: Command[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_command_help(self, context: Context[ClientT_Co_D], command: Command[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: raise NotImplementedError @abstractmethod - async def create_group_help(self, context: Context[ClientCoT], group: Group[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_group_help(self, context: Context[ClientT_Co_D], group: Group[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: raise NotImplementedError @abstractmethod - async def create_cog_help(self, context: Context[ClientCoT], cog: Cog[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_cog_help(self, context: Context[ClientT_Co_D], cog: Cog[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: raise NotImplementedError - async def send_help_command(self, context: Context[ClientCoT], message_payload: MessagePayload) -> Message: + async def send_help_command(self, context: Context[ClientT_Co_D], message_payload: MessagePayload) -> Message: return await context.send(**message_payload) - async def filter_commands(self, context: Context[ClientCoT], commands: list[Command[ClientCoT]]) -> list[Command[ClientCoT]]: - filtered: list[Command[ClientCoT]] = [] + async def filter_commands(self, context: Context[ClientT_Co_D], commands: list[Command[ClientT_Co_D]]) -> list[Command[ClientT_Co_D]]: + filtered: list[Command[ClientT_Co_D]] = [] for command in commands: + if command.hidden: + continue + try: if await context.can_run(command): filtered.append(command) @@ -58,29 +61,29 @@ class HelpCommand(ABC, Generic[ClientCoT]): return filtered - async def group_commands(self, context: Context[ClientCoT], commands: list[Command[ClientCoT]]) -> dict[Optional[Cog[ClientCoT]], list[Command[ClientCoT]]]: - cogs: dict[Optional[Cog[ClientCoT]], list[Command[ClientCoT]]] = {} + async def group_commands(self, context: Context[ClientT_Co_D], commands: list[Command[ClientT_Co_D]]) -> dict[Optional[Cog[ClientT_Co_D]], list[Command[ClientT_Co_D]]]: + cogs: dict[Optional[Cog[ClientT_Co_D]], list[Command[ClientT_Co_D]]] = {} for command in commands: cogs.setdefault(command.cog, []).append(command) return cogs - async def handle_message(self, context: Context[ClientCoT], message: Message) -> None: + async def handle_message(self, context: Context[ClientT_Co_D], message: Message) -> None: pass async def get_channel(self, context: Context) -> Messageable: return context @abstractmethod - async def handle_no_command_found(self, context: Context[ClientCoT], name: str) -> Union[str, SendableEmbed, MessagePayload]: + async def handle_no_command_found(self, context: Context[ClientT_Co_D], name: str) -> Union[str, SendableEmbed, MessagePayload]: raise NotImplementedError -class DefaultHelpCommand(HelpCommand[ClientCoT]): +class DefaultHelpCommand(HelpCommand[ClientT_Co_D]): def __init__(self, default_cog_name: str = "No Cog"): self.default_cog_name = default_cog_name - async def create_global_help(self, context: Context[ClientCoT], commands: dict[Optional[Cog[ClientCoT]], list[Command[ClientCoT]]]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_global_help(self, context: Context[ClientT_Co_D], commands: dict[Optional[Cog[ClientT_Co_D]], list[Command[ClientT_Co_D]]]) -> Union[str, SendableEmbed, MessagePayload]: lines = ["```"] for cog, cog_commands in commands.items(): @@ -95,7 +98,7 @@ class DefaultHelpCommand(HelpCommand[ClientCoT]): lines.append("```") return "\n".join(lines) - async def create_cog_help(self, context: Context[ClientCoT], cog: Cog[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_cog_help(self, context: Context[ClientT_Co_D], cog: Cog[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: lines = ["```"] lines.append(f"{cog.qualified_name}:") @@ -106,7 +109,7 @@ class DefaultHelpCommand(HelpCommand[ClientCoT]): lines.append("```") return "\n".join(lines) - async def create_command_help(self, context: Context[ClientCoT], command: Command[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_command_help(self, context: Context[ClientT_Co_D], command: Command[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: lines = ["```"] lines.append(f"{command.name}:") @@ -122,7 +125,7 @@ class DefaultHelpCommand(HelpCommand[ClientCoT]): lines.append("```") return "\n".join(lines) - async def create_group_help(self, context: Context[ClientCoT], group: Group[ClientCoT]) -> Union[str, SendableEmbed, MessagePayload]: + async def create_group_help(self, context: Context[ClientT_Co_D], group: Group[ClientT_Co_D]) -> Union[str, SendableEmbed, MessagePayload]: lines = ["```"] lines.append(f"{group.name}:") @@ -140,21 +143,21 @@ class DefaultHelpCommand(HelpCommand[ClientCoT]): lines.append("```") return "\n".join(lines) - async def handle_no_command_found(self, context: Context[ClientCoT], name: str) -> str: + async def handle_no_command_found(self, context: Context[ClientT_Co_D], name: str) -> str: return f"Command `{name}` not found." -class HelpCommandImpl(Command[ClientCoT]): - def __init__(self, client: ClientCoT): +class HelpCommandImpl(Command[ClientT_Co_D]): + def __init__(self, client: ClientT_Co_D): self.client = client - async def callback(_: Union[ClientCoT, Cog[ClientCoT]], context: Context[ClientCoT], *args: str) -> None: + async def callback(_: Union[ClientT_Co_D, Cog[ClientT_Co_D]], context: Context[ClientT_Co_D], *args: str) -> None: await help_command_impl(context.client, context, *args) super().__init__(callback=callback, name="help", aliases=[]) self.description: str | None = "Shows help for a command, cog or the entire bot" -async def help_command_impl(client: ClientT, context: Context[ClientT], *arguments: str) -> None: +async def help_command_impl(client: ClientT_D, context: Context[ClientT_D], *arguments: str) -> None: help_command = client.help_command if not help_command: @@ -167,7 +170,7 @@ async def help_command_impl(client: ClientT, context: Context[ClientT], *argumen payload = await help_command.create_global_help(context, commands) else: - parent: ClientT | Group[ClientT] = client + parent: ClientT_D | Group[ClientT_D] = client for param in arguments: try: @@ -183,7 +186,7 @@ async def help_command_impl(client: ClientT, context: Context[ClientT], *argumen break if isinstance(command, Group): - command = cast(Group[ClientT], command) + command = cast(Group[ClientT_D], command) parent = command else: payload = await help_command.create_command_help(context, command) @@ -191,7 +194,7 @@ async def help_command_impl(client: ClientT, context: Context[ClientT], *argumen else: if TYPE_CHECKING: - command = cast(Command[ClientT], ...) + command = cast(Command[ClientT_D], ...) if isinstance(command, Group): payload = await help_command.create_group_help(context, command) diff --git a/revolt/ext/commands/utils.py b/revolt/ext/commands/utils.py index c3bb67b..1d940c7 100755 --- a/revolt/ext/commands/utils.py +++ b/revolt/ext/commands/utils.py @@ -12,9 +12,10 @@ if TYPE_CHECKING: __all__ = ("evaluate_parameters",) -ClientT = TypeVar("ClientT", bound="CommandsClient", default="CommandsClient") -ClientCoT = TypeVar("ClientCoT", bound="CommandsClient", default="CommandsClient", covariant=True) -ContextT = TypeVar("ContextT", bound="Context") +ClientT_Co = TypeVar("ClientT_Co", bound="CommandsClient", covariant=True) +ClientT_D = TypeVar("ClientT_D", bound="CommandsClient", default="CommandsClient") +ClientT_Co_D = TypeVar("ClientT_Co_D", bound="CommandsClient", default="CommandsClient", covariant=True) +ContextT = TypeVar("ContextT", bound="Context", default="Context") def evaluate_parameters(parameters: Iterable[Parameter], globals: dict[str, Any]) -> list[Parameter]: new_parameters: list[Parameter] = []