Browse Source

Refactor human_join into its own private helper function

pull/9594/head
Rapptz 2 years ago
parent
commit
f617d01eee
  1. 21
      discord/app_commands/errors.py
  2. 39
      discord/ext/commands/errors.py
  3. 16
      discord/ui/select.py
  4. 14
      discord/utils.py

21
discord/app_commands/errors.py

@ -28,6 +28,7 @@ from typing import Any, TYPE_CHECKING, List, Optional, Sequence, Union
from ..enums import AppCommandOptionType, AppCommandType, Locale
from ..errors import DiscordException, HTTPException, _flatten_error_dict
from ..utils import _human_join
__all__ = (
'AppCommandError',
@ -242,13 +243,7 @@ class MissingAnyRole(CheckFailure):
def __init__(self, missing_roles: SnowflakeList) -> None:
self.missing_roles: SnowflakeList = missing_roles
missing = [f"'{role}'" for role in missing_roles]
if len(missing) > 2:
fmt = '{}, or {}'.format(', '.join(missing[:-1]), missing[-1])
else:
fmt = ' or '.join(missing)
fmt = _human_join([f"'{role}'" for role in missing_roles])
message = f'You are missing at least one of the required roles: {fmt}'
super().__init__(message)
@ -271,11 +266,7 @@ class MissingPermissions(CheckFailure):
self.missing_permissions: List[str] = missing_permissions
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions]
if len(missing) > 2:
fmt = '{}, and {}'.format(", ".join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
fmt = _human_join(missing, final='and')
message = f'You are missing {fmt} permission(s) to run this command.'
super().__init__(message, *args)
@ -298,11 +289,7 @@ class BotMissingPermissions(CheckFailure):
self.missing_permissions: List[str] = missing_permissions
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions]
if len(missing) > 2:
fmt = '{}, and {}'.format(", ".join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
fmt = _human_join(missing, final='and')
message = f'Bot requires {fmt} permission(s) to run this command.'
super().__init__(message, *args)

39
discord/ext/commands/errors.py

@ -27,6 +27,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple, Union
from discord.errors import ClientException, DiscordException
from discord.utils import _human_join
if TYPE_CHECKING:
from discord.abc import GuildChannel
@ -758,12 +759,7 @@ class MissingAnyRole(CheckFailure):
self.missing_roles: SnowflakeList = missing_roles
missing = [f"'{role}'" for role in missing_roles]
if len(missing) > 2:
fmt = '{}, or {}'.format(', '.join(missing[:-1]), missing[-1])
else:
fmt = ' or '.join(missing)
fmt = _human_join(missing)
message = f'You are missing at least one of the required roles: {fmt}'
super().__init__(message)
@ -788,12 +784,7 @@ class BotMissingAnyRole(CheckFailure):
self.missing_roles: SnowflakeList = missing_roles
missing = [f"'{role}'" for role in missing_roles]
if len(missing) > 2:
fmt = '{}, or {}'.format(', '.join(missing[:-1]), missing[-1])
else:
fmt = ' or '.join(missing)
fmt = _human_join(missing)
message = f'Bot is missing at least one of the required roles: {fmt}'
super().__init__(message)
@ -832,11 +823,7 @@ class MissingPermissions(CheckFailure):
self.missing_permissions: List[str] = missing_permissions
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions]
if len(missing) > 2:
fmt = '{}, and {}'.format(', '.join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
fmt = _human_join(missing, final='and')
message = f'You are missing {fmt} permission(s) to run this command.'
super().__init__(message, *args)
@ -857,11 +844,7 @@ class BotMissingPermissions(CheckFailure):
self.missing_permissions: List[str] = missing_permissions
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions]
if len(missing) > 2:
fmt = '{}, and {}'.format(', '.join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
fmt = _human_join(missing, final='and')
message = f'Bot requires {fmt} permission(s) to run this command.'
super().__init__(message, *args)
@ -896,11 +879,7 @@ class BadUnionArgument(UserInputError):
return x.__class__.__name__
to_string = [_get_name(x) for x in converters]
if len(to_string) > 2:
fmt = '{}, or {}'.format(', '.join(to_string[:-1]), to_string[-1])
else:
fmt = ' or '.join(to_string)
fmt = _human_join(to_string)
super().__init__(f'Could not convert "{param.displayed_name or param.name}" into {fmt}.')
@ -933,11 +912,7 @@ class BadLiteralArgument(UserInputError):
self.argument: str = argument
to_string = [repr(l) for l in literals]
if len(to_string) > 2:
fmt = '{}, or {}'.format(', '.join(to_string[:-1]), to_string[-1])
else:
fmt = ' or '.join(to_string)
fmt = _human_join(to_string)
super().__init__(f'Could not convert "{param.displayed_name or param.name}" into the literal {fmt}.')

16
discord/ui/select.py

@ -45,7 +45,7 @@ from .item import Item, ItemCallbackType
from ..enums import ChannelType, ComponentType, SelectDefaultValueType
from ..partial_emoji import PartialEmoji
from ..emoji import Emoji
from ..utils import MISSING
from ..utils import MISSING, _human_join
from ..components import (
SelectOption,
SelectMenu,
@ -160,15 +160,7 @@ def _handle_select_defaults(
object_type = obj.__class__ if not isinstance(obj, Object) else obj.type
if not _is_valid_object_type(object_type, component_type, type_to_supported_classes):
# TODO: split this into a util function
supported_classes = [c.__name__ for c in type_to_supported_classes[component_type]]
if len(supported_classes) > 2:
supported_classes = ', '.join(supported_classes[:-1]) + f', or {supported_classes[-1]}'
elif len(supported_classes) == 2:
supported_classes = f'{supported_classes[0]} or {supported_classes[1]}'
else:
supported_classes = supported_classes[0]
supported_classes = _human_join([c.__name__ for c in type_to_supported_classes[component_type]])
raise TypeError(f'Expected an instance of {supported_classes} not {object_type.__name__}')
if object_type is Object:
@ -1042,8 +1034,8 @@ def select(
raise TypeError('select function must be a coroutine function')
callback_cls = getattr(cls, '__origin__', cls)
if not issubclass(callback_cls, BaseSelect):
supported_classes = ", ".join(["ChannelSelect", "MentionableSelect", "RoleSelect", "Select", "UserSelect"])
raise TypeError(f'cls must be one of {supported_classes} or a subclass of one of them, not {cls!r}.')
supported_classes = ', '.join(['ChannelSelect', 'MentionableSelect', 'RoleSelect', 'Select', 'UserSelect'])
raise TypeError(f'cls must be one of {supported_classes} or a subclass of one of them, not {cls.__name__}.')
func.__discord_ui_model_type__ = callback_cls
func.__discord_ui_model_kwargs__ = {

14
discord/utils.py

@ -1380,3 +1380,17 @@ CAMEL_CASE_REGEX = re.compile(r'(?<!^)(?=[A-Z])')
def _to_kebab_case(text: str) -> str:
return CAMEL_CASE_REGEX.sub('-', text).lower()
def _human_join(seq: Sequence[str], /, *, delimiter: str = ', ', final: str = 'or') -> str:
size = len(seq)
if size == 0:
return ''
if size == 1:
return seq[0]
if size == 2:
return f'{seq[0]} {final} {seq[1]}'
return delimiter.join(seq[:-1]) + f' {final} {seq[-1]}'

Loading…
Cancel
Save