mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-09-05 09:26:10 +00:00
Fix typing issues and improve typing completeness across the library
Co-authored-by: Danny <Rapptz@users.noreply.github.com> Co-authored-by: Josh <josh.ja.butt@gmail.com>
This commit is contained in:
@ -22,13 +22,27 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import copy
|
||||
import functools
|
||||
import inspect
|
||||
import re
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Optional,
|
||||
Generator,
|
||||
List,
|
||||
TypeVar,
|
||||
Callable,
|
||||
Any,
|
||||
Dict,
|
||||
Tuple,
|
||||
Iterable,
|
||||
Sequence,
|
||||
Mapping,
|
||||
)
|
||||
|
||||
import discord.utils
|
||||
|
||||
@ -36,7 +50,21 @@ from .core import Group, Command, get_signature_parameters
|
||||
from .errors import CommandError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
import inspect
|
||||
|
||||
import discord.abc
|
||||
|
||||
from .bot import BotBase
|
||||
from .context import Context
|
||||
from .cog import Cog
|
||||
|
||||
from ._types import (
|
||||
Check,
|
||||
ContextT,
|
||||
BotT,
|
||||
_Bot,
|
||||
)
|
||||
|
||||
__all__ = (
|
||||
'Paginator',
|
||||
@ -45,7 +73,9 @@ __all__ = (
|
||||
'MinimalHelpCommand',
|
||||
)
|
||||
|
||||
MISSING = discord.utils.MISSING
|
||||
FuncT = TypeVar('FuncT', bound=Callable[..., Any])
|
||||
|
||||
MISSING: Any = discord.utils.MISSING
|
||||
|
||||
# help -> shows info of bot on top/bottom and lists subcommands
|
||||
# help command -> shows detailed info of command
|
||||
@ -80,10 +110,10 @@ class Paginator:
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
prefix: :class:`str`
|
||||
The prefix inserted to every page. e.g. three backticks.
|
||||
suffix: :class:`str`
|
||||
The suffix appended at the end of every page. e.g. three backticks.
|
||||
prefix: Optional[:class:`str`]
|
||||
The prefix inserted to every page. e.g. three backticks, if any.
|
||||
suffix: Optional[:class:`str`]
|
||||
The suffix appended at the end of every page. e.g. three backticks, if any.
|
||||
max_size: :class:`int`
|
||||
The maximum amount of codepoints allowed in a page.
|
||||
linesep: :class:`str`
|
||||
@ -91,36 +121,38 @@ class Paginator:
|
||||
.. versionadded:: 1.7
|
||||
"""
|
||||
|
||||
def __init__(self, prefix='```', suffix='```', max_size=2000, linesep='\n'):
|
||||
self.prefix = prefix
|
||||
self.suffix = suffix
|
||||
self.max_size = max_size
|
||||
self.linesep = linesep
|
||||
def __init__(
|
||||
self, prefix: Optional[str] = '```', suffix: Optional[str] = '```', max_size: int = 2000, linesep: str = '\n'
|
||||
) -> None:
|
||||
self.prefix: Optional[str] = prefix
|
||||
self.suffix: Optional[str] = suffix
|
||||
self.max_size: int = max_size
|
||||
self.linesep: str = linesep
|
||||
self.clear()
|
||||
|
||||
def clear(self):
|
||||
def clear(self) -> None:
|
||||
"""Clears the paginator to have no pages."""
|
||||
if self.prefix is not None:
|
||||
self._current_page = [self.prefix]
|
||||
self._count = len(self.prefix) + self._linesep_len # prefix + newline
|
||||
self._current_page: List[str] = [self.prefix]
|
||||
self._count: int = len(self.prefix) + self._linesep_len # prefix + newline
|
||||
else:
|
||||
self._current_page = []
|
||||
self._count = 0
|
||||
self._pages = []
|
||||
self._pages: List[str] = []
|
||||
|
||||
@property
|
||||
def _prefix_len(self):
|
||||
def _prefix_len(self) -> int:
|
||||
return len(self.prefix) if self.prefix else 0
|
||||
|
||||
@property
|
||||
def _suffix_len(self):
|
||||
def _suffix_len(self) -> int:
|
||||
return len(self.suffix) if self.suffix else 0
|
||||
|
||||
@property
|
||||
def _linesep_len(self):
|
||||
def _linesep_len(self) -> int:
|
||||
return len(self.linesep)
|
||||
|
||||
def add_line(self, line='', *, empty=False):
|
||||
def add_line(self, line: str = '', *, empty: bool = False) -> None:
|
||||
"""Adds a line to the current page.
|
||||
|
||||
If the line exceeds the :attr:`max_size` then an exception
|
||||
@ -152,7 +184,7 @@ class Paginator:
|
||||
self._current_page.append('')
|
||||
self._count += self._linesep_len
|
||||
|
||||
def close_page(self):
|
||||
def close_page(self) -> None:
|
||||
"""Prematurely terminate a page."""
|
||||
if self.suffix is not None:
|
||||
self._current_page.append(self.suffix)
|
||||
@ -165,36 +197,38 @@ class Paginator:
|
||||
self._current_page = []
|
||||
self._count = 0
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
total = sum(len(p) for p in self._pages)
|
||||
return total + self._count
|
||||
|
||||
@property
|
||||
def pages(self):
|
||||
def pages(self) -> List[str]:
|
||||
"""List[:class:`str`]: Returns the rendered list of pages."""
|
||||
# we have more than just the prefix in our current page
|
||||
if len(self._current_page) > (0 if self.prefix is None else 1):
|
||||
self.close_page()
|
||||
return self._pages
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
fmt = '<Paginator prefix: {0.prefix!r} suffix: {0.suffix!r} linesep: {0.linesep!r} max_size: {0.max_size} count: {0._count}>'
|
||||
return fmt.format(self)
|
||||
|
||||
|
||||
def _not_overridden(f):
|
||||
def _not_overridden(f: FuncT) -> FuncT:
|
||||
f.__help_command_not_overridden__ = True
|
||||
return f
|
||||
|
||||
|
||||
class _HelpCommandImpl(Command):
|
||||
def __init__(self, inject, *args, **kwargs):
|
||||
def __init__(self, inject: HelpCommand, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(inject.command_callback, *args, **kwargs)
|
||||
self._original = inject
|
||||
self._injected = inject
|
||||
self.params = get_signature_parameters(inject.command_callback, globals(), skip_parameters=1)
|
||||
self._original: HelpCommand = inject
|
||||
self._injected: HelpCommand = inject
|
||||
self.params: Dict[str, inspect.Parameter] = get_signature_parameters(
|
||||
inject.command_callback, globals(), skip_parameters=1
|
||||
)
|
||||
|
||||
async def prepare(self, ctx):
|
||||
async def prepare(self, ctx: Context[Any]) -> None:
|
||||
self._injected = injected = self._original.copy()
|
||||
injected.context = ctx
|
||||
self.callback = injected.command_callback
|
||||
@ -209,7 +243,7 @@ class _HelpCommandImpl(Command):
|
||||
|
||||
await super().prepare(ctx)
|
||||
|
||||
async def _parse_arguments(self, ctx):
|
||||
async def _parse_arguments(self, ctx: Context[BotT]) -> None:
|
||||
# Make the parser think we don't have a cog so it doesn't
|
||||
# inject the parameter into `ctx.args`.
|
||||
original_cog = self.cog
|
||||
@ -219,22 +253,26 @@ class _HelpCommandImpl(Command):
|
||||
finally:
|
||||
self.cog = original_cog
|
||||
|
||||
async def _on_error_cog_implementation(self, dummy, ctx, error):
|
||||
async def _on_error_cog_implementation(self, _, ctx: Context[BotT], error: CommandError) -> None:
|
||||
await self._injected.on_help_command_error(ctx, error)
|
||||
|
||||
def _inject_into_cog(self, cog):
|
||||
def _inject_into_cog(self, cog: Cog) -> None:
|
||||
# Warning: hacky
|
||||
|
||||
# Make the cog think that get_commands returns this command
|
||||
# as well if we inject it without modifying __cog_commands__
|
||||
# since that's used for the injection and ejection of cogs.
|
||||
def wrapped_get_commands(*, _original=cog.get_commands):
|
||||
def wrapped_get_commands(
|
||||
*, _original: Callable[[], List[Command[Any, ..., Any]]] = cog.get_commands
|
||||
) -> List[Command[Any, ..., Any]]:
|
||||
ret = _original()
|
||||
ret.append(self)
|
||||
return ret
|
||||
|
||||
# Ditto here
|
||||
def wrapped_walk_commands(*, _original=cog.walk_commands):
|
||||
def wrapped_walk_commands(
|
||||
*, _original: Callable[[], Generator[Command[Any, ..., Any], None, None]] = cog.walk_commands
|
||||
):
|
||||
yield from _original()
|
||||
yield self
|
||||
|
||||
@ -244,7 +282,7 @@ class _HelpCommandImpl(Command):
|
||||
cog.walk_commands = wrapped_walk_commands
|
||||
self.cog = cog
|
||||
|
||||
def _eject_cog(self):
|
||||
def _eject_cog(self) -> None:
|
||||
if self.cog is None:
|
||||
return
|
||||
|
||||
@ -298,7 +336,11 @@ class HelpCommand:
|
||||
|
||||
MENTION_PATTERN = re.compile('|'.join(MENTION_TRANSFORMS.keys()))
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if TYPE_CHECKING:
|
||||
__original_kwargs__: Dict[str, Any]
|
||||
__original_args__: Tuple[Any, ...]
|
||||
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
|
||||
# To prevent race conditions of a single instance while also allowing
|
||||
# for settings to be passed the original arguments passed must be assigned
|
||||
# to allow for easier copies (which will be made when the help command is actually called)
|
||||
@ -314,30 +356,31 @@ class HelpCommand:
|
||||
self.__original_args__ = deepcopy(args)
|
||||
return self
|
||||
|
||||
def __init__(self, **options):
|
||||
self.show_hidden = options.pop('show_hidden', False)
|
||||
self.verify_checks = options.pop('verify_checks', True)
|
||||
def __init__(self, **options: Any) -> None:
|
||||
self.show_hidden: bool = options.pop('show_hidden', False)
|
||||
self.verify_checks: bool = options.pop('verify_checks', True)
|
||||
self.command_attrs: Dict[str, Any]
|
||||
self.command_attrs = attrs = options.pop('command_attrs', {})
|
||||
attrs.setdefault('name', 'help')
|
||||
attrs.setdefault('help', 'Shows this message')
|
||||
self.context: Context = MISSING
|
||||
self.context: Context[_Bot] = MISSING
|
||||
self._command_impl = _HelpCommandImpl(self, **self.command_attrs)
|
||||
|
||||
def copy(self):
|
||||
def copy(self) -> Self:
|
||||
obj = self.__class__(*self.__original_args__, **self.__original_kwargs__)
|
||||
obj._command_impl = self._command_impl
|
||||
return obj
|
||||
|
||||
def _add_to_bot(self, bot):
|
||||
def _add_to_bot(self, bot: BotBase) -> None:
|
||||
command = _HelpCommandImpl(self, **self.command_attrs)
|
||||
bot.add_command(command)
|
||||
self._command_impl = command
|
||||
|
||||
def _remove_from_bot(self, bot):
|
||||
def _remove_from_bot(self, bot: BotBase) -> None:
|
||||
bot.remove_command(self._command_impl.name)
|
||||
self._command_impl._eject_cog()
|
||||
|
||||
def add_check(self, func, /):
|
||||
def add_check(self, func: Check[ContextT], /) -> None:
|
||||
"""
|
||||
Adds a check to the help command.
|
||||
|
||||
@ -355,7 +398,7 @@ class HelpCommand:
|
||||
|
||||
self._command_impl.add_check(func)
|
||||
|
||||
def remove_check(self, func, /):
|
||||
def remove_check(self, func: Check[ContextT], /) -> None:
|
||||
"""
|
||||
Removes a check from the help command.
|
||||
|
||||
@ -376,15 +419,15 @@ class HelpCommand:
|
||||
|
||||
self._command_impl.remove_check(func)
|
||||
|
||||
def get_bot_mapping(self):
|
||||
def get_bot_mapping(self) -> Dict[Optional[Cog], List[Command[Any, ..., Any]]]:
|
||||
"""Retrieves the bot mapping passed to :meth:`send_bot_help`."""
|
||||
bot = self.context.bot
|
||||
mapping = {cog: cog.get_commands() for cog in bot.cogs.values()}
|
||||
mapping: Dict[Optional[Cog], List[Command[Any, ..., Any]]] = {cog: cog.get_commands() for cog in bot.cogs.values()}
|
||||
mapping[None] = [c for c in bot.commands if c.cog is None]
|
||||
return mapping
|
||||
|
||||
@property
|
||||
def invoked_with(self):
|
||||
def invoked_with(self) -> Optional[str]:
|
||||
"""Similar to :attr:`Context.invoked_with` except properly handles
|
||||
the case where :meth:`Context.send_help` is used.
|
||||
|
||||
@ -395,7 +438,7 @@ class HelpCommand:
|
||||
|
||||
Returns
|
||||
---------
|
||||
:class:`str`
|
||||
Optional[:class:`str`]
|
||||
The command name that triggered this invocation.
|
||||
"""
|
||||
command_name = self._command_impl.name
|
||||
@ -404,7 +447,7 @@ class HelpCommand:
|
||||
return command_name
|
||||
return ctx.invoked_with
|
||||
|
||||
def get_command_signature(self, command):
|
||||
def get_command_signature(self, command: Command[Any, ..., Any]) -> str:
|
||||
"""Retrieves the signature portion of the help page.
|
||||
|
||||
Parameters
|
||||
@ -418,14 +461,14 @@ class HelpCommand:
|
||||
The signature for the command.
|
||||
"""
|
||||
|
||||
parent = command.parent
|
||||
parent: Optional[Group[Any, ..., Any]] = command.parent # type: ignore - the parent will be a Group
|
||||
entries = []
|
||||
while parent is not None:
|
||||
if not parent.signature or parent.invoke_without_command:
|
||||
entries.append(parent.name)
|
||||
else:
|
||||
entries.append(parent.name + ' ' + parent.signature)
|
||||
parent = parent.parent
|
||||
parent = parent.parent # type: ignore
|
||||
parent_sig = ' '.join(reversed(entries))
|
||||
|
||||
if len(command.aliases) > 0:
|
||||
@ -439,7 +482,7 @@ class HelpCommand:
|
||||
|
||||
return f'{self.context.clean_prefix}{alias} {command.signature}'
|
||||
|
||||
def remove_mentions(self, string):
|
||||
def remove_mentions(self, string: str) -> str:
|
||||
"""Removes mentions from the string to prevent abuse.
|
||||
|
||||
This includes ``@everyone``, ``@here``, member mentions and role mentions.
|
||||
@ -450,13 +493,13 @@ class HelpCommand:
|
||||
The string with mentions removed.
|
||||
"""
|
||||
|
||||
def replace(obj, *, transforms=self.MENTION_TRANSFORMS):
|
||||
def replace(obj: re.Match, *, transforms: Dict[str, str] = self.MENTION_TRANSFORMS) -> str:
|
||||
return transforms.get(obj.group(0), '@invalid')
|
||||
|
||||
return self.MENTION_PATTERN.sub(replace, string)
|
||||
|
||||
@property
|
||||
def cog(self):
|
||||
def cog(self) -> Optional[Cog]:
|
||||
"""A property for retrieving or setting the cog for the help command.
|
||||
|
||||
When a cog is set for the help command, it is as-if the help command
|
||||
@ -473,7 +516,7 @@ class HelpCommand:
|
||||
return self._command_impl.cog
|
||||
|
||||
@cog.setter
|
||||
def cog(self, cog):
|
||||
def cog(self, cog: Optional[Cog]) -> None:
|
||||
# Remove whatever cog is currently valid, if any
|
||||
self._command_impl._eject_cog()
|
||||
|
||||
@ -481,7 +524,7 @@ class HelpCommand:
|
||||
if cog is not None:
|
||||
self._command_impl._inject_into_cog(cog)
|
||||
|
||||
def command_not_found(self, string):
|
||||
def command_not_found(self, string: str) -> str:
|
||||
"""|maybecoro|
|
||||
|
||||
A method called when a command is not found in the help command.
|
||||
@ -502,7 +545,7 @@ class HelpCommand:
|
||||
"""
|
||||
return f'No command called "{string}" found.'
|
||||
|
||||
def subcommand_not_found(self, command, string):
|
||||
def subcommand_not_found(self, command: Command[Any, ..., Any], string: str) -> str:
|
||||
"""|maybecoro|
|
||||
|
||||
A method called when a command did not have a subcommand requested in the help command.
|
||||
@ -532,7 +575,13 @@ class HelpCommand:
|
||||
return f'Command "{command.qualified_name}" has no subcommand named {string}'
|
||||
return f'Command "{command.qualified_name}" has no subcommands.'
|
||||
|
||||
async def filter_commands(self, commands, *, sort=False, key=None):
|
||||
async def filter_commands(
|
||||
self,
|
||||
commands: Iterable[Command[Any, ..., Any]],
|
||||
*,
|
||||
sort: bool = False,
|
||||
key: Optional[Callable[[Command[Any, ..., Any]], Any]] = None,
|
||||
) -> List[Command[Any, ..., Any]]:
|
||||
"""|coro|
|
||||
|
||||
Returns a filtered list of commands and optionally sorts them.
|
||||
@ -546,7 +595,7 @@ class HelpCommand:
|
||||
An iterable of commands that are getting filtered.
|
||||
sort: :class:`bool`
|
||||
Whether to sort the result.
|
||||
key: Optional[Callable[:class:`Command`, Any]]
|
||||
key: Optional[Callable[[:class:`Command`], Any]]
|
||||
An optional key function to pass to :func:`py:sorted` that
|
||||
takes a :class:`Command` as its sole parameter. If ``sort`` is
|
||||
passed as ``True`` then this will default as the command name.
|
||||
@ -565,14 +614,14 @@ class HelpCommand:
|
||||
if self.verify_checks is False:
|
||||
# if we do not need to verify the checks then we can just
|
||||
# run it straight through normally without using await.
|
||||
return sorted(iterator, key=key) if sort else list(iterator)
|
||||
return sorted(iterator, key=key) if sort else list(iterator) # type: ignore - the key shouldn't be None
|
||||
|
||||
if self.verify_checks is None and not self.context.guild:
|
||||
# if verify_checks is None and we're in a DM, don't verify
|
||||
return sorted(iterator, key=key) if sort else list(iterator)
|
||||
return sorted(iterator, key=key) if sort else list(iterator) # type: ignore
|
||||
|
||||
# if we're here then we need to check every command if it can run
|
||||
async def predicate(cmd):
|
||||
async def predicate(cmd: Command[Any, ..., Any]) -> bool:
|
||||
try:
|
||||
return await cmd.can_run(self.context)
|
||||
except CommandError:
|
||||
@ -588,7 +637,7 @@ class HelpCommand:
|
||||
ret.sort(key=key)
|
||||
return ret
|
||||
|
||||
def get_max_size(self, commands):
|
||||
def get_max_size(self, commands: Sequence[Command[Any, ..., Any]]) -> int:
|
||||
"""Returns the largest name length of the specified command list.
|
||||
|
||||
Parameters
|
||||
@ -605,7 +654,7 @@ class HelpCommand:
|
||||
as_lengths = (discord.utils._string_width(c.name) for c in commands)
|
||||
return max(as_lengths, default=0)
|
||||
|
||||
def get_destination(self):
|
||||
def get_destination(self) -> discord.abc.MessageableChannel:
|
||||
"""Returns the :class:`~discord.abc.Messageable` where the help command will be output.
|
||||
|
||||
You can override this method to customise the behaviour.
|
||||
@ -619,7 +668,7 @@ class HelpCommand:
|
||||
"""
|
||||
return self.context.channel
|
||||
|
||||
async def send_error_message(self, error):
|
||||
async def send_error_message(self, error: str) -> None:
|
||||
"""|coro|
|
||||
|
||||
Handles the implementation when an error happens in the help command.
|
||||
@ -644,7 +693,7 @@ class HelpCommand:
|
||||
await destination.send(error)
|
||||
|
||||
@_not_overridden
|
||||
async def on_help_command_error(self, ctx, error):
|
||||
async def on_help_command_error(self, ctx: Context[BotT], error: CommandError) -> None:
|
||||
"""|coro|
|
||||
|
||||
The help command's error handler, as specified by :ref:`ext_commands_error_handler`.
|
||||
@ -664,7 +713,7 @@ class HelpCommand:
|
||||
"""
|
||||
pass
|
||||
|
||||
async def send_bot_help(self, mapping):
|
||||
async def send_bot_help(self, mapping: Mapping[Optional[Cog], List[Command[Any, ..., Any]]]) -> None:
|
||||
"""|coro|
|
||||
|
||||
Handles the implementation of the bot command page in the help command.
|
||||
@ -693,7 +742,7 @@ class HelpCommand:
|
||||
"""
|
||||
return None
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
async def send_cog_help(self, cog: Cog) -> None:
|
||||
"""|coro|
|
||||
|
||||
Handles the implementation of the cog page in the help command.
|
||||
@ -721,7 +770,7 @@ class HelpCommand:
|
||||
"""
|
||||
return None
|
||||
|
||||
async def send_group_help(self, group):
|
||||
async def send_group_help(self, group: Group[Any, ..., Any]) -> None:
|
||||
"""|coro|
|
||||
|
||||
Handles the implementation of the group page in the help command.
|
||||
@ -749,7 +798,7 @@ class HelpCommand:
|
||||
"""
|
||||
return None
|
||||
|
||||
async def send_command_help(self, command):
|
||||
async def send_command_help(self, command: Command[Any, ..., Any]) -> None:
|
||||
"""|coro|
|
||||
|
||||
Handles the implementation of the single command page in the help command.
|
||||
@ -787,7 +836,7 @@ class HelpCommand:
|
||||
"""
|
||||
return None
|
||||
|
||||
async def prepare_help_command(self, ctx, command=None):
|
||||
async def prepare_help_command(self, ctx: Context[BotT], command: Optional[str] = None) -> None:
|
||||
"""|coro|
|
||||
|
||||
A low level method that can be used to prepare the help command
|
||||
@ -811,7 +860,7 @@ class HelpCommand:
|
||||
"""
|
||||
pass
|
||||
|
||||
async def command_callback(self, ctx, *, command=None):
|
||||
async def command_callback(self, ctx: Context[BotT], *, command: Optional[str] = None) -> None:
|
||||
"""|coro|
|
||||
|
||||
The actual implementation of the help command.
|
||||
@ -856,7 +905,7 @@ class HelpCommand:
|
||||
|
||||
for key in keys[1:]:
|
||||
try:
|
||||
found = cmd.all_commands.get(key)
|
||||
found = cmd.all_commands.get(key) # type: ignore
|
||||
except AttributeError:
|
||||
string = await maybe_coro(self.subcommand_not_found, cmd, self.remove_mentions(key))
|
||||
return await self.send_error_message(string)
|
||||
@ -908,28 +957,28 @@ class DefaultHelpCommand(HelpCommand):
|
||||
The paginator used to paginate the help command output.
|
||||
"""
|
||||
|
||||
def __init__(self, **options):
|
||||
self.width = options.pop('width', 80)
|
||||
self.indent = options.pop('indent', 2)
|
||||
self.sort_commands = options.pop('sort_commands', True)
|
||||
self.dm_help = options.pop('dm_help', False)
|
||||
self.dm_help_threshold = options.pop('dm_help_threshold', 1000)
|
||||
self.commands_heading = options.pop('commands_heading', "Commands:")
|
||||
self.no_category = options.pop('no_category', 'No Category')
|
||||
self.paginator = options.pop('paginator', None)
|
||||
def __init__(self, **options: Any) -> None:
|
||||
self.width: int = options.pop('width', 80)
|
||||
self.indent: int = options.pop('indent', 2)
|
||||
self.sort_commands: bool = options.pop('sort_commands', True)
|
||||
self.dm_help: bool = options.pop('dm_help', False)
|
||||
self.dm_help_threshold: int = options.pop('dm_help_threshold', 1000)
|
||||
self.commands_heading: str = options.pop('commands_heading', "Commands:")
|
||||
self.no_category: str = options.pop('no_category', 'No Category')
|
||||
self.paginator: Paginator = options.pop('paginator', None)
|
||||
|
||||
if self.paginator is None:
|
||||
self.paginator = Paginator()
|
||||
self.paginator: Paginator = Paginator()
|
||||
|
||||
super().__init__(**options)
|
||||
|
||||
def shorten_text(self, text):
|
||||
def shorten_text(self, text: str) -> str:
|
||||
""":class:`str`: Shortens text to fit into the :attr:`width`."""
|
||||
if len(text) > self.width:
|
||||
return text[: self.width - 3].rstrip() + '...'
|
||||
return text
|
||||
|
||||
def get_ending_note(self):
|
||||
def get_ending_note(self) -> str:
|
||||
""":class:`str`: Returns help command's ending note. This is mainly useful to override for i18n purposes."""
|
||||
command_name = self.invoked_with
|
||||
return (
|
||||
@ -937,7 +986,9 @@ class DefaultHelpCommand(HelpCommand):
|
||||
f"You can also type {self.context.clean_prefix}{command_name} category for more info on a category."
|
||||
)
|
||||
|
||||
def add_indented_commands(self, commands, *, heading, max_size=None):
|
||||
def add_indented_commands(
|
||||
self, commands: Sequence[Command[Any, ..., Any]], *, heading: str, max_size: Optional[int] = None
|
||||
) -> None:
|
||||
"""Indents a list of commands after the specified heading.
|
||||
|
||||
The formatting is added to the :attr:`paginator`.
|
||||
@ -973,13 +1024,13 @@ class DefaultHelpCommand(HelpCommand):
|
||||
entry = f'{self.indent * " "}{name:<{width}} {command.short_doc}'
|
||||
self.paginator.add_line(self.shorten_text(entry))
|
||||
|
||||
async def send_pages(self):
|
||||
async def send_pages(self) -> None:
|
||||
"""A helper utility to send the page output from :attr:`paginator` to the destination."""
|
||||
destination = self.get_destination()
|
||||
for page in self.paginator.pages:
|
||||
await destination.send(page)
|
||||
|
||||
def add_command_formatting(self, command):
|
||||
def add_command_formatting(self, command: Command[Any, ..., Any]) -> None:
|
||||
"""A utility function to format the non-indented block of commands and groups.
|
||||
|
||||
Parameters
|
||||
@ -1002,7 +1053,7 @@ class DefaultHelpCommand(HelpCommand):
|
||||
self.paginator.add_line(line)
|
||||
self.paginator.add_line()
|
||||
|
||||
def get_destination(self):
|
||||
def get_destination(self) -> discord.abc.Messageable:
|
||||
ctx = self.context
|
||||
if self.dm_help is True:
|
||||
return ctx.author
|
||||
@ -1011,11 +1062,11 @@ class DefaultHelpCommand(HelpCommand):
|
||||
else:
|
||||
return ctx.channel
|
||||
|
||||
async def prepare_help_command(self, ctx, command):
|
||||
async def prepare_help_command(self, ctx: Context[BotT], command: str) -> None:
|
||||
self.paginator.clear()
|
||||
await super().prepare_help_command(ctx, command)
|
||||
|
||||
async def send_bot_help(self, mapping):
|
||||
async def send_bot_help(self, mapping: Mapping[Optional[Cog], List[Command[Any, ..., Any]]]) -> None:
|
||||
ctx = self.context
|
||||
bot = ctx.bot
|
||||
|
||||
@ -1045,12 +1096,12 @@ class DefaultHelpCommand(HelpCommand):
|
||||
|
||||
await self.send_pages()
|
||||
|
||||
async def send_command_help(self, command):
|
||||
async def send_command_help(self, command: Command[Any, ..., Any]) -> None:
|
||||
self.add_command_formatting(command)
|
||||
self.paginator.close_page()
|
||||
await self.send_pages()
|
||||
|
||||
async def send_group_help(self, group):
|
||||
async def send_group_help(self, group: Group[Any, ..., Any]) -> None:
|
||||
self.add_command_formatting(group)
|
||||
|
||||
filtered = await self.filter_commands(group.commands, sort=self.sort_commands)
|
||||
@ -1064,7 +1115,7 @@ class DefaultHelpCommand(HelpCommand):
|
||||
|
||||
await self.send_pages()
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
async def send_cog_help(self, cog: Cog) -> None:
|
||||
if cog.description:
|
||||
self.paginator.add_line(cog.description, empty=True)
|
||||
|
||||
@ -1111,27 +1162,27 @@ class MinimalHelpCommand(HelpCommand):
|
||||
The paginator used to paginate the help command output.
|
||||
"""
|
||||
|
||||
def __init__(self, **options):
|
||||
self.sort_commands = options.pop('sort_commands', True)
|
||||
self.commands_heading = options.pop('commands_heading', "Commands")
|
||||
self.dm_help = options.pop('dm_help', False)
|
||||
self.dm_help_threshold = options.pop('dm_help_threshold', 1000)
|
||||
self.aliases_heading = options.pop('aliases_heading', "Aliases:")
|
||||
self.no_category = options.pop('no_category', 'No Category')
|
||||
self.paginator = options.pop('paginator', None)
|
||||
def __init__(self, **options: Any) -> None:
|
||||
self.sort_commands: bool = options.pop('sort_commands', True)
|
||||
self.commands_heading: str = options.pop('commands_heading', "Commands")
|
||||
self.dm_help: bool = options.pop('dm_help', False)
|
||||
self.dm_help_threshold: int = options.pop('dm_help_threshold', 1000)
|
||||
self.aliases_heading: str = options.pop('aliases_heading', "Aliases:")
|
||||
self.no_category: str = options.pop('no_category', 'No Category')
|
||||
self.paginator: Paginator = options.pop('paginator', None)
|
||||
|
||||
if self.paginator is None:
|
||||
self.paginator = Paginator(suffix=None, prefix=None)
|
||||
self.paginator: Paginator = Paginator(suffix=None, prefix=None)
|
||||
|
||||
super().__init__(**options)
|
||||
|
||||
async def send_pages(self):
|
||||
async def send_pages(self) -> None:
|
||||
"""A helper utility to send the page output from :attr:`paginator` to the destination."""
|
||||
destination = self.get_destination()
|
||||
for page in self.paginator.pages:
|
||||
await destination.send(page)
|
||||
|
||||
def get_opening_note(self):
|
||||
def get_opening_note(self) -> str:
|
||||
"""Returns help command's opening note. This is mainly useful to override for i18n purposes.
|
||||
|
||||
The default implementation returns ::
|
||||
@ -1150,10 +1201,10 @@ class MinimalHelpCommand(HelpCommand):
|
||||
f"You can also use `{self.context.clean_prefix}{command_name} [category]` for more info on a category."
|
||||
)
|
||||
|
||||
def get_command_signature(self, command):
|
||||
def get_command_signature(self, command: Command[Any, ..., Any]) -> str:
|
||||
return f'{self.context.clean_prefix}{command.qualified_name} {command.signature}'
|
||||
|
||||
def get_ending_note(self):
|
||||
def get_ending_note(self) -> str:
|
||||
"""Return the help command's ending note. This is mainly useful to override for i18n purposes.
|
||||
|
||||
The default implementation does nothing.
|
||||
@ -1163,9 +1214,9 @@ class MinimalHelpCommand(HelpCommand):
|
||||
:class:`str`
|
||||
The help command ending note.
|
||||
"""
|
||||
return None
|
||||
return ''
|
||||
|
||||
def add_bot_commands_formatting(self, commands, heading):
|
||||
def add_bot_commands_formatting(self, commands: Sequence[Command[Any, ..., Any]], heading: str) -> None:
|
||||
"""Adds the minified bot heading with commands to the output.
|
||||
|
||||
The formatting should be added to the :attr:`paginator`.
|
||||
@ -1186,7 +1237,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
self.paginator.add_line(f'__**{heading}**__')
|
||||
self.paginator.add_line(joined)
|
||||
|
||||
def add_subcommand_formatting(self, command):
|
||||
def add_subcommand_formatting(self, command: Command[Any, ..., Any]) -> None:
|
||||
"""Adds formatting information on a subcommand.
|
||||
|
||||
The formatting should be added to the :attr:`paginator`.
|
||||
@ -1202,7 +1253,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
fmt = '{0}{1} \N{EN DASH} {2}' if command.short_doc else '{0}{1}'
|
||||
self.paginator.add_line(fmt.format(self.context.clean_prefix, command.qualified_name, command.short_doc))
|
||||
|
||||
def add_aliases_formatting(self, aliases):
|
||||
def add_aliases_formatting(self, aliases: Sequence[str]) -> None:
|
||||
"""Adds the formatting information on a command's aliases.
|
||||
|
||||
The formatting should be added to the :attr:`paginator`.
|
||||
@ -1219,7 +1270,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
"""
|
||||
self.paginator.add_line(f'**{self.aliases_heading}** {", ".join(aliases)}', empty=True)
|
||||
|
||||
def add_command_formatting(self, command):
|
||||
def add_command_formatting(self, command: Command[Any, ..., Any]) -> None:
|
||||
"""A utility function to format commands and groups.
|
||||
|
||||
Parameters
|
||||
@ -1246,7 +1297,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
self.paginator.add_line(line)
|
||||
self.paginator.add_line()
|
||||
|
||||
def get_destination(self):
|
||||
def get_destination(self) -> discord.abc.Messageable:
|
||||
ctx = self.context
|
||||
if self.dm_help is True:
|
||||
return ctx.author
|
||||
@ -1255,11 +1306,11 @@ class MinimalHelpCommand(HelpCommand):
|
||||
else:
|
||||
return ctx.channel
|
||||
|
||||
async def prepare_help_command(self, ctx, command):
|
||||
async def prepare_help_command(self, ctx: Context[BotT], command: str) -> None:
|
||||
self.paginator.clear()
|
||||
await super().prepare_help_command(ctx, command)
|
||||
|
||||
async def send_bot_help(self, mapping):
|
||||
async def send_bot_help(self, mapping: Mapping[Optional[Cog], List[Command[Any, ..., Any]]]) -> None:
|
||||
ctx = self.context
|
||||
bot = ctx.bot
|
||||
|
||||
@ -1272,7 +1323,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
|
||||
no_category = f'\u200b{self.no_category}'
|
||||
|
||||
def get_category(command, *, no_category=no_category):
|
||||
def get_category(command: Command[Any, ..., Any], *, no_category: str = no_category) -> str:
|
||||
cog = command.cog
|
||||
return cog.qualified_name if cog is not None else no_category
|
||||
|
||||
@ -1290,7 +1341,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
|
||||
await self.send_pages()
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
async def send_cog_help(self, cog: Cog) -> None:
|
||||
bot = self.context.bot
|
||||
if bot.description:
|
||||
self.paginator.add_line(bot.description, empty=True)
|
||||
@ -1315,7 +1366,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
|
||||
await self.send_pages()
|
||||
|
||||
async def send_group_help(self, group):
|
||||
async def send_group_help(self, group: Group[Any, ..., Any]) -> None:
|
||||
self.add_command_formatting(group)
|
||||
|
||||
filtered = await self.filter_commands(group.commands, sort=self.sort_commands)
|
||||
@ -1335,7 +1386,7 @@ class MinimalHelpCommand(HelpCommand):
|
||||
|
||||
await self.send_pages()
|
||||
|
||||
async def send_command_help(self, command):
|
||||
async def send_command_help(self, command: Command[Any, ..., Any]) -> None:
|
||||
self.add_command_formatting(command)
|
||||
self.paginator.close_page()
|
||||
await self.send_pages()
|
||||
|
Reference in New Issue
Block a user