diff --git a/redbot/__main__.py b/redbot/__main__.py index a5666dca6..9cf8bdb98 100644 --- a/redbot/__main__.py +++ b/redbot/__main__.py @@ -181,7 +181,7 @@ async def _edit_prefix(red, prefix, no_prompt): async def _edit_owner(red, owner, no_prompt): if owner: - if not (15 <= len(str(owner)) <= 21): + if not (15 <= len(str(owner)) <= 20): print( "The provided owner id doesn't look like a valid Discord user id." " Instance's owner will remain unchanged." @@ -199,7 +199,7 @@ async def _edit_owner(red, owner, no_prompt): print("Please enter a Discord user id for new owner:") while True: owner_id = input("> ").strip() - if not (15 <= len(owner_id) <= 21 and owner_id.isdecimal()): + if not (15 <= len(owner_id) <= 20 and owner_id.isdecimal()): print("That doesn't look like a valid Discord user id.") continue owner_id = int(owner_id) @@ -434,7 +434,7 @@ async def shutdown_handler(red, signal_type=None, exit_code=None): red._shutdown_mode = exit_code try: - await red.logout() + await red.close() finally: # Then cancels all outstanding tasks other than ourselves pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] diff --git a/redbot/cogs/audio/converters.py b/redbot/cogs/audio/converters.py index 9558e3dc1..ea5ce66bf 100644 --- a/redbot/cogs/audio/converters.py +++ b/redbot/cogs/audio/converters.py @@ -58,7 +58,7 @@ Guild must be a valid version of one of the following: _ = T_ -MENTION_RE: Final[Pattern] = re.compile(r"^?$") +MENTION_RE: Final[Pattern] = re.compile(r"^?$") def _match_id(arg: str) -> Optional[int]: diff --git a/redbot/cogs/mod/converters.py b/redbot/cogs/mod/converters.py index 9bb9da7df..8235ee04a 100644 --- a/redbot/cogs/mod/converters.py +++ b/redbot/cogs/mod/converters.py @@ -4,8 +4,8 @@ from redbot.core.i18n import Translator _ = Translator("Mod", __file__) -_id_regex = re.compile(r"([0-9]{15,21})$") -_mention_regex = re.compile(r"<@!?([0-9]{15,21})>$") +_id_regex = re.compile(r"([0-9]{15,20})$") +_mention_regex = re.compile(r"<@!?([0-9]{15,20})>$") class RawUserIds(Converter): diff --git a/redbot/cogs/permissions/converters.py b/redbot/cogs/permissions/converters.py index a19a6a6ba..acd6cc697 100644 --- a/redbot/cogs/permissions/converters.py +++ b/redbot/cogs/permissions/converters.py @@ -10,7 +10,7 @@ from redbot.core.utils import AsyncIter _ = Translator("PermissionsConverters", __file__) -MENTION_RE = re.compile(r"^?$") +MENTION_RE = re.compile(r"^?$") def _match_id(arg: str) -> Optional[int]: diff --git a/redbot/core/bot.py b/redbot/core/bot.py index 334ddd3b3..d0791d554 100644 --- a/redbot/core/bot.py +++ b/redbot/core/bot.py @@ -1664,9 +1664,9 @@ class RedBase( await asyncio.sleep(delay) await _delete_helper(message) - async def logout(self): + async def close(self): """Logs out of Discord and closes all connections.""" - await super().logout() + await super().close() await drivers.get_driver_class().teardown() try: if self.rpc_enabled: @@ -1691,7 +1691,7 @@ class RedBase( else: self._shutdown_mode = ExitCodes.RESTART - await self.logout() + await self.close() sys.exit(self._shutdown_mode) async def _core_data_deletion( diff --git a/redbot/core/commands/__init__.py b/redbot/core/commands/__init__.py index e2f5cf452..afb48b2c3 100644 --- a/redbot/core/commands/__init__.py +++ b/redbot/core/commands/__init__.py @@ -21,7 +21,6 @@ from .commands import ( from .context import Context as Context, GuildContext as GuildContext, DMContext as DMContext from .converter import ( DictConverter as DictConverter, - GuildConverter as GuildConverter, TimedeltaConverter as TimedeltaConverter, get_dict_converter as get_dict_converter, get_timedelta_converter as get_timedelta_converter, @@ -84,6 +83,7 @@ from ._dpy_reimplements import ( from discord.ext.commands import ( BadArgument as BadArgument, EmojiConverter as EmojiConverter, + GuildConverter as GuildConverter, InvalidEndOfQuotedStringError as InvalidEndOfQuotedStringError, MemberConverter as MemberConverter, BotMissingRole as BotMissingRole, @@ -103,6 +103,7 @@ from discord.ext.commands import ( ExtensionError as ExtensionError, Cooldown as Cooldown, CheckFailure as CheckFailure, + PartialMessageConverter as PartialMessageConverter, MessageConverter as MessageConverter, MissingPermissions as MissingPermissions, BadUnionArgument as BadUnionArgument, @@ -130,6 +131,8 @@ from discord.ext.commands import ( ColourConverter as ColourConverter, ColorConverter as ColorConverter, VoiceChannelConverter as VoiceChannelConverter, + StageChannelConverter as StageChannelConverter, + StoreChannelConverter as StoreChannelConverter, NSFWChannelRequired as NSFWChannelRequired, IDConverter as IDConverter, MissingRequiredArgument as MissingRequiredArgument, @@ -147,6 +150,7 @@ from discord.ext.commands import ( MaxConcurrencyReached as MaxConcurrencyReached, bot_has_guild_permissions as bot_has_guild_permissions, CommandRegistrationError as CommandRegistrationError, + GuildNotFound as GuildNotFound, MessageNotFound as MessageNotFound, MemberNotFound as MemberNotFound, UserNotFound as UserNotFound, diff --git a/redbot/core/commands/converter.py b/redbot/core/commands/converter.py index 3bd335e0e..820bbcc04 100644 --- a/redbot/core/commands/converter.py +++ b/redbot/core/commands/converter.py @@ -35,7 +35,6 @@ if TYPE_CHECKING: __all__ = [ "DictConverter", - "GuildConverter", "UserInputOptional", "NoParseOptional", "TimedeltaConverter", @@ -47,7 +46,7 @@ __all__ = [ _ = Translator("commands.converter", __file__) -ID_REGEX = re.compile(r"([0-9]{15,21})") +ID_REGEX = re.compile(r"([0-9]{15,20})") # Taken with permission from @@ -134,29 +133,46 @@ def parse_timedelta( return None -class GuildConverter(discord.Guild): +class _GuildConverter(discord.Guild): """Converts to a `discord.Guild` object. The lookup strategy is as follows (in order): 1. Lookup by ID. 2. Lookup by name. + + .. deprecated-removed:: 3.4.8 60 + ``GuildConverter`` is now only provided within ``redbot.core.commands`` namespace. """ @classmethod async def convert(cls, ctx: "Context", argument: str) -> discord.Guild: - match = ID_REGEX.fullmatch(argument) + return await dpy_commands.GuildConverter().convert(ctx, argument) - if match is None: - ret = discord.utils.get(ctx.bot.guilds, name=argument) - else: - guild_id = int(match.group(1)) - ret = ctx.bot.get_guild(guild_id) - if ret is None: - raise BadArgument(_('Server "{name}" not found.').format(name=argument)) +_GuildConverter.__name__ = "GuildConverter" - return ret + +def __getattr__(name: str, *, stacklevel: int = 2) -> Any: + # Let me just say it one more time... This is awesome! (PEP-562) + if name == "GuildConverter": + # let's not waste time on importing this when we don't need it + # (and let's not put in the public API) + from redbot.core.utils._internal_utils import deprecated_removed + + deprecated_removed( + "`GuildConverter` from `redbot.core.commands.converter` namespace", + "3.4.8", + 60, + "Use `GuildConverter` from `redbot.core.commands` namespace instead.", + stacklevel=2, + ) + return globals()["_GuildConverter"] + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +def __dir__() -> List[str]: + return [*globals().keys(), "GuildConverter"] # Below this line are a lot of lies for mypy about things that *end up* correct when diff --git a/redbot/core/commands/help.py b/redbot/core/commands/help.py index e98019914..f6a80b5f9 100644 --- a/redbot/core/commands/help.py +++ b/redbot/core/commands/help.py @@ -275,6 +275,20 @@ class RedHelpFormatter(HelpFormatterABC): "You can also type {ctx.clean_prefix}help for more info on a category." ).format(ctx=ctx) + @staticmethod + def get_command_signature(ctx: Context, command: commands.Command) -> str: + parent = command.parent + 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_sig = (" ".join(reversed(entries)) + " ") if entries else "" + + return f"{ctx.clean_prefix}{parent_sig}{command.name} {command.signature}" + async def format_command_help( self, ctx: Context, obj: commands.Command, help_settings: HelpSettings ): @@ -300,9 +314,9 @@ class RedHelpFormatter(HelpFormatterABC): description = command.description or "" tagline = (help_settings.tagline) or self.get_default_tagline(ctx) - signature = _( - "Syntax: {ctx.clean_prefix}{command.qualified_name} {command.signature}" - ).format(ctx=ctx, command=command) + signature = _("Syntax: {command_signature}").format( + command_signature=self.get_command_signature(ctx, command) + ) aliases = command.aliases if help_settings.show_aliases and aliases: diff --git a/redbot/core/commands/requires.py b/redbot/core/commands/requires.py index 645e074bb..0b66afbca 100644 --- a/redbot/core/commands/requires.py +++ b/redbot/core/commands/requires.py @@ -28,7 +28,6 @@ from typing import ( import discord from discord.ext.commands import check -from .converter import GuildConverter from .errors import BotMissingPermissions if TYPE_CHECKING: @@ -70,7 +69,7 @@ GlobalPermissionModel = Union[ discord.TextChannel, discord.CategoryChannel, discord.Role, - GuildConverter, # Unfortunately this will have to do for now + discord.Guild, ] GuildPermissionModel = Union[ discord.Member, @@ -78,7 +77,7 @@ GuildPermissionModel = Union[ discord.TextChannel, discord.CategoryChannel, discord.Role, - GuildConverter, + discord.Guild, ] PermissionModel = Union[GlobalPermissionModel, GuildPermissionModel] CheckPredicate = Callable[["Context"], Union[Optional[bool], Awaitable[Optional[bool]]]] diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index 8db32bf27..03c209eb8 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -3876,6 +3876,7 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic): # Removing this command from forks is a violation of the GPLv3 under which it is licensed. # Otherwise interfering with the ability for this command to be accessible is also a violation. + @commands.cooldown(1, 180, lambda msg: (msg.channel.id, msg.author.id)) @commands.command( cls=commands.commands._AlwaysAvailableCommand, name="licenseinfo", @@ -3895,24 +3896,3 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic): ) await ctx.send(message) # We need a link which contains a thank you to other projects which we use at some point. - - -# DEP-WARN: CooldownMapping should have a method `from_cooldown` -# which accepts (number, number, bucket) -# the bucket should only be used for the method `_bucket_key` -# and `_bucket_key` should be used to determine the grouping -# of ratelimit consumption. -class LicenseCooldownMapping(commands.CooldownMapping): - """ - This is so that a single user can't spam a channel with this - it's used below as 1 per 3 minutes per user-channel combination. - """ - - def _bucket_key(self, msg): - return (msg.channel.id, msg.author.id) - - -# DEP-WARN: command objects should store a single cooldown mapping as `._buckets` -Core.license_info_command._buckets = LicenseCooldownMapping.from_cooldown( - 1, 180, commands.BucketType.member # pick a random bucket,it wont get used. -) diff --git a/redbot/core/events.py b/redbot/core/events.py index 31cd838a0..db7f3606f 100644 --- a/redbot/core/events.py +++ b/redbot/core/events.py @@ -221,7 +221,7 @@ def init_events(bot, cli_flags): return if ctx.cog: - if commands.Cog._get_overridden_method(ctx.cog.cog_command_error) is not None: + if ctx.cog.has_error_handler(): return if not isinstance(error, commands.CommandNotFound): asyncio.create_task(bot._delete_delay(ctx)) diff --git a/redbot/core/utils/predicates.py b/redbot/core/utils/predicates.py index 45cc8f40e..e2520bc55 100644 --- a/redbot/core/utils/predicates.py +++ b/redbot/core/utils/predicates.py @@ -7,10 +7,10 @@ import discord from redbot.core import commands -_ID_RE = re.compile(r"([0-9]{15,21})$") -_USER_MENTION_RE = re.compile(r"<@!?([0-9]{15,21})>$") -_CHAN_MENTION_RE = re.compile(r"<#([0-9]{15,21})>$") -_ROLE_MENTION_RE = re.compile(r"<@&([0-9]{15,21})>$") +_ID_RE = re.compile(r"([0-9]{15,20})$") +_USER_MENTION_RE = re.compile(r"<@!?([0-9]{15,20})>$") +_CHAN_MENTION_RE = re.compile(r"<#([0-9]{15,20})>$") +_ROLE_MENTION_RE = re.compile(r"<@&([0-9]{15,20})>$") class MessagePredicate(Callable[[discord.Message], bool]): diff --git a/setup.cfg b/setup.cfg index 85c22a937..cdfa163e0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,7 +45,7 @@ install_requires = colorama==0.4.4 commonmark==0.9.1 contextlib2==0.6.0.post1 - discord.py==1.6.0 + discord.py==1.7.0 distro==1.5.0; sys_platform == "linux" fuzzywuzzy==0.18.0 idna==2.10