Browse Source

ext.commands: cog, core

pull/10189/head
Soheab_ 2 weeks ago
parent
commit
3ff66286cb
  1. 17
      discord/ext/commands/cog.py
  2. 75
      discord/ext/commands/core.py

17
discord/ext/commands/cog.py

@ -44,18 +44,29 @@ from typing import (
Tuple, Tuple,
TypeVar, TypeVar,
Union, Union,
TypedDict
) )
from ._types import _BaseCommand, BotT from ._types import _BaseCommand, BotT
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Self from typing_extensions import Self, Unpack, NotRequired
from discord.abc import Snowflake from discord.abc import Snowflake
from discord._types import ClientT from discord._types import ClientT
from .bot import BotBase from .bot import BotBase
from .context import Context from .context import Context
from .core import Command from .core import Command, _CommandDecoratorKwargs
class _CogKwargs(TypedDict):
name: NotRequired[Optional[str]]
group_name: NotRequired[Optional[Union[str, app_commands.locale_str]]]
description: NotRequired[Optional[str]]
group_description: NotRequired[Optional[Union[str, app_commands.locale_str]]]
group_nsfw: NotRequired[bool]
group_auto_locale_strings: NotRequired[bool]
group_extras: NotRequired[Dict[Any, Any]]
command_attrs: NotRequired[_CommandDecoratorKwargs]
__all__ = ( __all__ = (
'CogMeta', 'CogMeta',
@ -169,7 +180,7 @@ class CogMeta(type):
__cog_app_commands__: List[Union[app_commands.Group, app_commands.Command[Any, ..., Any]]] __cog_app_commands__: List[Union[app_commands.Group, app_commands.Command[Any, ..., Any]]]
__cog_listeners__: List[Tuple[str, str]] __cog_listeners__: List[Tuple[str, str]]
def __new__(cls, *args: Any, **kwargs: Any) -> CogMeta: def __new__(cls, *args: Any, **kwargs: Unpack[_CogKwargs]) -> CogMeta:
name, bases, attrs = args name, bases, attrs = args
if any(issubclass(base, app_commands.Group) for base in bases): if any(issubclass(base, app_commands.Group) for base in bases):
raise TypeError( raise TypeError(

75
discord/ext/commands/core.py

@ -43,6 +43,7 @@ from typing import (
TypeVar, TypeVar,
Union, Union,
overload, overload,
TypedDict,
) )
import re import re
@ -58,10 +59,37 @@ from .parameters import Parameter, Signature
from discord.app_commands.commands import NUMPY_DOCSTRING_ARG_REGEX from discord.app_commands.commands import NUMPY_DOCSTRING_ARG_REGEX
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import Concatenate, ParamSpec, Self from typing_extensions import Concatenate, ParamSpec, Self, NotRequired, Unpack
from ._types import BotT, Check, ContextT, Coro, CoroFunc, Error, Hook, UserCheck from ._types import BotT, Check, ContextT, Coro, CoroFunc, Error, Hook, UserCheck
class _CommandDecoratorKwargs(TypedDict):
enabled: NotRequired[bool]
help: NotRequired[str]
brief: NotRequired[str]
usage: NotRequired[str]
rest_is_raw: NotRequired[bool]
aliases: NotRequired[List[str]]
description: NotRequired[str]
hidden: NotRequired[bool]
checks: NotRequired[List[UserCheck[Context[Any]]]]
cooldown: NotRequired[CooldownMapping[Context[Any]]]
max_concurrency: NotRequired[MaxConcurrency]
require_var_positional: NotRequired[bool]
cooldown_after_parsing: NotRequired[bool]
ignore_extra: NotRequired[bool]
extras: NotRequired[Dict[Any, Any]]
class _CommandKwargs(_CommandDecoratorKwargs):
name: NotRequired[str]
class _GroupDecoratorKwargs(_CommandDecoratorKwargs):
invoke_without_command: NotRequired[bool]
case_insensitive: NotRequired[bool]
class _GroupKwargs(_GroupDecoratorKwargs):
name: NotRequired[str]
__all__ = ( __all__ = (
'Command', 'Command',
@ -368,9 +396,9 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
.. versionadded:: 2.0 .. versionadded:: 2.0
""" """
__original_kwargs__: Dict[str, Any] __original_kwargs__: _CommandKwargs
def __new__(cls, *args: Any, **kwargs: Any) -> Self: def __new__(cls, *args: Any, **kwargs: Unpack[_CommandKwargs]) -> Self:
# if you're wondering why this is done, it's because we need to ensure # if you're wondering why this is done, it's because we need to ensure
# we have a complete original copy of **kwargs even for classes that # we have a complete original copy of **kwargs even for classes that
# mess with it by popping before delegating to the subclass __init__. # mess with it by popping before delegating to the subclass __init__.
@ -393,11 +421,11 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
Callable[Concatenate[Context[Any], P], Coro[T]], Callable[Concatenate[Context[Any], P], Coro[T]],
], ],
/, /,
**kwargs: Any, **kwargs: Unpack[_CommandKwargs],
) -> None: ) -> None:
if not asyncio.iscoroutinefunction(func): if not asyncio.iscoroutinefunction(func):
raise TypeError('Callback must be a coroutine.') raise TypeError('Callback must be a coroutine.')
name = kwargs.get('name') or func.__name__ name = kwargs.get('name') or func.__name__
if not isinstance(name, str): if not isinstance(name, str):
raise TypeError('Name of a command must be a string.') raise TypeError('Name of a command must be a string.')
@ -453,7 +481,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
max_concurrency = kwargs.get('max_concurrency') max_concurrency = kwargs.get('max_concurrency')
self._max_concurrency: Optional[MaxConcurrency] = max_concurrency self._max_concurrency: Optional[MaxConcurrency] = max_concurrency
self.require_var_positional: bool = kwargs.get('require_var_positional', False) self.require_var_positional: bool = kwargs.get('require_var_positional', False)
self.ignore_extra: bool = kwargs.get('ignore_extra', True) self.ignore_extra: bool = kwargs.get('ignore_extra', True)
self.cooldown_after_parsing: bool = kwargs.get('cooldown_after_parsing', False) self.cooldown_after_parsing: bool = kwargs.get('cooldown_after_parsing', False)
@ -556,7 +584,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
except ValueError: except ValueError:
pass pass
def update(self, **kwargs: Any) -> None: def update(self, **kwargs: Unpack[_CommandKwargs]) -> None:
"""Updates :class:`Command` instance with updated attribute. """Updates :class:`Command` instance with updated attribute.
This works similarly to the :func:`~discord.ext.commands.command` decorator in terms This works similarly to the :func:`~discord.ext.commands.command` decorator in terms
@ -564,7 +592,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
subclass constructors, sans the name and callback. subclass constructors, sans the name and callback.
""" """
cog = self.cog cog = self.cog
self.__init__(self.callback, **dict(self.__original_kwargs__, **kwargs)) self.__init__(self.callback, **dict(self.__original_kwargs__, **kwargs)) # type: ignore # it's a typeddict
self.cog = cog self.cog = cog
async def __call__(self, context: Context[BotT], /, *args: P.args, **kwargs: P.kwargs) -> T: async def __call__(self, context: Context[BotT], /, *args: P.args, **kwargs: P.kwargs) -> T:
@ -1468,7 +1496,7 @@ class GroupMixin(Generic[CogT]):
self: GroupMixin[CogT], self: GroupMixin[CogT],
name: str = ..., name: str = ...,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_CommandDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1486,7 +1514,7 @@ class GroupMixin(Generic[CogT]):
name: str = ..., name: str = ...,
cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_CommandDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1503,7 +1531,7 @@ class GroupMixin(Generic[CogT]):
name: str = MISSING, name: str = MISSING,
cls: Type[Command[Any, ..., Any]] = MISSING, cls: Type[Command[Any, ..., Any]] = MISSING,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_CommandDecoratorKwargs],
) -> Any: ) -> Any:
"""A shortcut decorator that invokes :func:`~discord.ext.commands.command` and adds it to """A shortcut decorator that invokes :func:`~discord.ext.commands.command` and adds it to
the internal command list via :meth:`~.GroupMixin.add_command`. the internal command list via :meth:`~.GroupMixin.add_command`.
@ -1515,8 +1543,7 @@ class GroupMixin(Generic[CogT]):
""" """
def decorator(func): def decorator(func):
kwargs.setdefault('parent', self) # type: ignore # the parent kwarg is not for users to set.
kwargs.setdefault('parent', self)
result = command(name=name, cls=cls, *args, **kwargs)(func) result = command(name=name, cls=cls, *args, **kwargs)(func)
self.add_command(result) self.add_command(result)
return result return result
@ -1528,7 +1555,7 @@ class GroupMixin(Generic[CogT]):
self: GroupMixin[CogT], self: GroupMixin[CogT],
name: str = ..., name: str = ...,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_GroupDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1546,7 +1573,7 @@ class GroupMixin(Generic[CogT]):
name: str = ..., name: str = ...,
cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_GroupDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1563,7 +1590,7 @@ class GroupMixin(Generic[CogT]):
name: str = MISSING, name: str = MISSING,
cls: Type[Group[Any, ..., Any]] = MISSING, cls: Type[Group[Any, ..., Any]] = MISSING,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Unpack[_GroupDecoratorKwargs],
) -> Any: ) -> Any:
"""A shortcut decorator that invokes :func:`.group` and adds it to """A shortcut decorator that invokes :func:`.group` and adds it to
the internal command list via :meth:`~.GroupMixin.add_command`. the internal command list via :meth:`~.GroupMixin.add_command`.
@ -1575,7 +1602,7 @@ class GroupMixin(Generic[CogT]):
""" """
def decorator(func): def decorator(func):
kwargs.setdefault('parent', self) kwargs.setdefault('parent', self) # type: ignore # the parent kwarg is not for users to set.
result = group(name=name, cls=cls, *args, **kwargs)(func) result = group(name=name, cls=cls, *args, **kwargs)(func)
self.add_command(result) self.add_command(result)
return result return result
@ -1606,7 +1633,7 @@ class Group(GroupMixin[CogT], Command[CogT, P, T]):
Defaults to ``False``. Defaults to ``False``.
""" """
def __init__(self, *args: Any, **attrs: Any) -> None: def __init__(self, *args: Any, **attrs: Unpack[_GroupKwargs]) -> None:
self.invoke_without_command: bool = attrs.pop('invoke_without_command', False) self.invoke_without_command: bool = attrs.pop('invoke_without_command', False)
super().__init__(*args, **attrs) super().__init__(*args, **attrs)
@ -1728,7 +1755,7 @@ if TYPE_CHECKING:
@overload @overload
def command( def command(
name: str = ..., name: str = ...,
**attrs: Any, **attrs: Unpack[_CommandDecoratorKwargs],
) -> _CommandDecorator: ) -> _CommandDecorator:
... ...
@ -1737,7 +1764,7 @@ def command(
def command( def command(
name: str = ..., name: str = ...,
cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set
**attrs: Any, **attrs: Unpack[_CommandDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1753,7 +1780,7 @@ def command(
def command( def command(
name: str = MISSING, name: str = MISSING,
cls: Type[Command[Any, ..., Any]] = MISSING, cls: Type[Command[Any, ..., Any]] = MISSING,
**attrs: Any, **attrs: Unpack[_CommandDecoratorKwargs],
) -> Any: ) -> Any:
"""A decorator that transforms a function into a :class:`.Command` """A decorator that transforms a function into a :class:`.Command`
or if called with :func:`.group`, :class:`.Group`. or if called with :func:`.group`, :class:`.Group`.
@ -1798,7 +1825,7 @@ def command(
@overload @overload
def group( def group(
name: str = ..., name: str = ...,
**attrs: Any, **attrs: Unpack[_GroupDecoratorKwargs],
) -> _GroupDecorator: ) -> _GroupDecorator:
... ...
@ -1807,7 +1834,7 @@ def group(
def group( def group(
name: str = ..., name: str = ...,
cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set
**attrs: Any, **attrs: Unpack[_GroupDecoratorKwargs],
) -> Callable[ ) -> Callable[
[ [
Union[ Union[
@ -1823,7 +1850,7 @@ def group(
def group( def group(
name: str = MISSING, name: str = MISSING,
cls: Type[Group[Any, ..., Any]] = MISSING, cls: Type[Group[Any, ..., Any]] = MISSING,
**attrs: Any, **attrs: Unpack[_GroupDecoratorKwargs],
) -> Any: ) -> Any:
"""A decorator that transforms a function into a :class:`.Group`. """A decorator that transforms a function into a :class:`.Group`.

Loading…
Cancel
Save