mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
Add public positive_int and finite_float converters (#5969)
Co-authored-by: Kreusada <67752638+Kreusada@users.noreply.github.com>
This commit is contained in:
parent
fa305cb060
commit
eafbb06756
@ -7,13 +7,13 @@ import discord
|
|||||||
|
|
||||||
from redbot.core import commands, Config
|
from redbot.core import commands, Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import RawUserIdConverter
|
from redbot.core.commands import positive_int, RawUserIdConverter
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils.chat_formatting import humanize_number
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
from redbot.core.utils.mod import slow_deletion, mass_purge
|
from redbot.core.utils.mod import slow_deletion, mass_purge
|
||||||
from redbot.core.utils.predicates import MessagePredicate
|
from redbot.core.utils.predicates import MessagePredicate
|
||||||
from .checks import check_self_permissions
|
from .checks import check_self_permissions
|
||||||
from .converters import PositiveInt, RawMessageIds, positive_int
|
from .converters import RawMessageIds
|
||||||
|
|
||||||
_ = Translator("Cleanup", __file__)
|
_ = Translator("Cleanup", __file__)
|
||||||
|
|
||||||
@ -78,9 +78,9 @@ class Cleanup(commands.Cog):
|
|||||||
channel: Union[
|
channel: Union[
|
||||||
discord.TextChannel, discord.VoiceChannel, discord.DMChannel, discord.Thread
|
discord.TextChannel, discord.VoiceChannel, discord.DMChannel, discord.Thread
|
||||||
],
|
],
|
||||||
number: Optional[PositiveInt] = None,
|
number: Optional[int] = None,
|
||||||
check: Callable[[discord.Message], bool] = lambda x: True,
|
check: Callable[[discord.Message], bool] = lambda x: True,
|
||||||
limit: Optional[PositiveInt] = None,
|
limit: Optional[int] = None,
|
||||||
before: Union[discord.Message, datetime] = None,
|
before: Union[discord.Message, datetime] = None,
|
||||||
after: Union[discord.Message, datetime] = None,
|
after: Union[discord.Message, datetime] = None,
|
||||||
delete_pinned: bool = False,
|
delete_pinned: bool = False,
|
||||||
@ -684,9 +684,7 @@ class Cleanup(commands.Cog):
|
|||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.mod_or_permissions(manage_messages=True)
|
@commands.mod_or_permissions(manage_messages=True)
|
||||||
@commands.bot_has_permissions(manage_messages=True)
|
@commands.bot_has_permissions(manage_messages=True)
|
||||||
async def cleanup_duplicates(
|
async def cleanup_duplicates(self, ctx: commands.Context, number: positive_int = 50):
|
||||||
self, ctx: commands.Context, number: positive_int = PositiveInt(50)
|
|
||||||
):
|
|
||||||
"""Deletes duplicate messages in the channel from the last X messages and keeps only one copy.
|
"""Deletes duplicate messages in the channel from the last X messages and keeps only one copy.
|
||||||
|
|
||||||
Defaults to 50.
|
Defaults to 50.
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
from typing import NewType, TYPE_CHECKING
|
|
||||||
|
|
||||||
from redbot.core.commands import BadArgument, Context, Converter
|
from redbot.core.commands import BadArgument, Context, Converter
|
||||||
from redbot.core.i18n import Translator
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import inline
|
|
||||||
|
|
||||||
_ = Translator("Cleanup", __file__)
|
_ = Translator("Cleanup", __file__)
|
||||||
|
|
||||||
@ -15,18 +12,3 @@ class RawMessageIds(Converter):
|
|||||||
return int(argument)
|
return int(argument)
|
||||||
|
|
||||||
raise BadArgument(_("{} doesn't look like a valid message ID.").format(argument))
|
raise BadArgument(_("{} doesn't look like a valid message ID.").format(argument))
|
||||||
|
|
||||||
|
|
||||||
PositiveInt = NewType("PositiveInt", int)
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
positive_int = PositiveInt
|
|
||||||
else:
|
|
||||||
|
|
||||||
def positive_int(arg: str) -> int:
|
|
||||||
try:
|
|
||||||
ret = int(arg)
|
|
||||||
except ValueError:
|
|
||||||
raise BadArgument(_("{arg} is not an integer.").format(arg=inline(arg)))
|
|
||||||
if ret <= 0:
|
|
||||||
raise BadArgument(_("{arg} is not a positive integer.").format(arg=inline(arg)))
|
|
||||||
return ret
|
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
from typing import NewType, TYPE_CHECKING
|
|
||||||
|
|
||||||
from redbot.core.commands import BadArgument
|
|
||||||
from redbot.core.i18n import Translator
|
|
||||||
from redbot.core.utils.chat_formatting import inline
|
|
||||||
|
|
||||||
_ = Translator("Economy", __file__)
|
|
||||||
|
|
||||||
# Duplicate of redbot.cogs.cleanup.converters.PositiveInt
|
|
||||||
PositiveInt = NewType("PositiveInt", int)
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
positive_int = PositiveInt
|
|
||||||
else:
|
|
||||||
|
|
||||||
def positive_int(arg: str) -> int:
|
|
||||||
try:
|
|
||||||
ret = int(arg)
|
|
||||||
except ValueError:
|
|
||||||
raise BadArgument(_("{arg} is not an integer.").format(arg=inline(arg)))
|
|
||||||
if ret <= 0:
|
|
||||||
raise BadArgument(_("{arg} is not a positive integer.").format(arg=inline(arg)))
|
|
||||||
return ret
|
|
||||||
@ -5,18 +5,17 @@ from collections import defaultdict, deque, namedtuple
|
|||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import cast, Iterable, Union, Literal
|
from typing import cast, Iterable, Literal
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
from redbot.core import Config, bank, commands, errors
|
from redbot.core import Config, bank, commands, errors
|
||||||
from redbot.core.commands.converter import TimedeltaConverter
|
from redbot.core.commands.converter import TimedeltaConverter, positive_int
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import box, humanize_number
|
from redbot.core.utils.chat_formatting import box, humanize_number
|
||||||
from redbot.core.utils.menus import close_menu, menu
|
from redbot.core.utils.menus import menu
|
||||||
from .converters import positive_int
|
|
||||||
|
|
||||||
T_ = Translator("Economy", __file__)
|
T_ = Translator("Economy", __file__)
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import pkgutil
|
|||||||
from importlib import import_module, invalidate_caches
|
from importlib import import_module, invalidate_caches
|
||||||
from importlib.machinery import ModuleSpec
|
from importlib.machinery import ModuleSpec
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Union, List, Optional
|
from typing import Union, List, Optional
|
||||||
|
|
||||||
import redbot.cogs
|
import redbot.cogs
|
||||||
from redbot.core.commands import BadArgument
|
from redbot.core.commands import positive_int
|
||||||
from redbot.core.utils import deduplicate_iterables
|
from redbot.core.utils import deduplicate_iterables
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
@ -21,21 +21,6 @@ from .utils.chat_formatting import box, pagify, humanize_list, inline
|
|||||||
__all__ = ["CogManager"]
|
__all__ = ["CogManager"]
|
||||||
|
|
||||||
|
|
||||||
# Duplicate of redbot.cogs.cleanup.converters.positive_int
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
positive_int = int
|
|
||||||
else:
|
|
||||||
|
|
||||||
def positive_int(arg: str) -> int:
|
|
||||||
try:
|
|
||||||
ret = int(arg)
|
|
||||||
except ValueError:
|
|
||||||
raise BadArgument(_("{arg} is not an integer.").format(arg=inline(arg)))
|
|
||||||
if ret <= 0:
|
|
||||||
raise BadArgument(_("{arg} is not a positive integer.").format(arg=inline(arg)))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
class NoSuchCog(ImportError):
|
class NoSuchCog(ImportError):
|
||||||
"""Thrown when a cog is missing.
|
"""Thrown when a cog is missing.
|
||||||
|
|
||||||
|
|||||||
@ -28,10 +28,12 @@ from .converter import (
|
|||||||
DictConverter as DictConverter,
|
DictConverter as DictConverter,
|
||||||
RelativedeltaConverter as RelativedeltaConverter,
|
RelativedeltaConverter as RelativedeltaConverter,
|
||||||
TimedeltaConverter as TimedeltaConverter,
|
TimedeltaConverter as TimedeltaConverter,
|
||||||
|
finite_float as finite_float,
|
||||||
get_dict_converter as get_dict_converter,
|
get_dict_converter as get_dict_converter,
|
||||||
get_timedelta_converter as get_timedelta_converter,
|
get_timedelta_converter as get_timedelta_converter,
|
||||||
parse_relativedelta as parse_relativedelta,
|
parse_relativedelta as parse_relativedelta,
|
||||||
parse_timedelta as parse_timedelta,
|
parse_timedelta as parse_timedelta,
|
||||||
|
positive_int as positive_int,
|
||||||
NoParseOptional as NoParseOptional,
|
NoParseOptional as NoParseOptional,
|
||||||
UserInputOptional as UserInputOptional,
|
UserInputOptional as UserInputOptional,
|
||||||
RawUserIdConverter as RawUserIdConverter,
|
RawUserIdConverter as RawUserIdConverter,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ This module contains useful functions and classes for command argument conversio
|
|||||||
Some of the converters within are included provisionally and are marked as such.
|
Some of the converters within are included provisionally and are marked as such.
|
||||||
"""
|
"""
|
||||||
import functools
|
import functools
|
||||||
|
import math
|
||||||
import re
|
import re
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
@ -37,10 +38,12 @@ __all__ = [
|
|||||||
"NoParseOptional",
|
"NoParseOptional",
|
||||||
"RelativedeltaConverter",
|
"RelativedeltaConverter",
|
||||||
"TimedeltaConverter",
|
"TimedeltaConverter",
|
||||||
|
"finite_float",
|
||||||
"get_dict_converter",
|
"get_dict_converter",
|
||||||
"get_timedelta_converter",
|
"get_timedelta_converter",
|
||||||
"parse_relativedelta",
|
"parse_relativedelta",
|
||||||
"parse_timedelta",
|
"parse_timedelta",
|
||||||
|
"positive_int",
|
||||||
"CommandConverter",
|
"CommandConverter",
|
||||||
"CogConverter",
|
"CogConverter",
|
||||||
]
|
]
|
||||||
@ -233,6 +236,26 @@ class RawUserIdConverter(dpy_commands.Converter):
|
|||||||
# which is *not* for type checking for the actual implementation
|
# which is *not* for type checking for the actual implementation
|
||||||
# and ensure the lies stay correct for how the object should look as a typehint
|
# and ensure the lies stay correct for how the object should look as a typehint
|
||||||
|
|
||||||
|
positive_int = dpy_commands.Range[int, 0, None]
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
finite_float = float
|
||||||
|
else:
|
||||||
|
|
||||||
|
def finite_float(arg: str) -> float:
|
||||||
|
"""
|
||||||
|
This converts a user provided string into a finite float.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
ret = float(arg)
|
||||||
|
except ValueError:
|
||||||
|
raise BadArgument(_("`{arg}` is not a number.").format(arg=arg))
|
||||||
|
if not math.isfinite(ret):
|
||||||
|
raise BadArgument(_("`{arg}` is not a finite number.").format(arg=ret))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
DictConverter = Dict[str, str]
|
DictConverter = Dict[str, str]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import asyncio
|
|||||||
import contextlib
|
import contextlib
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
@ -17,12 +16,9 @@ from redbot.core import data_manager
|
|||||||
from redbot.core.commands import RedHelpFormatter, HelpSettings
|
from redbot.core.commands import RedHelpFormatter, HelpSettings
|
||||||
from redbot.core.i18n import (
|
from redbot.core.i18n import (
|
||||||
Translator,
|
Translator,
|
||||||
set_contextual_locale,
|
|
||||||
set_contextual_regional_format,
|
|
||||||
set_contextual_locales_from_guild,
|
set_contextual_locales_from_guild,
|
||||||
)
|
)
|
||||||
from .utils import AsyncIter
|
from .. import __version__ as red_version, version_info as red_version_info
|
||||||
from .. import __version__ as red_version, version_info as red_version_info, VersionInfo
|
|
||||||
from . import commands
|
from . import commands
|
||||||
from .config import get_latest_confs
|
from .config import get_latest_confs
|
||||||
from .utils._internal_utils import (
|
from .utils._internal_utils import (
|
||||||
@ -32,7 +28,7 @@ from .utils._internal_utils import (
|
|||||||
fetch_latest_red_version_info,
|
fetch_latest_red_version_info,
|
||||||
send_to_owners_with_prefix_replaced,
|
send_to_owners_with_prefix_replaced,
|
||||||
)
|
)
|
||||||
from .utils.chat_formatting import inline, format_perms_list, humanize_timedelta
|
from .utils.chat_formatting import inline, format_perms_list
|
||||||
|
|
||||||
import rich
|
import rich
|
||||||
from rich import box
|
from rich import box
|
||||||
@ -229,6 +225,8 @@ def init_events(bot, cli_flags):
|
|||||||
return
|
return
|
||||||
if not isinstance(error, commands.CommandNotFound):
|
if not isinstance(error, commands.CommandNotFound):
|
||||||
asyncio.create_task(bot._delete_delay(ctx))
|
asyncio.create_task(bot._delete_delay(ctx))
|
||||||
|
converter = getattr(ctx.current_parameter, "converter", None)
|
||||||
|
argument = ctx.current_argument
|
||||||
|
|
||||||
if isinstance(error, commands.MissingRequiredArgument):
|
if isinstance(error, commands.MissingRequiredArgument):
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
@ -241,10 +239,112 @@ def init_events(bot, cli_flags):
|
|||||||
await ctx.send(msg)
|
await ctx.send(msg)
|
||||||
if error.send_cmd_help:
|
if error.send_cmd_help:
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
|
elif isinstance(error, commands.RangeError):
|
||||||
|
if isinstance(error.value, int):
|
||||||
|
if error.minimum == 0 and error.maximum is None:
|
||||||
|
message = _("Argument `{parameter_name}` must be a positive integer.")
|
||||||
|
elif error.minimum is None and error.maximum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif error.minimum is not None and error.maximum is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer no less than {minimum}."
|
||||||
|
)
|
||||||
|
elif error.maximum is not None and error.minimum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
elif isinstance(error.value, float):
|
||||||
|
if error.minimum == 0 and error.maximum is None:
|
||||||
|
message = _("Argument `{parameter_name}` must be a positive number.")
|
||||||
|
elif error.minimum is None and error.maximum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif error.minimum is not None and error.maximum is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number no less than {maximum}."
|
||||||
|
)
|
||||||
|
elif error.maximum is not None and error.minimum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
elif isinstance(error.value, str):
|
||||||
|
if error.minimum is None and error.maximum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif error.minimum is not None and error.maximum is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of no less than {minimum}."
|
||||||
|
)
|
||||||
|
elif error.maximum is not None and error.minimum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
await ctx.send(
|
||||||
|
message.format(
|
||||||
|
maximum=error.maximum,
|
||||||
|
minimum=error.minimum,
|
||||||
|
parameter_name=ctx.current_parameter.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
elif isinstance(error, commands.BadArgument):
|
elif isinstance(error, commands.BadArgument):
|
||||||
|
if isinstance(converter, commands.Range):
|
||||||
|
if converter.annotation is int:
|
||||||
|
if converter.min == 0 and converter.max is None:
|
||||||
|
message = _("Argument `{parameter_name}` must be a positive integer.")
|
||||||
|
elif converter.min is None and converter.max is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif converter.min is not None and converter.max is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer no less than {minimum}."
|
||||||
|
)
|
||||||
|
elif converter.max is not None and converter.min is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be an integer between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
elif converter.annotation is float:
|
||||||
|
if converter.min == 0 and converter.max is None:
|
||||||
|
message = _("Argument `{parameter_name}` must be a positive number.")
|
||||||
|
elif converter.min is None and converter.max is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif converter.min is not None and converter.max is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number no less than {minimum}."
|
||||||
|
)
|
||||||
|
elif converter.max is not None and converter.min is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a number between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
elif converter.annotation is str:
|
||||||
|
if error.minimum is None and error.maximum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of no more than {maximum}."
|
||||||
|
)
|
||||||
|
elif error.minimum is not None and error.maximum is None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of no less than {minimum}."
|
||||||
|
)
|
||||||
|
elif error.maximum is not None and error.minimum is not None:
|
||||||
|
message = _(
|
||||||
|
"Argument `{parameter_name}` must be a string with a length of between {minimum} and {maximum}."
|
||||||
|
)
|
||||||
|
await ctx.send(
|
||||||
|
message.format(
|
||||||
|
maximum=converter.max,
|
||||||
|
minimum=converter.min,
|
||||||
|
parameter_name=ctx.current_parameter.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
if isinstance(error.__cause__, ValueError):
|
if isinstance(error.__cause__, ValueError):
|
||||||
converter = ctx.current_parameter.converter
|
|
||||||
argument = ctx.current_argument
|
|
||||||
if converter is int:
|
if converter is int:
|
||||||
await ctx.send(_('"{argument}" is not an integer.').format(argument=argument))
|
await ctx.send(_('"{argument}" is not an integer.').format(argument=argument))
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user