Bump discord.py to 1.7.0 (#4928)

* Bump discord.py, but to the git version for now

* Import GuildConverter from d.py and deprecate our implementation

* Import PartialMessageConverter in our commands extension

* Use newly added `Cog.has_error_handler()` rather than private method

* Update snowflake regex to use 20 as max length

See Rapptz/discord.py#6501

* Use new supported way for custom cooldown buckets

* Include group args in command signature

* Update code to use `Client.close()` over `Client.logout()`

* Add StageChannelConverter and StoreChannelConverter

* Fix AttributeError in licenseinfo
This commit is contained in:
jack1142 2021-04-05 21:33:19 +02:00 committed by GitHub
parent 9008410fa4
commit adda30cbee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 69 additions and 56 deletions

View File

@ -181,7 +181,7 @@ async def _edit_prefix(red, prefix, no_prompt):
async def _edit_owner(red, owner, no_prompt): async def _edit_owner(red, owner, no_prompt):
if owner: if owner:
if not (15 <= len(str(owner)) <= 21): if not (15 <= len(str(owner)) <= 20):
print( print(
"The provided owner id doesn't look like a valid Discord user id." "The provided owner id doesn't look like a valid Discord user id."
" Instance's owner will remain unchanged." " 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:") print("Please enter a Discord user id for new owner:")
while True: while True:
owner_id = input("> ").strip() 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.") print("That doesn't look like a valid Discord user id.")
continue continue
owner_id = int(owner_id) 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 red._shutdown_mode = exit_code
try: try:
await red.logout() await red.close()
finally: finally:
# Then cancels all outstanding tasks other than ourselves # Then cancels all outstanding tasks other than ourselves
pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]

View File

@ -58,7 +58,7 @@ Guild must be a valid version of one of the following:
_ = T_ _ = T_
MENTION_RE: Final[Pattern] = re.compile(r"^<?(?:(?:@[!&]?)?|#)(\d{15,21})>?$") MENTION_RE: Final[Pattern] = re.compile(r"^<?(?:(?:@[!&]?)?|#)(\d{15,20})>?$")
def _match_id(arg: str) -> Optional[int]: def _match_id(arg: str) -> Optional[int]:

View File

@ -4,8 +4,8 @@ from redbot.core.i18n import Translator
_ = Translator("Mod", __file__) _ = Translator("Mod", __file__)
_id_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,21})>$") _mention_regex = re.compile(r"<@!?([0-9]{15,20})>$")
class RawUserIds(Converter): class RawUserIds(Converter):

View File

@ -10,7 +10,7 @@ from redbot.core.utils import AsyncIter
_ = Translator("PermissionsConverters", __file__) _ = Translator("PermissionsConverters", __file__)
MENTION_RE = re.compile(r"^<?(?:(?:@[!&]?)?|#)(\d{15,21})>?$") MENTION_RE = re.compile(r"^<?(?:(?:@[!&]?)?|#)(\d{15,20})>?$")
def _match_id(arg: str) -> Optional[int]: def _match_id(arg: str) -> Optional[int]:

View File

@ -1664,9 +1664,9 @@ class RedBase(
await asyncio.sleep(delay) await asyncio.sleep(delay)
await _delete_helper(message) await _delete_helper(message)
async def logout(self): async def close(self):
"""Logs out of Discord and closes all connections.""" """Logs out of Discord and closes all connections."""
await super().logout() await super().close()
await drivers.get_driver_class().teardown() await drivers.get_driver_class().teardown()
try: try:
if self.rpc_enabled: if self.rpc_enabled:
@ -1691,7 +1691,7 @@ class RedBase(
else: else:
self._shutdown_mode = ExitCodes.RESTART self._shutdown_mode = ExitCodes.RESTART
await self.logout() await self.close()
sys.exit(self._shutdown_mode) sys.exit(self._shutdown_mode)
async def _core_data_deletion( async def _core_data_deletion(

View File

@ -21,7 +21,6 @@ from .commands import (
from .context import Context as Context, GuildContext as GuildContext, DMContext as DMContext from .context import Context as Context, GuildContext as GuildContext, DMContext as DMContext
from .converter import ( from .converter import (
DictConverter as DictConverter, DictConverter as DictConverter,
GuildConverter as GuildConverter,
TimedeltaConverter as TimedeltaConverter, TimedeltaConverter as TimedeltaConverter,
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,
@ -84,6 +83,7 @@ from ._dpy_reimplements import (
from discord.ext.commands import ( from discord.ext.commands import (
BadArgument as BadArgument, BadArgument as BadArgument,
EmojiConverter as EmojiConverter, EmojiConverter as EmojiConverter,
GuildConverter as GuildConverter,
InvalidEndOfQuotedStringError as InvalidEndOfQuotedStringError, InvalidEndOfQuotedStringError as InvalidEndOfQuotedStringError,
MemberConverter as MemberConverter, MemberConverter as MemberConverter,
BotMissingRole as BotMissingRole, BotMissingRole as BotMissingRole,
@ -103,6 +103,7 @@ from discord.ext.commands import (
ExtensionError as ExtensionError, ExtensionError as ExtensionError,
Cooldown as Cooldown, Cooldown as Cooldown,
CheckFailure as CheckFailure, CheckFailure as CheckFailure,
PartialMessageConverter as PartialMessageConverter,
MessageConverter as MessageConverter, MessageConverter as MessageConverter,
MissingPermissions as MissingPermissions, MissingPermissions as MissingPermissions,
BadUnionArgument as BadUnionArgument, BadUnionArgument as BadUnionArgument,
@ -130,6 +131,8 @@ from discord.ext.commands import (
ColourConverter as ColourConverter, ColourConverter as ColourConverter,
ColorConverter as ColorConverter, ColorConverter as ColorConverter,
VoiceChannelConverter as VoiceChannelConverter, VoiceChannelConverter as VoiceChannelConverter,
StageChannelConverter as StageChannelConverter,
StoreChannelConverter as StoreChannelConverter,
NSFWChannelRequired as NSFWChannelRequired, NSFWChannelRequired as NSFWChannelRequired,
IDConverter as IDConverter, IDConverter as IDConverter,
MissingRequiredArgument as MissingRequiredArgument, MissingRequiredArgument as MissingRequiredArgument,
@ -147,6 +150,7 @@ from discord.ext.commands import (
MaxConcurrencyReached as MaxConcurrencyReached, MaxConcurrencyReached as MaxConcurrencyReached,
bot_has_guild_permissions as bot_has_guild_permissions, bot_has_guild_permissions as bot_has_guild_permissions,
CommandRegistrationError as CommandRegistrationError, CommandRegistrationError as CommandRegistrationError,
GuildNotFound as GuildNotFound,
MessageNotFound as MessageNotFound, MessageNotFound as MessageNotFound,
MemberNotFound as MemberNotFound, MemberNotFound as MemberNotFound,
UserNotFound as UserNotFound, UserNotFound as UserNotFound,

View File

@ -35,7 +35,6 @@ if TYPE_CHECKING:
__all__ = [ __all__ = [
"DictConverter", "DictConverter",
"GuildConverter",
"UserInputOptional", "UserInputOptional",
"NoParseOptional", "NoParseOptional",
"TimedeltaConverter", "TimedeltaConverter",
@ -47,7 +46,7 @@ __all__ = [
_ = Translator("commands.converter", __file__) _ = 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 # Taken with permission from
@ -134,29 +133,46 @@ def parse_timedelta(
return None return None
class GuildConverter(discord.Guild): class _GuildConverter(discord.Guild):
"""Converts to a `discord.Guild` object. """Converts to a `discord.Guild` object.
The lookup strategy is as follows (in order): The lookup strategy is as follows (in order):
1. Lookup by ID. 1. Lookup by ID.
2. Lookup by name. 2. Lookup by name.
.. deprecated-removed:: 3.4.8 60
``GuildConverter`` is now only provided within ``redbot.core.commands`` namespace.
""" """
@classmethod @classmethod
async def convert(cls, ctx: "Context", argument: str) -> discord.Guild: 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: _GuildConverter.__name__ = "GuildConverter"
raise BadArgument(_('Server "{name}" not found.').format(name=argument))
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 # Below this line are a lot of lies for mypy about things that *end up* correct when

View File

@ -275,6 +275,20 @@ class RedHelpFormatter(HelpFormatterABC):
"You can also type {ctx.clean_prefix}help <category> for more info on a category." "You can also type {ctx.clean_prefix}help <category> for more info on a category."
).format(ctx=ctx) ).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( async def format_command_help(
self, ctx: Context, obj: commands.Command, help_settings: HelpSettings self, ctx: Context, obj: commands.Command, help_settings: HelpSettings
): ):
@ -300,9 +314,9 @@ class RedHelpFormatter(HelpFormatterABC):
description = command.description or "" description = command.description or ""
tagline = (help_settings.tagline) or self.get_default_tagline(ctx) tagline = (help_settings.tagline) or self.get_default_tagline(ctx)
signature = _( signature = _("Syntax: {command_signature}").format(
"Syntax: {ctx.clean_prefix}{command.qualified_name} {command.signature}" command_signature=self.get_command_signature(ctx, command)
).format(ctx=ctx, command=command) )
aliases = command.aliases aliases = command.aliases
if help_settings.show_aliases and aliases: if help_settings.show_aliases and aliases:

View File

@ -28,7 +28,6 @@ from typing import (
import discord import discord
from discord.ext.commands import check from discord.ext.commands import check
from .converter import GuildConverter
from .errors import BotMissingPermissions from .errors import BotMissingPermissions
if TYPE_CHECKING: if TYPE_CHECKING:
@ -70,7 +69,7 @@ GlobalPermissionModel = Union[
discord.TextChannel, discord.TextChannel,
discord.CategoryChannel, discord.CategoryChannel,
discord.Role, discord.Role,
GuildConverter, # Unfortunately this will have to do for now discord.Guild,
] ]
GuildPermissionModel = Union[ GuildPermissionModel = Union[
discord.Member, discord.Member,
@ -78,7 +77,7 @@ GuildPermissionModel = Union[
discord.TextChannel, discord.TextChannel,
discord.CategoryChannel, discord.CategoryChannel,
discord.Role, discord.Role,
GuildConverter, discord.Guild,
] ]
PermissionModel = Union[GlobalPermissionModel, GuildPermissionModel] PermissionModel = Union[GlobalPermissionModel, GuildPermissionModel]
CheckPredicate = Callable[["Context"], Union[Optional[bool], Awaitable[Optional[bool]]]] CheckPredicate = Callable[["Context"], Union[Optional[bool], Awaitable[Optional[bool]]]]

View File

@ -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. # 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. # 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( @commands.command(
cls=commands.commands._AlwaysAvailableCommand, cls=commands.commands._AlwaysAvailableCommand,
name="licenseinfo", name="licenseinfo",
@ -3895,24 +3896,3 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
) )
await ctx.send(message) await ctx.send(message)
# We need a link which contains a thank you to other projects which we use at some point. # 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.
)

View File

@ -221,7 +221,7 @@ def init_events(bot, cli_flags):
return return
if ctx.cog: if ctx.cog:
if commands.Cog._get_overridden_method(ctx.cog.cog_command_error) is not None: if ctx.cog.has_error_handler():
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))

View File

@ -7,10 +7,10 @@ import discord
from redbot.core import commands from redbot.core import commands
_ID_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,21})>$") _USER_MENTION_RE = re.compile(r"<@!?([0-9]{15,20})>$")
_CHAN_MENTION_RE = re.compile(r"<#([0-9]{15,21})>$") _CHAN_MENTION_RE = re.compile(r"<#([0-9]{15,20})>$")
_ROLE_MENTION_RE = re.compile(r"<@&([0-9]{15,21})>$") _ROLE_MENTION_RE = re.compile(r"<@&([0-9]{15,20})>$")
class MessagePredicate(Callable[[discord.Message], bool]): class MessagePredicate(Callable[[discord.Message], bool]):

View File

@ -45,7 +45,7 @@ install_requires =
colorama==0.4.4 colorama==0.4.4
commonmark==0.9.1 commonmark==0.9.1
contextlib2==0.6.0.post1 contextlib2==0.6.0.post1
discord.py==1.6.0 discord.py==1.7.0
distro==1.5.0; sys_platform == "linux" distro==1.5.0; sys_platform == "linux"
fuzzywuzzy==0.18.0 fuzzywuzzy==0.18.0
idna==2.10 idna==2.10