mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-09-07 18:33:02 +00:00
Reformat code using black
Segments where readability was hampered were fixed by appropriate format skipping directives. New code should hopefully be black compatible. The moment they remove the -S option is probably the moment I stop using black though.
This commit is contained in:
@ -39,7 +39,9 @@ CoroFunc = Callable[..., Coro[Any]]
|
||||
|
||||
Check = Union[Callable[["Cog", "Context[Any]"], MaybeCoro[bool]], Callable[["Context[Any]"], MaybeCoro[bool]]]
|
||||
Hook = Union[Callable[["Cog", "Context[Any]"], Coro[Any]], Callable[["Context[Any]"], Coro[Any]]]
|
||||
Error = Union[Callable[["Cog", "Context[Any]", "CommandError"], Coro[Any]], Callable[["Context[Any]", "CommandError"], Coro[Any]]]
|
||||
Error = Union[
|
||||
Callable[["Cog", "Context[Any]", "CommandError"], Coro[Any]], Callable[["Context[Any]", "CommandError"], Coro[Any]]
|
||||
]
|
||||
|
||||
|
||||
# This is merely a tag type to avoid circular import issues.
|
||||
|
@ -66,6 +66,7 @@ T = TypeVar('T')
|
||||
CFT = TypeVar('CFT', bound='CoroFunc')
|
||||
CXT = TypeVar('CXT', bound='Context')
|
||||
|
||||
|
||||
def when_mentioned(bot: Union[Bot, AutoShardedBot], msg: Message) -> List[str]:
|
||||
"""A callable that implements a command prefix equivalent to being mentioned.
|
||||
|
||||
@ -74,6 +75,7 @@ def when_mentioned(bot: Union[Bot, AutoShardedBot], msg: Message) -> List[str]:
|
||||
# bot.user will never be None when this is called
|
||||
return [f'<@{bot.user.id}> ', f'<@!{bot.user.id}> '] # type: ignore
|
||||
|
||||
|
||||
def when_mentioned_or(*prefixes: str) -> Callable[[Union[Bot, AutoShardedBot], Message], List[str]]:
|
||||
"""A callable that implements when mentioned or other prefixes provided.
|
||||
|
||||
@ -103,6 +105,7 @@ def when_mentioned_or(*prefixes: str) -> Callable[[Union[Bot, AutoShardedBot], M
|
||||
----------
|
||||
:func:`.when_mentioned`
|
||||
"""
|
||||
|
||||
def inner(bot, msg):
|
||||
r = list(prefixes)
|
||||
r = when_mentioned(bot, msg) + r
|
||||
@ -110,15 +113,19 @@ def when_mentioned_or(*prefixes: str) -> Callable[[Union[Bot, AutoShardedBot], M
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
def _is_submodule(parent: str, child: str) -> bool:
|
||||
return parent == child or child.startswith(parent + ".")
|
||||
|
||||
|
||||
class _DefaultRepr:
|
||||
def __repr__(self):
|
||||
return '<default-help-command>'
|
||||
|
||||
|
||||
_default = _DefaultRepr()
|
||||
|
||||
|
||||
class BotBase(GroupMixin):
|
||||
def __init__(self, command_prefix, help_command=_default, description=None, **options):
|
||||
super().__init__(**options)
|
||||
@ -833,11 +840,13 @@ class BotBase(GroupMixin):
|
||||
raise errors.ExtensionNotLoaded(name)
|
||||
|
||||
# get the previous module states from sys modules
|
||||
# fmt: off
|
||||
modules = {
|
||||
name: module
|
||||
for name, module in sys.modules.items()
|
||||
if _is_submodule(lib.__name__, name)
|
||||
}
|
||||
# fmt: on
|
||||
|
||||
try:
|
||||
# Unload and then load the module...
|
||||
@ -913,8 +922,10 @@ class BotBase(GroupMixin):
|
||||
if isinstance(ret, collections.abc.Iterable):
|
||||
raise
|
||||
|
||||
raise TypeError("command_prefix must be plain string, iterable of strings, or callable "
|
||||
f"returning either of these, not {ret.__class__.__name__}")
|
||||
raise TypeError(
|
||||
"command_prefix must be plain string, iterable of strings, or callable "
|
||||
f"returning either of these, not {ret.__class__.__name__}"
|
||||
)
|
||||
|
||||
if not ret:
|
||||
raise ValueError("Iterable command_prefix must contain at least one prefix")
|
||||
@ -974,14 +985,17 @@ class BotBase(GroupMixin):
|
||||
|
||||
except TypeError:
|
||||
if not isinstance(prefix, list):
|
||||
raise TypeError("get_prefix must return either a string or a list of string, "
|
||||
f"not {prefix.__class__.__name__}")
|
||||
raise TypeError(
|
||||
"get_prefix must return either a string or a list of string, " f"not {prefix.__class__.__name__}"
|
||||
)
|
||||
|
||||
# It's possible a bad command_prefix got us here.
|
||||
for value in prefix:
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("Iterable command_prefix or list returned from get_prefix must "
|
||||
f"contain only strings, not {value.__class__.__name__}")
|
||||
raise TypeError(
|
||||
"Iterable command_prefix or list returned from get_prefix must "
|
||||
f"contain only strings, not {value.__class__.__name__}"
|
||||
)
|
||||
|
||||
# Getting here shouldn't happen
|
||||
raise
|
||||
@ -1053,6 +1067,7 @@ class BotBase(GroupMixin):
|
||||
async def on_message(self, message):
|
||||
await self.process_commands(message)
|
||||
|
||||
|
||||
class Bot(BotBase, discord.Client):
|
||||
"""Represents a discord bot.
|
||||
|
||||
@ -1123,10 +1138,13 @@ class Bot(BotBase, discord.Client):
|
||||
|
||||
.. versionadded:: 1.7
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class AutoShardedBot(BotBase, discord.AutoShardedClient):
|
||||
"""This is similar to :class:`.Bot` except that it is inherited from
|
||||
:class:`discord.AutoShardedClient` instead.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
@ -45,6 +45,7 @@ FuncT = TypeVar('FuncT', bound=Callable[..., Any])
|
||||
|
||||
MISSING: Any = discord.utils.MISSING
|
||||
|
||||
|
||||
class CogMeta(type):
|
||||
"""A metaclass for defining a cog.
|
||||
|
||||
@ -104,6 +105,7 @@ class CogMeta(type):
|
||||
async def bar(self, ctx):
|
||||
pass # hidden -> False
|
||||
"""
|
||||
|
||||
__cog_name__: str
|
||||
__cog_settings__: Dict[str, Any]
|
||||
__cog_commands__: List[Command]
|
||||
@ -150,7 +152,7 @@ class CogMeta(type):
|
||||
raise TypeError(no_bot_cog.format(base, elem))
|
||||
listeners[elem] = value
|
||||
|
||||
new_cls.__cog_commands__ = list(commands.values()) # this will be copied in Cog.__new__
|
||||
new_cls.__cog_commands__ = list(commands.values()) # this will be copied in Cog.__new__
|
||||
|
||||
listeners_as_list = []
|
||||
for listener in listeners.values():
|
||||
@ -169,10 +171,12 @@ class CogMeta(type):
|
||||
def qualified_name(cls) -> str:
|
||||
return cls.__cog_name__
|
||||
|
||||
|
||||
def _cog_special_method(func: FuncT) -> FuncT:
|
||||
func.__cog_special_method__ = None
|
||||
return func
|
||||
|
||||
|
||||
class Cog(metaclass=CogMeta):
|
||||
"""The base class that all cogs must inherit from.
|
||||
|
||||
@ -183,6 +187,7 @@ class Cog(metaclass=CogMeta):
|
||||
When inheriting from this class, the options shown in :class:`CogMeta`
|
||||
are equally valid here.
|
||||
"""
|
||||
|
||||
__cog_name__: ClassVar[str]
|
||||
__cog_settings__: ClassVar[Dict[str, Any]]
|
||||
__cog_commands__: ClassVar[List[Command]]
|
||||
@ -199,10 +204,7 @@ class Cog(metaclass=CogMeta):
|
||||
# r.e type ignore, type-checker complains about overriding a ClassVar
|
||||
self.__cog_commands__ = tuple(c._update_copy(cmd_attrs) for c in cls.__cog_commands__) # type: ignore
|
||||
|
||||
lookup = {
|
||||
cmd.qualified_name: cmd
|
||||
for cmd in self.__cog_commands__
|
||||
}
|
||||
lookup = {cmd.qualified_name: cmd for cmd in self.__cog_commands__}
|
||||
|
||||
# Update the Command instances dynamically as well
|
||||
for command in self.__cog_commands__:
|
||||
@ -255,6 +257,7 @@ class Cog(metaclass=CogMeta):
|
||||
A command or group from the cog.
|
||||
"""
|
||||
from .core import GroupMixin
|
||||
|
||||
for command in self.__cog_commands__:
|
||||
if command.parent is None:
|
||||
yield command
|
||||
@ -315,6 +318,7 @@ class Cog(metaclass=CogMeta):
|
||||
# to pick it up but the metaclass unfurls the function and
|
||||
# thus the assignments need to be on the actual function
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
def has_error_handler(self) -> bool:
|
||||
|
@ -49,9 +49,11 @@ if TYPE_CHECKING:
|
||||
from .help import HelpCommand
|
||||
from .view import StringView
|
||||
|
||||
# fmt: off
|
||||
__all__ = (
|
||||
'Context',
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
MISSING: Any = discord.utils.MISSING
|
||||
|
||||
@ -122,7 +124,8 @@ class Context(discord.abc.Messageable, Generic[BotT]):
|
||||
or invoked.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
message: Message,
|
||||
bot: BotT,
|
||||
@ -237,7 +240,7 @@ class Context(discord.abc.Messageable, Generic[BotT]):
|
||||
view.index = len(self.prefix or '')
|
||||
view.previous = 0
|
||||
self.invoked_parents = []
|
||||
self.invoked_with = view.get_word() # advance to get the root command
|
||||
self.invoked_with = view.get_word() # advance to get the root command
|
||||
else:
|
||||
to_call = cmd
|
||||
|
||||
|
@ -48,14 +48,15 @@ __all__ = (
|
||||
C = TypeVar('C', bound='CooldownMapping')
|
||||
MC = TypeVar('MC', bound='MaxConcurrency')
|
||||
|
||||
|
||||
class BucketType(Enum):
|
||||
default = 0
|
||||
user = 1
|
||||
guild = 2
|
||||
channel = 3
|
||||
member = 4
|
||||
default = 0
|
||||
user = 1
|
||||
guild = 2
|
||||
channel = 3
|
||||
member = 4
|
||||
category = 5
|
||||
role = 6
|
||||
role = 6
|
||||
|
||||
def get_key(self, msg: Message) -> Any:
|
||||
if self is BucketType.user:
|
||||
@ -192,6 +193,7 @@ class Cooldown:
|
||||
def __repr__(self) -> str:
|
||||
return f'<Cooldown rate: {self.rate} per: {self.per} window: {self._window} tokens: {self._tokens}>'
|
||||
|
||||
|
||||
class CooldownMapping:
|
||||
def __init__(
|
||||
self,
|
||||
@ -256,12 +258,12 @@ class CooldownMapping:
|
||||
bucket = self.get_bucket(message, current)
|
||||
return bucket.update_rate_limit(current)
|
||||
|
||||
class DynamicCooldownMapping(CooldownMapping):
|
||||
|
||||
class DynamicCooldownMapping(CooldownMapping):
|
||||
def __init__(
|
||||
self,
|
||||
factory: Callable[[Message], Cooldown],
|
||||
type: Callable[[Message], Any]
|
||||
type: Callable[[Message], Any],
|
||||
) -> None:
|
||||
super().__init__(None, type)
|
||||
self._factory: Callable[[Message], Cooldown] = factory
|
||||
@ -278,6 +280,7 @@ class DynamicCooldownMapping(CooldownMapping):
|
||||
def create_bucket(self, message: Message) -> Cooldown:
|
||||
return self._factory(message)
|
||||
|
||||
|
||||
class _Semaphore:
|
||||
"""This class is a version of a semaphore.
|
||||
|
||||
@ -337,6 +340,7 @@ class _Semaphore:
|
||||
self.value += 1
|
||||
self.wake_up()
|
||||
|
||||
|
||||
class MaxConcurrency:
|
||||
__slots__ = ('number', 'per', 'wait', '_mapping')
|
||||
|
||||
|
@ -93,7 +93,7 @@ __all__ = (
|
||||
'is_owner',
|
||||
'is_nsfw',
|
||||
'has_guild_permissions',
|
||||
'bot_has_guild_permissions'
|
||||
'bot_has_guild_permissions',
|
||||
)
|
||||
|
||||
MISSING: Any = discord.utils.MISSING
|
||||
@ -112,6 +112,7 @@ if TYPE_CHECKING:
|
||||
else:
|
||||
P = TypeVar('P')
|
||||
|
||||
|
||||
def unwrap_function(function: Callable[..., Any]) -> Callable[..., Any]:
|
||||
partial = functools.partial
|
||||
while True:
|
||||
@ -158,8 +159,10 @@ def wrap_callback(coro):
|
||||
except Exception as exc:
|
||||
raise CommandInvokeError(exc) from exc
|
||||
return ret
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
def hooked_wrapped_callback(command, ctx, coro):
|
||||
@functools.wraps(coro)
|
||||
async def wrapped(*args, **kwargs):
|
||||
@ -180,6 +183,7 @@ def hooked_wrapped_callback(command, ctx, coro):
|
||||
|
||||
await command.call_after_hooks(ctx)
|
||||
return ret
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
@ -202,6 +206,7 @@ class _CaseInsensitiveDict(dict):
|
||||
def __setitem__(self, k, v):
|
||||
super().__setitem__(k.casefold(), v)
|
||||
|
||||
|
||||
class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
r"""A class that implements the protocol for a bot text command.
|
||||
|
||||
@ -269,8 +274,8 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
which calls converters. If ``False`` then cooldown processing is done
|
||||
first and then the converters are called second. Defaults to ``False``.
|
||||
extras: :class:`dict`
|
||||
A dict of user provided extras to attach to the Command.
|
||||
|
||||
A dict of user provided extras to attach to the Command.
|
||||
|
||||
.. note::
|
||||
This object may be copied by the library.
|
||||
|
||||
@ -295,10 +300,14 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
self.__original_kwargs__ = kwargs.copy()
|
||||
return self
|
||||
|
||||
def __init__(self, func: Union[
|
||||
def __init__(
|
||||
self,
|
||||
func: Union[
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
Callable[Concatenate[ContextT, P], Coro[T]],
|
||||
], **kwargs: Any):
|
||||
],
|
||||
**kwargs: Any,
|
||||
):
|
||||
if not asyncio.iscoroutinefunction(func):
|
||||
raise TypeError('Callback must be a coroutine.')
|
||||
|
||||
@ -344,7 +353,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
cooldown = func.__commands_cooldown__
|
||||
except AttributeError:
|
||||
cooldown = kwargs.get('cooldown')
|
||||
|
||||
|
||||
if cooldown is None:
|
||||
buckets = CooldownMapping(cooldown, BucketType.default)
|
||||
elif isinstance(cooldown, CooldownMapping):
|
||||
@ -386,17 +395,19 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
self.after_invoke(after_invoke)
|
||||
|
||||
@property
|
||||
def callback(self) -> Union[
|
||||
Callable[Concatenate[CogT, Context, P], Coro[T]],
|
||||
Callable[Concatenate[Context, P], Coro[T]],
|
||||
]:
|
||||
def callback(
|
||||
self,
|
||||
) -> Union[Callable[Concatenate[CogT, Context, P], Coro[T]], Callable[Concatenate[Context, P], Coro[T]],]:
|
||||
return self._callback
|
||||
|
||||
@callback.setter
|
||||
def callback(self, function: Union[
|
||||
def callback(
|
||||
self,
|
||||
function: Union[
|
||||
Callable[Concatenate[CogT, Context, P], Coro[T]],
|
||||
Callable[Concatenate[Context, P], Coro[T]],
|
||||
]) -> None:
|
||||
],
|
||||
) -> None:
|
||||
self._callback = function
|
||||
unwrap = unwrap_function(function)
|
||||
self.module = unwrap.__module__
|
||||
@ -561,7 +572,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
|
||||
if view.eof:
|
||||
if param.kind == param.VAR_POSITIONAL:
|
||||
raise RuntimeError() # break the loop
|
||||
raise RuntimeError() # break the loop
|
||||
if required:
|
||||
if self._is_typing_optional(param.annotation):
|
||||
return None
|
||||
@ -616,7 +627,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
value = await run_converters(ctx, converter, argument, param) # type: ignore
|
||||
except (CommandError, ArgumentParsingError):
|
||||
view.index = previous
|
||||
raise RuntimeError() from None # break loop
|
||||
raise RuntimeError() from None # break loop
|
||||
else:
|
||||
return value
|
||||
|
||||
@ -653,9 +664,9 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
entries = []
|
||||
command = self
|
||||
# command.parent is type-hinted as GroupMixin some attributes are resolved via MRO
|
||||
while command.parent is not None: # type: ignore
|
||||
command = command.parent # type: ignore
|
||||
entries.append(command.name) # type: ignore
|
||||
while command.parent is not None: # type: ignore
|
||||
command = command.parent # type: ignore
|
||||
entries.append(command.name) # type: ignore
|
||||
|
||||
return ' '.join(reversed(entries))
|
||||
|
||||
@ -671,8 +682,8 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
"""
|
||||
entries = []
|
||||
command = self
|
||||
while command.parent is not None: # type: ignore
|
||||
command = command.parent # type: ignore
|
||||
while command.parent is not None: # type: ignore
|
||||
command = command.parent # type: ignore
|
||||
entries.append(command)
|
||||
|
||||
return entries
|
||||
@ -1061,8 +1072,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
# do [name] since [name=None] or [name=] are not exactly useful for the user.
|
||||
should_print = param.default if isinstance(param.default, str) else param.default is not None
|
||||
if should_print:
|
||||
result.append(f'[{name}={param.default}]' if not greedy else
|
||||
f'[{name}={param.default}]...')
|
||||
result.append(f'[{name}={param.default}]' if not greedy else f'[{name}={param.default}]...')
|
||||
continue
|
||||
else:
|
||||
result.append(f'[{name}]')
|
||||
@ -1135,6 +1145,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
|
||||
finally:
|
||||
ctx.command = original
|
||||
|
||||
|
||||
class GroupMixin(Generic[CogT]):
|
||||
"""A mixin that implements common functionality for classes that behave
|
||||
similar to :class:`.Group` and are allowed to register commands.
|
||||
@ -1147,6 +1158,7 @@ class GroupMixin(Generic[CogT]):
|
||||
case_insensitive: :class:`bool`
|
||||
Whether the commands should be case insensitive. Defaults to ``False``.
|
||||
"""
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
case_insensitive = kwargs.get('case_insensitive', False)
|
||||
self.all_commands: Dict[str, Command[CogT, Any, Any]] = _CaseInsensitiveDict() if case_insensitive else {}
|
||||
@ -1320,7 +1332,9 @@ class GroupMixin(Generic[CogT]):
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
Callable[Concatenate[ContextT, P], Coro[T]],
|
||||
]
|
||||
], Command[CogT, P, T]]:
|
||||
],
|
||||
Command[CogT, P, T],
|
||||
]:
|
||||
...
|
||||
|
||||
@overload
|
||||
@ -1348,6 +1362,7 @@ class GroupMixin(Generic[CogT]):
|
||||
Callable[..., :class:`Command`]
|
||||
A decorator that converts the provided method into a Command, adds it to the bot, then returns it.
|
||||
"""
|
||||
|
||||
def decorator(func: Callable[Concatenate[ContextT, P], Coro[Any]]) -> CommandT:
|
||||
kwargs.setdefault('parent', self)
|
||||
result = command(name=name, cls=cls, *args, **kwargs)(func)
|
||||
@ -1363,12 +1378,10 @@ class GroupMixin(Generic[CogT]):
|
||||
cls: Type[Group[CogT, P, T]] = ...,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Callable[[
|
||||
Union[
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
Callable[Concatenate[ContextT, P], Coro[T]]
|
||||
]
|
||||
], Group[CogT, P, T]]:
|
||||
) -> Callable[
|
||||
[Union[Callable[Concatenate[CogT, ContextT, P], Coro[T]], Callable[Concatenate[ContextT, P], Coro[T]]]],
|
||||
Group[CogT, P, T],
|
||||
]:
|
||||
...
|
||||
|
||||
@overload
|
||||
@ -1396,6 +1409,7 @@ class GroupMixin(Generic[CogT]):
|
||||
Callable[..., :class:`Group`]
|
||||
A decorator that converts the provided method into a Group, adds it to the bot, then returns it.
|
||||
"""
|
||||
|
||||
def decorator(func: Callable[Concatenate[ContextT, P], Coro[Any]]) -> GroupT:
|
||||
kwargs.setdefault('parent', self)
|
||||
result = group(name=name, cls=cls, *args, **kwargs)(func)
|
||||
@ -1404,6 +1418,7 @@ class GroupMixin(Generic[CogT]):
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
class Group(GroupMixin[CogT], Command[CogT, P, T]):
|
||||
"""A class that implements a grouping protocol for commands to be
|
||||
executed as subcommands.
|
||||
@ -1426,6 +1441,7 @@ class Group(GroupMixin[CogT], Command[CogT, P, T]):
|
||||
Indicates if the group's commands should be case insensitive.
|
||||
Defaults to ``False``.
|
||||
"""
|
||||
|
||||
def __init__(self, *args: Any, **attrs: Any) -> None:
|
||||
self.invoke_without_command: bool = attrs.pop('invoke_without_command', False)
|
||||
super().__init__(*args, **attrs)
|
||||
@ -1514,8 +1530,10 @@ class Group(GroupMixin[CogT], Command[CogT, P, T]):
|
||||
view.previous = previous
|
||||
await super().reinvoke(ctx, call_hooks=call_hooks)
|
||||
|
||||
|
||||
# Decorators
|
||||
|
||||
|
||||
@overload
|
||||
def command(
|
||||
name: str = ...,
|
||||
@ -1527,10 +1545,12 @@ def command(
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
Callable[Concatenate[ContextT, P], Coro[T]],
|
||||
]
|
||||
]
|
||||
, Command[CogT, P, T]]:
|
||||
],
|
||||
Command[CogT, P, T],
|
||||
]:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def command(
|
||||
name: str = ...,
|
||||
@ -1542,22 +1562,25 @@ def command(
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[Any]],
|
||||
Callable[Concatenate[ContextT, P], Coro[Any]],
|
||||
]
|
||||
]
|
||||
, CommandT]:
|
||||
],
|
||||
CommandT,
|
||||
]:
|
||||
...
|
||||
|
||||
|
||||
def command(
|
||||
name: str = MISSING,
|
||||
cls: Type[CommandT] = MISSING,
|
||||
**attrs: Any
|
||||
**attrs: Any,
|
||||
) -> Callable[
|
||||
[
|
||||
Union[
|
||||
Callable[Concatenate[ContextT, P], Coro[Any]],
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
]
|
||||
]
|
||||
, Union[Command[CogT, P, T], CommandT]]:
|
||||
],
|
||||
Union[Command[CogT, P, T], CommandT],
|
||||
]:
|
||||
"""A decorator that transforms a function into a :class:`.Command`
|
||||
or if called with :func:`.group`, :class:`.Group`.
|
||||
|
||||
@ -1590,16 +1613,19 @@ def command(
|
||||
if cls is MISSING:
|
||||
cls = Command # type: ignore
|
||||
|
||||
def decorator(func: Union[
|
||||
def decorator(
|
||||
func: Union[
|
||||
Callable[Concatenate[ContextT, P], Coro[Any]],
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[Any]],
|
||||
]) -> CommandT:
|
||||
]
|
||||
) -> CommandT:
|
||||
if isinstance(func, Command):
|
||||
raise TypeError('Callback is already a command.')
|
||||
return cls(func, name=name, **attrs)
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@overload
|
||||
def group(
|
||||
name: str = ...,
|
||||
@ -1611,10 +1637,12 @@ def group(
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
Callable[Concatenate[ContextT, P], Coro[T]],
|
||||
]
|
||||
]
|
||||
, Group[CogT, P, T]]:
|
||||
],
|
||||
Group[CogT, P, T],
|
||||
]:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def group(
|
||||
name: str = ...,
|
||||
@ -1626,10 +1654,12 @@ def group(
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[Any]],
|
||||
Callable[Concatenate[ContextT, P], Coro[Any]],
|
||||
]
|
||||
]
|
||||
, GroupT]:
|
||||
],
|
||||
GroupT,
|
||||
]:
|
||||
...
|
||||
|
||||
|
||||
def group(
|
||||
name: str = MISSING,
|
||||
cls: Type[GroupT] = MISSING,
|
||||
@ -1640,8 +1670,9 @@ def group(
|
||||
Callable[Concatenate[ContextT, P], Coro[Any]],
|
||||
Callable[Concatenate[CogT, ContextT, P], Coro[T]],
|
||||
]
|
||||
]
|
||||
, Union[Group[CogT, P, T], GroupT]]:
|
||||
],
|
||||
Union[Group[CogT, P, T], GroupT],
|
||||
]:
|
||||
"""A decorator that transforms a function into a :class:`.Group`.
|
||||
|
||||
This is similar to the :func:`.command` decorator but the ``cls``
|
||||
@ -1654,6 +1685,7 @@ def group(
|
||||
cls = Group # type: ignore
|
||||
return command(name=name, cls=cls, **attrs) # type: ignore
|
||||
|
||||
|
||||
def check(predicate: Check) -> Callable[[T], T]:
|
||||
r"""A decorator that adds a check to the :class:`.Command` or its
|
||||
subclasses. These checks could be accessed via :attr:`.Command.checks`.
|
||||
@ -1739,13 +1771,16 @@ def check(predicate: Check) -> Callable[[T], T]:
|
||||
if inspect.iscoroutinefunction(predicate):
|
||||
decorator.predicate = predicate
|
||||
else:
|
||||
|
||||
@functools.wraps(predicate)
|
||||
async def wrapper(ctx):
|
||||
return predicate(ctx) # type: ignore
|
||||
|
||||
decorator.predicate = wrapper
|
||||
|
||||
return decorator # type: ignore
|
||||
|
||||
|
||||
def check_any(*checks: Check) -> Callable[[T], T]:
|
||||
r"""A :func:`check` that is added that checks if any of the checks passed
|
||||
will pass, i.e. using logical OR.
|
||||
@ -1814,6 +1849,7 @@ def check_any(*checks: Check) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def has_role(item: Union[int, str]) -> Callable[[T], T]:
|
||||
"""A :func:`.check` that is added that checks if the member invoking the
|
||||
command has the role specified via the name or ID specified.
|
||||
@ -1856,6 +1892,7 @@ def has_role(item: Union[int, str]) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def has_any_role(*items: Union[int, str]) -> Callable[[T], T]:
|
||||
r"""A :func:`.check` that is added that checks if the member invoking the
|
||||
command has **any** of the roles specified. This means that if they have
|
||||
@ -1887,6 +1924,7 @@ def has_any_role(*items: Union[int, str]) -> Callable[[T], T]:
|
||||
async def cool(ctx):
|
||||
await ctx.send('You are cool indeed')
|
||||
"""
|
||||
|
||||
def predicate(ctx):
|
||||
if ctx.guild is None:
|
||||
raise NoPrivateMessage()
|
||||
@ -1899,6 +1937,7 @@ def has_any_role(*items: Union[int, str]) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def bot_has_role(item: int) -> Callable[[T], T]:
|
||||
"""Similar to :func:`.has_role` except checks if the bot itself has the
|
||||
role.
|
||||
@ -1925,8 +1964,10 @@ def bot_has_role(item: int) -> Callable[[T], T]:
|
||||
if role is None:
|
||||
raise BotMissingRole(item)
|
||||
return True
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def bot_has_any_role(*items: int) -> Callable[[T], T]:
|
||||
"""Similar to :func:`.has_any_role` except checks if the bot itself has
|
||||
any of the roles listed.
|
||||
@ -1940,6 +1981,7 @@ def bot_has_any_role(*items: int) -> Callable[[T], T]:
|
||||
Raise :exc:`.BotMissingAnyRole` or :exc:`.NoPrivateMessage`
|
||||
instead of generic checkfailure
|
||||
"""
|
||||
|
||||
def predicate(ctx):
|
||||
if ctx.guild is None:
|
||||
raise NoPrivateMessage()
|
||||
@ -1949,8 +1991,10 @@ def bot_has_any_role(*items: int) -> Callable[[T], T]:
|
||||
if any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items):
|
||||
return True
|
||||
raise BotMissingAnyRole(list(items))
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def has_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
"""A :func:`.check` that is added that checks if the member has all of
|
||||
the permissions necessary.
|
||||
@ -1998,6 +2042,7 @@ def has_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def bot_has_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
"""Similar to :func:`.has_permissions` except checks if the bot itself has
|
||||
the permissions listed.
|
||||
@ -2024,6 +2069,7 @@ def bot_has_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def has_guild_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
"""Similar to :func:`.has_permissions`, but operates on guild wide
|
||||
permissions instead of the current channel permissions.
|
||||
@ -2052,6 +2098,7 @@ def has_guild_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def bot_has_guild_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
"""Similar to :func:`.has_guild_permissions`, but checks the bot
|
||||
members guild permissions.
|
||||
@ -2077,6 +2124,7 @@ def bot_has_guild_permissions(**perms: bool) -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def dm_only() -> Callable[[T], T]:
|
||||
"""A :func:`.check` that indicates this command must only be used in a
|
||||
DM context. Only private messages are allowed when
|
||||
@ -2095,6 +2143,7 @@ def dm_only() -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def guild_only() -> Callable[[T], T]:
|
||||
"""A :func:`.check` that indicates this command must only be used in a
|
||||
guild context only. Basically, no private messages are allowed when
|
||||
@ -2111,6 +2160,7 @@ def guild_only() -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def is_owner() -> Callable[[T], T]:
|
||||
"""A :func:`.check` that checks if the person invoking this command is the
|
||||
owner of the bot.
|
||||
@ -2128,6 +2178,7 @@ def is_owner() -> Callable[[T], T]:
|
||||
|
||||
return check(predicate)
|
||||
|
||||
|
||||
def is_nsfw() -> Callable[[T], T]:
|
||||
"""A :func:`.check` that checks if the channel is a NSFW channel.
|
||||
|
||||
@ -2139,14 +2190,21 @@ def is_nsfw() -> Callable[[T], T]:
|
||||
Raise :exc:`.NSFWChannelRequired` instead of generic :exc:`.CheckFailure`.
|
||||
DM channels will also now pass this check.
|
||||
"""
|
||||
|
||||
def pred(ctx: Context) -> bool:
|
||||
ch = ctx.channel
|
||||
if ctx.guild is None or (isinstance(ch, (discord.TextChannel, discord.Thread)) and ch.is_nsfw()):
|
||||
return True
|
||||
raise NSFWChannelRequired(ch) # type: ignore
|
||||
|
||||
return check(pred)
|
||||
|
||||
def cooldown(rate: int, per: float, type: Union[BucketType, Callable[[Message], Any]] = BucketType.default) -> Callable[[T], T]:
|
||||
|
||||
def cooldown(
|
||||
rate: int,
|
||||
per: float,
|
||||
type: Union[BucketType, Callable[[Message], Any]] = BucketType.default,
|
||||
) -> Callable[[T], T]:
|
||||
"""A decorator that adds a cooldown to a :class:`.Command`
|
||||
|
||||
A cooldown allows a command to only be used a specific amount
|
||||
@ -2179,9 +2237,14 @@ def cooldown(rate: int, per: float, type: Union[BucketType, Callable[[Message],
|
||||
else:
|
||||
func.__commands_cooldown__ = CooldownMapping(Cooldown(rate, per), type)
|
||||
return func
|
||||
|
||||
return decorator # type: ignore
|
||||
|
||||
def dynamic_cooldown(cooldown: Union[BucketType, Callable[[Message], Any]], type: BucketType = BucketType.default) -> Callable[[T], T]:
|
||||
|
||||
def dynamic_cooldown(
|
||||
cooldown: Union[BucketType, Callable[[Message], Any]],
|
||||
type: BucketType = BucketType.default,
|
||||
) -> Callable[[T], T]:
|
||||
"""A decorator that adds a dynamic cooldown to a :class:`.Command`
|
||||
|
||||
This differs from :func:`.cooldown` in that it takes a function that
|
||||
@ -2219,8 +2282,10 @@ def dynamic_cooldown(cooldown: Union[BucketType, Callable[[Message], Any]], type
|
||||
else:
|
||||
func.__commands_cooldown__ = DynamicCooldownMapping(cooldown, type)
|
||||
return func
|
||||
|
||||
return decorator # type: ignore
|
||||
|
||||
|
||||
def max_concurrency(number: int, per: BucketType = BucketType.default, *, wait: bool = False) -> Callable[[T], T]:
|
||||
"""A decorator that adds a maximum concurrency to a :class:`.Command` or its subclasses.
|
||||
|
||||
@ -2252,8 +2317,10 @@ def max_concurrency(number: int, per: BucketType = BucketType.default, *, wait:
|
||||
else:
|
||||
func.__commands_max_concurrency__ = value
|
||||
return func
|
||||
|
||||
return decorator # type: ignore
|
||||
|
||||
|
||||
def before_invoke(coro) -> Callable[[T], T]:
|
||||
"""A decorator that registers a coroutine as a pre-invoke hook.
|
||||
|
||||
@ -2292,14 +2359,17 @@ def before_invoke(coro) -> Callable[[T], T]:
|
||||
|
||||
bot.add_cog(What())
|
||||
"""
|
||||
|
||||
def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]:
|
||||
if isinstance(func, Command):
|
||||
func.before_invoke(coro)
|
||||
else:
|
||||
func.__before_invoke__ = coro
|
||||
return func
|
||||
|
||||
return decorator # type: ignore
|
||||
|
||||
|
||||
def after_invoke(coro) -> Callable[[T], T]:
|
||||
"""A decorator that registers a coroutine as a post-invoke hook.
|
||||
|
||||
@ -2308,10 +2378,12 @@ def after_invoke(coro) -> Callable[[T], T]:
|
||||
|
||||
.. versionadded:: 1.4
|
||||
"""
|
||||
|
||||
def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]:
|
||||
if isinstance(func, Command):
|
||||
func.after_invoke(coro)
|
||||
else:
|
||||
func.__after_invoke__ = coro
|
||||
return func
|
||||
|
||||
return decorator # type: ignore
|
||||
|
@ -100,6 +100,7 @@ __all__ = (
|
||||
'MissingRequiredFlag',
|
||||
)
|
||||
|
||||
|
||||
class CommandError(DiscordException):
|
||||
r"""The base exception type for all command related errors.
|
||||
|
||||
@ -109,6 +110,7 @@ class CommandError(DiscordException):
|
||||
in a special way as they are caught and passed into a special event
|
||||
from :class:`.Bot`\, :func:`.on_command_error`.
|
||||
"""
|
||||
|
||||
def __init__(self, message: Optional[str] = None, *args: Any) -> None:
|
||||
if message is not None:
|
||||
# clean-up @everyone and @here mentions
|
||||
@ -117,6 +119,7 @@ class CommandError(DiscordException):
|
||||
else:
|
||||
super().__init__(*args)
|
||||
|
||||
|
||||
class ConversionError(CommandError):
|
||||
"""Exception raised when a Converter class raises non-CommandError.
|
||||
|
||||
@ -130,18 +133,22 @@ class ConversionError(CommandError):
|
||||
The original exception that was raised. You can also get this via
|
||||
the ``__cause__`` attribute.
|
||||
"""
|
||||
|
||||
def __init__(self, converter: Converter, original: Exception) -> None:
|
||||
self.converter: Converter = converter
|
||||
self.original: Exception = original
|
||||
|
||||
|
||||
class UserInputError(CommandError):
|
||||
"""The base exception type for errors that involve errors
|
||||
regarding user input.
|
||||
|
||||
This inherits from :exc:`CommandError`.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CommandNotFound(CommandError):
|
||||
"""Exception raised when a command is attempted to be invoked
|
||||
but no command under that name is found.
|
||||
@ -151,8 +158,10 @@ class CommandNotFound(CommandError):
|
||||
|
||||
This inherits from :exc:`CommandError`.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MissingRequiredArgument(UserInputError):
|
||||
"""Exception raised when parsing a command and a parameter
|
||||
that is required is not encountered.
|
||||
@ -164,33 +173,41 @@ class MissingRequiredArgument(UserInputError):
|
||||
param: :class:`inspect.Parameter`
|
||||
The argument that is missing.
|
||||
"""
|
||||
|
||||
def __init__(self, param: Parameter) -> None:
|
||||
self.param: Parameter = param
|
||||
super().__init__(f'{param.name} is a required argument that is missing.')
|
||||
|
||||
|
||||
class TooManyArguments(UserInputError):
|
||||
"""Exception raised when the command was passed too many arguments and its
|
||||
:attr:`.Command.ignore_extra` attribute was not set to ``True``.
|
||||
|
||||
This inherits from :exc:`UserInputError`
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BadArgument(UserInputError):
|
||||
"""Exception raised when a parsing or conversion failure is encountered
|
||||
on an argument to pass into a command.
|
||||
|
||||
This inherits from :exc:`UserInputError`
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CheckFailure(CommandError):
|
||||
"""Exception raised when the predicates in :attr:`.Command.checks` have failed.
|
||||
|
||||
This inherits from :exc:`CommandError`
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CheckAnyFailure(CheckFailure):
|
||||
"""Exception raised when all predicates in :func:`check_any` fail.
|
||||
|
||||
@ -211,15 +228,18 @@ class CheckAnyFailure(CheckFailure):
|
||||
self.errors: List[Callable[[Context], bool]] = errors
|
||||
super().__init__('You do not have permission to run this command.')
|
||||
|
||||
|
||||
class PrivateMessageOnly(CheckFailure):
|
||||
"""Exception raised when an operation does not work outside of private
|
||||
message contexts.
|
||||
|
||||
This inherits from :exc:`CheckFailure`
|
||||
"""
|
||||
|
||||
def __init__(self, message: Optional[str] = None) -> None:
|
||||
super().__init__(message or 'This command can only be used in private messages.')
|
||||
|
||||
|
||||
class NoPrivateMessage(CheckFailure):
|
||||
"""Exception raised when an operation does not work in private message
|
||||
contexts.
|
||||
@ -230,13 +250,16 @@ class NoPrivateMessage(CheckFailure):
|
||||
def __init__(self, message: Optional[str] = None) -> None:
|
||||
super().__init__(message or 'This command cannot be used in private messages.')
|
||||
|
||||
|
||||
class NotOwner(CheckFailure):
|
||||
"""Exception raised when the message author is not the owner of the bot.
|
||||
|
||||
This inherits from :exc:`CheckFailure`
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ObjectNotFound(BadArgument):
|
||||
"""Exception raised when the argument provided did not match the format
|
||||
of an ID or a mention.
|
||||
@ -250,10 +273,12 @@ class ObjectNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The argument supplied by the caller that was not matched
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'{argument!r} does not follow a valid ID or mention format.')
|
||||
|
||||
|
||||
class MemberNotFound(BadArgument):
|
||||
"""Exception raised when the member provided was not found in the bot's
|
||||
cache.
|
||||
@ -267,10 +292,12 @@ class MemberNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The member supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Member "{argument}" not found.')
|
||||
|
||||
|
||||
class GuildNotFound(BadArgument):
|
||||
"""Exception raised when the guild provided was not found in the bot's cache.
|
||||
|
||||
@ -283,10 +310,12 @@ class GuildNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The guild supplied by the called that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Guild "{argument}" not found.')
|
||||
|
||||
|
||||
class UserNotFound(BadArgument):
|
||||
"""Exception raised when the user provided was not found in the bot's
|
||||
cache.
|
||||
@ -300,10 +329,12 @@ class UserNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The user supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'User "{argument}" not found.')
|
||||
|
||||
|
||||
class MessageNotFound(BadArgument):
|
||||
"""Exception raised when the message provided was not found in the channel.
|
||||
|
||||
@ -316,10 +347,12 @@ class MessageNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The message supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Message "{argument}" not found.')
|
||||
|
||||
|
||||
class ChannelNotReadable(BadArgument):
|
||||
"""Exception raised when the bot does not have permission to read messages
|
||||
in the channel.
|
||||
@ -333,10 +366,12 @@ class ChannelNotReadable(BadArgument):
|
||||
argument: Union[:class:`.abc.GuildChannel`, :class:`.Thread`]
|
||||
The channel supplied by the caller that was not readable
|
||||
"""
|
||||
|
||||
def __init__(self, argument: Union[GuildChannel, Thread]) -> None:
|
||||
self.argument: Union[GuildChannel, Thread] = argument
|
||||
super().__init__(f"Can't read messages in {argument.mention}.")
|
||||
|
||||
|
||||
class ChannelNotFound(BadArgument):
|
||||
"""Exception raised when the bot can not find the channel.
|
||||
|
||||
@ -349,10 +384,12 @@ class ChannelNotFound(BadArgument):
|
||||
argument: Union[:class:`int`, :class:`str`]
|
||||
The channel supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: Union[int, str]) -> None:
|
||||
self.argument: Union[int, str] = argument
|
||||
super().__init__(f'Channel "{argument}" not found.')
|
||||
|
||||
|
||||
class ThreadNotFound(BadArgument):
|
||||
"""Exception raised when the bot can not find the thread.
|
||||
|
||||
@ -365,10 +402,12 @@ class ThreadNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The thread supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Thread "{argument}" not found.')
|
||||
|
||||
|
||||
class BadColourArgument(BadArgument):
|
||||
"""Exception raised when the colour is not valid.
|
||||
|
||||
@ -381,12 +420,15 @@ class BadColourArgument(BadArgument):
|
||||
argument: :class:`str`
|
||||
The colour supplied by the caller that was not valid
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Colour "{argument}" is invalid.')
|
||||
|
||||
|
||||
BadColorArgument = BadColourArgument
|
||||
|
||||
|
||||
class RoleNotFound(BadArgument):
|
||||
"""Exception raised when the bot can not find the role.
|
||||
|
||||
@ -399,10 +441,12 @@ class RoleNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The role supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Role "{argument}" not found.')
|
||||
|
||||
|
||||
class BadInviteArgument(BadArgument):
|
||||
"""Exception raised when the invite is invalid or expired.
|
||||
|
||||
@ -410,10 +454,12 @@ class BadInviteArgument(BadArgument):
|
||||
|
||||
.. versionadded:: 1.5
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Invite "{argument}" is invalid or expired.')
|
||||
|
||||
|
||||
class EmojiNotFound(BadArgument):
|
||||
"""Exception raised when the bot can not find the emoji.
|
||||
|
||||
@ -426,10 +472,12 @@ class EmojiNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The emoji supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Emoji "{argument}" not found.')
|
||||
|
||||
|
||||
class PartialEmojiConversionFailure(BadArgument):
|
||||
"""Exception raised when the emoji provided does not match the correct
|
||||
format.
|
||||
@ -443,10 +491,12 @@ class PartialEmojiConversionFailure(BadArgument):
|
||||
argument: :class:`str`
|
||||
The emoji supplied by the caller that did not match the regex
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Couldn\'t convert "{argument}" to PartialEmoji.')
|
||||
|
||||
|
||||
class GuildStickerNotFound(BadArgument):
|
||||
"""Exception raised when the bot can not find the sticker.
|
||||
|
||||
@ -459,10 +509,12 @@ class GuildStickerNotFound(BadArgument):
|
||||
argument: :class:`str`
|
||||
The sticker supplied by the caller that was not found
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'Sticker "{argument}" not found.')
|
||||
|
||||
|
||||
class BadBoolArgument(BadArgument):
|
||||
"""Exception raised when a boolean argument was not convertable.
|
||||
|
||||
@ -475,17 +527,21 @@ class BadBoolArgument(BadArgument):
|
||||
argument: :class:`str`
|
||||
The boolean argument supplied by the caller that is not in the predefined list
|
||||
"""
|
||||
|
||||
def __init__(self, argument: str) -> None:
|
||||
self.argument: str = argument
|
||||
super().__init__(f'{argument} is not a recognised boolean option')
|
||||
|
||||
|
||||
class DisabledCommand(CommandError):
|
||||
"""Exception raised when the command being invoked is disabled.
|
||||
|
||||
This inherits from :exc:`CommandError`
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CommandInvokeError(CommandError):
|
||||
"""Exception raised when the command being invoked raised an exception.
|
||||
|
||||
@ -497,10 +553,12 @@ class CommandInvokeError(CommandError):
|
||||
The original exception that was raised. You can also get this via
|
||||
the ``__cause__`` attribute.
|
||||
"""
|
||||
|
||||
def __init__(self, e: Exception) -> None:
|
||||
self.original: Exception = e
|
||||
super().__init__(f'Command raised an exception: {e.__class__.__name__}: {e}')
|
||||
|
||||
|
||||
class CommandOnCooldown(CommandError):
|
||||
"""Exception raised when the command being invoked is on cooldown.
|
||||
|
||||
@ -516,12 +574,14 @@ class CommandOnCooldown(CommandError):
|
||||
retry_after: :class:`float`
|
||||
The amount of seconds to wait before you can retry again.
|
||||
"""
|
||||
|
||||
def __init__(self, cooldown: Cooldown, retry_after: float, type: BucketType) -> None:
|
||||
self.cooldown: Cooldown = cooldown
|
||||
self.retry_after: float = retry_after
|
||||
self.type: BucketType = type
|
||||
super().__init__(f'You are on cooldown. Try again in {retry_after:.2f}s')
|
||||
|
||||
|
||||
class MaxConcurrencyReached(CommandError):
|
||||
"""Exception raised when the command being invoked has reached its maximum concurrency.
|
||||
|
||||
@ -544,6 +604,7 @@ class MaxConcurrencyReached(CommandError):
|
||||
fmt = plural % (number, suffix)
|
||||
super().__init__(f'Too many people are using this command. It can only be used {fmt} concurrently.')
|
||||
|
||||
|
||||
class MissingRole(CheckFailure):
|
||||
"""Exception raised when the command invoker lacks a role to run a command.
|
||||
|
||||
@ -557,11 +618,13 @@ class MissingRole(CheckFailure):
|
||||
The required role that is missing.
|
||||
This is the parameter passed to :func:`~.commands.has_role`.
|
||||
"""
|
||||
|
||||
def __init__(self, missing_role: Snowflake) -> None:
|
||||
self.missing_role: Snowflake = missing_role
|
||||
message = f'Role {missing_role!r} is required to run this command.'
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class BotMissingRole(CheckFailure):
|
||||
"""Exception raised when the bot's member lacks a role to run a command.
|
||||
|
||||
@ -575,11 +638,13 @@ class BotMissingRole(CheckFailure):
|
||||
The required role that is missing.
|
||||
This is the parameter passed to :func:`~.commands.has_role`.
|
||||
"""
|
||||
|
||||
def __init__(self, missing_role: Snowflake) -> None:
|
||||
self.missing_role: Snowflake = missing_role
|
||||
message = f'Bot requires the role {missing_role!r} to run this command'
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class MissingAnyRole(CheckFailure):
|
||||
"""Exception raised when the command invoker lacks any of
|
||||
the roles specified to run a command.
|
||||
@ -594,6 +659,7 @@ class MissingAnyRole(CheckFailure):
|
||||
The roles that the invoker is missing.
|
||||
These are the parameters passed to :func:`~.commands.has_any_role`.
|
||||
"""
|
||||
|
||||
def __init__(self, missing_roles: SnowflakeList) -> None:
|
||||
self.missing_roles: SnowflakeList = missing_roles
|
||||
|
||||
@ -623,6 +689,7 @@ class BotMissingAnyRole(CheckFailure):
|
||||
These are the parameters passed to :func:`~.commands.has_any_role`.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, missing_roles: SnowflakeList) -> None:
|
||||
self.missing_roles: SnowflakeList = missing_roles
|
||||
|
||||
@ -636,6 +703,7 @@ class BotMissingAnyRole(CheckFailure):
|
||||
message = f"Bot is missing at least one of the required roles: {fmt}"
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class NSFWChannelRequired(CheckFailure):
|
||||
"""Exception raised when a channel does not have the required NSFW setting.
|
||||
|
||||
@ -648,10 +716,12 @@ class NSFWChannelRequired(CheckFailure):
|
||||
channel: Union[:class:`.abc.GuildChannel`, :class:`.Thread`]
|
||||
The channel that does not have NSFW enabled.
|
||||
"""
|
||||
|
||||
def __init__(self, channel: Union[GuildChannel, Thread]) -> None:
|
||||
self.channel: Union[GuildChannel, Thread] = channel
|
||||
super().__init__(f"Channel '{channel}' needs to be NSFW for this command to work.")
|
||||
|
||||
|
||||
class MissingPermissions(CheckFailure):
|
||||
"""Exception raised when the command invoker lacks permissions to run a
|
||||
command.
|
||||
@ -663,6 +733,7 @@ class MissingPermissions(CheckFailure):
|
||||
missing_permissions: List[:class:`str`]
|
||||
The required permissions that are missing.
|
||||
"""
|
||||
|
||||
def __init__(self, missing_permissions: List[str], *args: Any) -> None:
|
||||
self.missing_permissions: List[str] = missing_permissions
|
||||
|
||||
@ -675,6 +746,7 @@ class MissingPermissions(CheckFailure):
|
||||
message = f'You are missing {fmt} permission(s) to run this command.'
|
||||
super().__init__(message, *args)
|
||||
|
||||
|
||||
class BotMissingPermissions(CheckFailure):
|
||||
"""Exception raised when the bot's member lacks permissions to run a
|
||||
command.
|
||||
@ -686,6 +758,7 @@ class BotMissingPermissions(CheckFailure):
|
||||
missing_permissions: List[:class:`str`]
|
||||
The required permissions that are missing.
|
||||
"""
|
||||
|
||||
def __init__(self, missing_permissions: List[str], *args: Any) -> None:
|
||||
self.missing_permissions: List[str] = missing_permissions
|
||||
|
||||
@ -698,6 +771,7 @@ class BotMissingPermissions(CheckFailure):
|
||||
message = f'Bot requires {fmt} permission(s) to run this command.'
|
||||
super().__init__(message, *args)
|
||||
|
||||
|
||||
class BadUnionArgument(UserInputError):
|
||||
"""Exception raised when a :data:`typing.Union` converter fails for all
|
||||
its associated types.
|
||||
@ -713,6 +787,7 @@ class BadUnionArgument(UserInputError):
|
||||
errors: List[:class:`CommandError`]
|
||||
A list of errors that were caught from failing the conversion.
|
||||
"""
|
||||
|
||||
def __init__(self, param: Parameter, converters: Tuple[Type, ...], errors: List[CommandError]) -> None:
|
||||
self.param: Parameter = param
|
||||
self.converters: Tuple[Type, ...] = converters
|
||||
@ -734,6 +809,7 @@ class BadUnionArgument(UserInputError):
|
||||
|
||||
super().__init__(f'Could not convert "{param.name}" into {fmt}.')
|
||||
|
||||
|
||||
class BadLiteralArgument(UserInputError):
|
||||
"""Exception raised when a :data:`typing.Literal` converter fails for all
|
||||
its associated values.
|
||||
@ -751,6 +827,7 @@ class BadLiteralArgument(UserInputError):
|
||||
errors: List[:class:`CommandError`]
|
||||
A list of errors that were caught from failing the conversion.
|
||||
"""
|
||||
|
||||
def __init__(self, param: Parameter, literals: Tuple[Any, ...], errors: List[CommandError]) -> None:
|
||||
self.param: Parameter = param
|
||||
self.literals: Tuple[Any, ...] = literals
|
||||
@ -764,6 +841,7 @@ class BadLiteralArgument(UserInputError):
|
||||
|
||||
super().__init__(f'Could not convert "{param.name}" into the literal {fmt}.')
|
||||
|
||||
|
||||
class ArgumentParsingError(UserInputError):
|
||||
"""An exception raised when the parser fails to parse a user's input.
|
||||
|
||||
@ -772,8 +850,10 @@ class ArgumentParsingError(UserInputError):
|
||||
There are child classes that implement more granular parsing errors for
|
||||
i18n purposes.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnexpectedQuoteError(ArgumentParsingError):
|
||||
"""An exception raised when the parser encounters a quote mark inside a non-quoted string.
|
||||
|
||||
@ -784,10 +864,12 @@ class UnexpectedQuoteError(ArgumentParsingError):
|
||||
quote: :class:`str`
|
||||
The quote mark that was found inside the non-quoted string.
|
||||
"""
|
||||
|
||||
def __init__(self, quote: str) -> None:
|
||||
self.quote: str = quote
|
||||
super().__init__(f'Unexpected quote mark, {quote!r}, in non-quoted string')
|
||||
|
||||
|
||||
class InvalidEndOfQuotedStringError(ArgumentParsingError):
|
||||
"""An exception raised when a space is expected after the closing quote in a string
|
||||
but a different character is found.
|
||||
@ -799,10 +881,12 @@ class InvalidEndOfQuotedStringError(ArgumentParsingError):
|
||||
char: :class:`str`
|
||||
The character found instead of the expected string.
|
||||
"""
|
||||
|
||||
def __init__(self, char: str) -> None:
|
||||
self.char: str = char
|
||||
super().__init__(f'Expected space after closing quotation but received {char!r}')
|
||||
|
||||
|
||||
class ExpectedClosingQuoteError(ArgumentParsingError):
|
||||
"""An exception raised when a quote character is expected but not found.
|
||||
|
||||
@ -818,6 +902,7 @@ class ExpectedClosingQuoteError(ArgumentParsingError):
|
||||
self.close_quote: str = close_quote
|
||||
super().__init__(f'Expected closing {close_quote}.')
|
||||
|
||||
|
||||
class ExtensionError(DiscordException):
|
||||
"""Base exception for extension related errors.
|
||||
|
||||
@ -828,6 +913,7 @@ class ExtensionError(DiscordException):
|
||||
name: :class:`str`
|
||||
The extension that had an error.
|
||||
"""
|
||||
|
||||
def __init__(self, message: Optional[str] = None, *args: Any, name: str) -> None:
|
||||
self.name: str = name
|
||||
message = message or f'Extension {name!r} had an error.'
|
||||
@ -835,30 +921,37 @@ class ExtensionError(DiscordException):
|
||||
m = message.replace('@everyone', '@\u200beveryone').replace('@here', '@\u200bhere')
|
||||
super().__init__(m, *args)
|
||||
|
||||
|
||||
class ExtensionAlreadyLoaded(ExtensionError):
|
||||
"""An exception raised when an extension has already been loaded.
|
||||
|
||||
This inherits from :exc:`ExtensionError`
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(f'Extension {name!r} is already loaded.', name=name)
|
||||
|
||||
|
||||
class ExtensionNotLoaded(ExtensionError):
|
||||
"""An exception raised when an extension was not loaded.
|
||||
|
||||
This inherits from :exc:`ExtensionError`
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(f'Extension {name!r} has not been loaded.', name=name)
|
||||
|
||||
|
||||
class NoEntryPointError(ExtensionError):
|
||||
"""An exception raised when an extension does not have a ``setup`` entry point function.
|
||||
|
||||
This inherits from :exc:`ExtensionError`
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(f"Extension {name!r} has no 'setup' function.", name=name)
|
||||
|
||||
|
||||
class ExtensionFailed(ExtensionError):
|
||||
"""An exception raised when an extension failed to load during execution of the module or ``setup`` entry point.
|
||||
|
||||
@ -872,11 +965,13 @@ class ExtensionFailed(ExtensionError):
|
||||
The original exception that was raised. You can also get this via
|
||||
the ``__cause__`` attribute.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, original: Exception) -> None:
|
||||
self.original: Exception = original
|
||||
msg = f'Extension {name!r} raised an error: {original.__class__.__name__}: {original}'
|
||||
super().__init__(msg, name=name)
|
||||
|
||||
|
||||
class ExtensionNotFound(ExtensionError):
|
||||
"""An exception raised when an extension is not found.
|
||||
|
||||
@ -890,10 +985,12 @@ class ExtensionNotFound(ExtensionError):
|
||||
name: :class:`str`
|
||||
The extension that had the error.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
msg = f'Extension {name!r} could not be loaded.'
|
||||
super().__init__(msg, name=name)
|
||||
|
||||
|
||||
class CommandRegistrationError(ClientException):
|
||||
"""An exception raised when the command can't be added
|
||||
because the name is already taken by a different command.
|
||||
@ -909,12 +1006,14 @@ class CommandRegistrationError(ClientException):
|
||||
alias_conflict: :class:`bool`
|
||||
Whether the name that conflicts is an alias of the command we try to add.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, *, alias_conflict: bool = False) -> None:
|
||||
self.name: str = name
|
||||
self.alias_conflict: bool = alias_conflict
|
||||
type_ = 'alias' if alias_conflict else 'command'
|
||||
super().__init__(f'The {type_} {name} is already an existing command or alias.')
|
||||
|
||||
|
||||
class FlagError(BadArgument):
|
||||
"""The base exception type for all flag parsing related errors.
|
||||
|
||||
@ -922,8 +1021,10 @@ class FlagError(BadArgument):
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TooManyFlags(FlagError):
|
||||
"""An exception raised when a flag has received too many values.
|
||||
|
||||
@ -938,11 +1039,13 @@ class TooManyFlags(FlagError):
|
||||
values: List[:class:`str`]
|
||||
The values that were passed.
|
||||
"""
|
||||
|
||||
def __init__(self, flag: Flag, values: List[str]) -> None:
|
||||
self.flag: Flag = flag
|
||||
self.values: List[str] = values
|
||||
super().__init__(f'Too many flag values, expected {flag.max_args} but received {len(values)}.')
|
||||
|
||||
|
||||
class BadFlagArgument(FlagError):
|
||||
"""An exception raised when a flag failed to convert a value.
|
||||
|
||||
@ -955,6 +1058,7 @@ class BadFlagArgument(FlagError):
|
||||
flag: :class:`~discord.ext.commands.Flag`
|
||||
The flag that failed to convert.
|
||||
"""
|
||||
|
||||
def __init__(self, flag: Flag) -> None:
|
||||
self.flag: Flag = flag
|
||||
try:
|
||||
@ -964,6 +1068,7 @@ class BadFlagArgument(FlagError):
|
||||
|
||||
super().__init__(f'Could not convert to {name!r} for flag {flag.name!r}')
|
||||
|
||||
|
||||
class MissingRequiredFlag(FlagError):
|
||||
"""An exception raised when a required flag was not given.
|
||||
|
||||
@ -976,10 +1081,12 @@ class MissingRequiredFlag(FlagError):
|
||||
flag: :class:`~discord.ext.commands.Flag`
|
||||
The required flag that was not found.
|
||||
"""
|
||||
|
||||
def __init__(self, flag: Flag) -> None:
|
||||
self.flag: Flag = flag
|
||||
super().__init__(f'Flag {flag.name!r} is required and missing')
|
||||
|
||||
|
||||
class MissingFlagArgument(FlagError):
|
||||
"""An exception raised when a flag did not get a value.
|
||||
|
||||
@ -992,6 +1099,7 @@ class MissingFlagArgument(FlagError):
|
||||
flag: :class:`~discord.ext.commands.Flag`
|
||||
The flag that did not get a value.
|
||||
"""
|
||||
|
||||
def __init__(self, flag: Flag) -> None:
|
||||
self.flag: Flag = flag
|
||||
super().__init__(f'Flag {flag.name!r} does not have an argument')
|
||||
|
@ -932,7 +932,7 @@ class DefaultHelpCommand(HelpCommand):
|
||||
def shorten_text(self, text):
|
||||
""":class:`str`: Shortens text to fit into the :attr:`width`."""
|
||||
if len(text) > self.width:
|
||||
return text[:self.width - 3].rstrip() + '...'
|
||||
return text[: self.width - 3].rstrip() + '...'
|
||||
return text
|
||||
|
||||
def get_ending_note(self):
|
||||
|
@ -46,6 +46,7 @@ _quotes = {
|
||||
}
|
||||
_all_quotes = set(_quotes.keys()) | set(_quotes.values())
|
||||
|
||||
|
||||
class StringView:
|
||||
def __init__(self, buffer):
|
||||
self.index = 0
|
||||
@ -81,20 +82,20 @@ class StringView:
|
||||
|
||||
def skip_string(self, string):
|
||||
strlen = len(string)
|
||||
if self.buffer[self.index:self.index + strlen] == string:
|
||||
if self.buffer[self.index : self.index + strlen] == string:
|
||||
self.previous = self.index
|
||||
self.index += strlen
|
||||
return True
|
||||
return False
|
||||
|
||||
def read_rest(self):
|
||||
result = self.buffer[self.index:]
|
||||
result = self.buffer[self.index :]
|
||||
self.previous = self.index
|
||||
self.index = self.end
|
||||
return result
|
||||
|
||||
def read(self, n):
|
||||
result = self.buffer[self.index:self.index + n]
|
||||
result = self.buffer[self.index : self.index + n]
|
||||
self.previous = self.index
|
||||
self.index += n
|
||||
return result
|
||||
@ -120,7 +121,7 @@ class StringView:
|
||||
except IndexError:
|
||||
break
|
||||
self.previous = self.index
|
||||
result = self.buffer[self.index:self.index + pos]
|
||||
result = self.buffer[self.index : self.index + pos]
|
||||
self.index += pos
|
||||
return result
|
||||
|
||||
@ -187,6 +188,5 @@ class StringView:
|
||||
|
||||
result.append(current)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return f'<StringView pos: {self.index} prev: {self.previous} end: {self.end} eof: {self.eof}>'
|
||||
|
@ -48,9 +48,11 @@ from collections.abc import Sequence
|
||||
from discord.backoff import ExponentialBackoff
|
||||
from discord.utils import MISSING
|
||||
|
||||
# fmt: off
|
||||
__all__ = (
|
||||
'loop',
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
T = TypeVar('T')
|
||||
_func = Callable[..., Awaitable[Any]]
|
||||
|
Reference in New Issue
Block a user