Browse Source

[commands] Add support for Range[str, ...]

pull/8200/head
Rapptz 3 years ago
parent
commit
b5392ea0f1
  1. 27
      discord/ext/commands/converter.py
  2. 14
      discord/ext/commands/errors.py

27
discord/ext/commands/converter.py

@ -1041,8 +1041,8 @@ if TYPE_CHECKING:
else:
class Range:
"""A special converter that can be applied to a parameter to require a numeric type
to fit within the range provided.
"""A special converter that can be applied to a parameter to require a numeric
or string type to fit within the range provided.
During type checking time this is equivalent to :obj:`typing.Annotated` so type checkers understand
the intent of the code.
@ -1055,6 +1055,9 @@ else:
Inside a :class:`HybridCommand` this functions equivalently to :class:`discord.app_commands.Range`.
If the converter fails then :class:`~.ext.commands.RangeError` is raised to
the appropriate error handlers.
.. versionadded:: 2.0
Examples
@ -1079,8 +1082,11 @@ else:
self.max: Optional[Union[int, float]] = max
async def convert(self, ctx: Context[BotT], value: str) -> Union[int, float]:
converted = self.annotation(value)
if (self.min is not None and converted < self.min) or (self.max is not None and converted > self.max):
count = converted = self.annotation(value)
if self.annotation is str:
count = len(value)
if (self.min is not None and count < self.min) or (self.max is not None and count > self.max):
raise RangeError(converted, minimum=self.min, maximum=self.max)
return converted
@ -1108,13 +1114,18 @@ else:
if type(min) != type(max):
raise TypeError('Both min and max in Range must be the same type')
if annotation not in (int, float):
raise TypeError(f'expected int or float as range type, received {annotation!r} instead')
if annotation not in (int, float, str):
raise TypeError(f'expected int, float, or str as range type, received {annotation!r} instead')
if annotation in (str, int):
cast = int
else:
cast = float
return cls(
annotation=annotation,
min=annotation(min) if min is not None else None,
max=annotation(max) if max is not None else None,
min=cast(min) if min is not None else None,
max=cast(max) if max is not None else None,
)

14
discord/ext/commands/errors.py

@ -594,17 +594,17 @@ class RangeError(BadArgument):
The minimum value expected or ``None`` if there wasn't one
maximum: Optional[Union[:class:`int`, :class:`float`]]
The maximum value expected or ``None`` if there wasn't one
value: Union[:class:`int`, :class:`float`]
value: Union[:class:`int`, :class:`float`, :class:`str`]
The value that was out of range.
"""
def __init__(
self,
value: Union[int, float],
value: Union[int, float, str],
minimum: Optional[Union[int, float]],
maximum: Optional[Union[int, float]],
) -> None:
self.value: Union[int, float] = value
self.value: Union[int, float, str] = value
self.minimum: Optional[Union[int, float]] = minimum
self.maximum: Optional[Union[int, float]] = maximum
@ -616,6 +616,14 @@ class RangeError(BadArgument):
elif maximum is not None and minimum is not None:
label = f'between {minimum} and {maximum}'
if label and isinstance(value, str):
label += ' characters'
count = len(value)
if count == 1:
value = '1 character'
else:
value = f'{count} characters'
super().__init__(f'value must be {label} but received {value}')

Loading…
Cancel
Save