diff options
Diffstat (limited to '')
31 files changed, 369 insertions, 176 deletions
diff --git a/bot/converters.py b/bot/converters.py index 4d019691e..4a4d3b544 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -273,7 +273,7 @@ class Snowflake(IDConverter):          snowflake = int(arg)          try: -            time = snowflake_time(snowflake) +            time = snowflake_time(snowflake).replace(tzinfo=None)          except (OverflowError, OSError) as e:              # Not sure if this can ever even happen, but let's be safe.              raise BadArgument(f"{error}: {e}") diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py index d5883d6b4..1787beea5 100644 --- a/bot/exts/filters/antispam.py +++ b/bot/exts/filters/antispam.py @@ -108,7 +108,7 @@ class DeletionContext:              colour=Colour(Colours.soft_red),              title="Spam detected!",              text=mod_alert_message, -            thumbnail=first_message.author.avatar_url_as(static_format="png"), +            thumbnail=first_message.author.display_avatar.url,              channel_id=Channels.mod_alerts,              ping_everyone=AntiSpamConfig.ping_everyone          ) @@ -180,7 +180,9 @@ class AntiSpam(Cog):          self.cache.append(message)          earliest_relevant_at = datetime.utcnow() - timedelta(seconds=self.max_interval) -        relevant_messages = list(takewhile(lambda msg: msg.created_at > earliest_relevant_at, self.cache)) +        relevant_messages = list( +            takewhile(lambda msg: msg.created_at.replace(tzinfo=None) > earliest_relevant_at, self.cache) +        )          for rule_name in AntiSpamConfig.rules:              rule_config = AntiSpamConfig.rules[rule_name] @@ -189,7 +191,9 @@ class AntiSpam(Cog):              # Create a list of messages that were sent in the interval that the rule cares about.              latest_interesting_stamp = datetime.utcnow() - timedelta(seconds=rule_config['interval'])              messages_for_rule = list( -                takewhile(lambda msg: msg.created_at > latest_interesting_stamp, relevant_messages) +                takewhile( +                    lambda msg: msg.created_at.replace(tzinfo=None) > latest_interesting_stamp, relevant_messages +                )              )              result = await rule_function(message, messages_for_rule, rule_config) diff --git a/bot/exts/filters/filtering.py b/bot/exts/filters/filtering.py index a8e3d11e3..9281eb343 100644 --- a/bot/exts/filters/filtering.py +++ b/bot/exts/filters/filtering.py @@ -226,7 +226,7 @@ class Filtering(Cog):                  title="Username filtering alert",                  text=log_string,                  channel_id=Channels.mod_alerts, -                thumbnail=member.avatar_url +                thumbnail=member.display_avatar.url              )              # Update time when alert sent @@ -386,7 +386,7 @@ class Filtering(Cog):              colour=Colour(Colours.soft_red),              title=f"{_filter['type'].title()} triggered!",              text=message, -            thumbnail=msg.author.avatar_url_as(static_format="png"), +            thumbnail=msg.author.display_avatar.url,              channel_id=Channels.mod_alerts,              ping_everyone=ping_everyone,              additional_embeds=stats.additional_embeds, diff --git a/bot/exts/filters/token_remover.py b/bot/exts/filters/token_remover.py index f68d4b987..520283ba3 100644 --- a/bot/exts/filters/token_remover.py +++ b/bot/exts/filters/token_remover.py @@ -109,7 +109,7 @@ class TokenRemover(Cog):              colour=Colour(Colours.soft_red),              title="Token removed!",              text=log_message + "\n" + userid_message, -            thumbnail=msg.author.avatar_url_as(static_format="png"), +            thumbnail=msg.author.display_avatar.url,              channel_id=Channels.mod_alerts,              ping_everyone=mention_everyone,          ) diff --git a/bot/exts/filters/webhook_remover.py b/bot/exts/filters/webhook_remover.py index 40cb4e141..96334317c 100644 --- a/bot/exts/filters/webhook_remover.py +++ b/bot/exts/filters/webhook_remover.py @@ -63,7 +63,7 @@ class WebhookRemover(Cog):              colour=Colour(Colours.soft_red),              title="Discord webhook URL removed!",              text=message, -            thumbnail=msg.author.avatar_url_as(static_format="png"), +            thumbnail=msg.author.display_avatar.url,              channel_id=Channels.mod_alerts          ) diff --git a/bot/exts/fun/duck_pond.py b/bot/exts/fun/duck_pond.py index 2b5592530..c51656343 100644 --- a/bot/exts/fun/duck_pond.py +++ b/bot/exts/fun/duck_pond.py @@ -94,7 +94,7 @@ class DuckPond(Cog):                  webhook=self.webhook,                  content=message.clean_content,                  username=message.author.display_name, -                avatar_url=message.author.avatar_url +                avatar_url=message.author.display_avatar.url              )          if message.attachments: @@ -109,7 +109,7 @@ class DuckPond(Cog):                      webhook=self.webhook,                      embed=e,                      username=message.author.display_name, -                    avatar_url=message.author.avatar_url +                    avatar_url=message.author.display_avatar.url                  )              except discord.HTTPException:                  log.exception("Failed to send an attachment to the webhook") diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index f27483af8..1b3e28e79 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -315,7 +315,7 @@ class Information(Cog):          for field_name, field_content in fields:              embed.add_field(name=field_name, value=field_content, inline=False) -        embed.set_thumbnail(url=user.avatar_url_as(static_format="png")) +        embed.set_thumbnail(url=user.display_avatar.url)          embed.colour = user.colour if user.colour != Colour.default() else Colour.blurple()          return embed diff --git a/bot/exts/moderation/defcon.py b/bot/exts/moderation/defcon.py index 56051d0e5..80ba10112 100644 --- a/bot/exts/moderation/defcon.py +++ b/bot/exts/moderation/defcon.py @@ -111,7 +111,7 @@ class Defcon(Cog):          if self.threshold:              now = datetime.utcnow() -            if now - member.created_at < relativedelta_to_timedelta(self.threshold): +            if now - member.created_at.replace(tzinfo=None) < relativedelta_to_timedelta(self.threshold):                  log.info(f"Rejecting user {member}: Account is too new")                  message_sent = False @@ -137,7 +137,7 @@ class Defcon(Cog):                  await self.mod_log.send_log_message(                      Icons.defcon_denied, Colours.soft_red, "Entry denied", -                    message, member.avatar_url_as(static_format="png") +                    message, member.display_avatar.url                  )      @group(name='defcon', aliases=('dc',), invoke_without_command=True) @@ -185,7 +185,12 @@ class Defcon(Cog):          role = ctx.guild.default_role          permissions = role.permissions -        permissions.update(send_messages=False, add_reactions=False, connect=False) +        permissions.update( +            send_messages=False, +            add_reactions=False, +            send_messages_in_threads=False, +            connect=False +        )          await role.edit(reason="DEFCON shutdown", permissions=permissions)          await ctx.send(f"{Action.SERVER_SHUTDOWN.value.emoji} Server shut down.") @@ -196,7 +201,12 @@ class Defcon(Cog):          role = ctx.guild.default_role          permissions = role.permissions -        permissions.update(send_messages=True, add_reactions=True, connect=True) +        permissions.update( +            send_messages=True, +            add_reactions=True, +            send_messages_in_threads=True, +            connect=True +        )          await role.edit(reason="DEFCON unshutdown", permissions=permissions)          await ctx.send(f"{Action.SERVER_OPEN.value.emoji} Server reopened.") diff --git a/bot/exts/moderation/incidents.py b/bot/exts/moderation/incidents.py index 4470b6dd6..097fa36f1 100644 --- a/bot/exts/moderation/incidents.py +++ b/bot/exts/moderation/incidents.py @@ -94,7 +94,7 @@ async def make_embed(incident: discord.Message, outcome: Signal, actioned_by: di          timestamp=datetime.utcnow(),          colour=colour,      ) -    embed.set_footer(text=footer, icon_url=actioned_by.avatar_url) +    embed.set_footer(text=footer, icon_url=actioned_by.display_avatar.url)      if incident.attachments:          attachment = incident.attachments[0]  # User-sent messages can only contain one attachment @@ -253,7 +253,7 @@ class Incidents(Cog):              await webhook.send(                  embed=embed,                  username=sub_clyde(incident.author.name), -                avatar_url=incident.author.avatar_url, +                avatar_url=incident.author.display_avatar.url,                  file=attachment_file,              )          except Exception: diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 2a1ccb9d4..2a27f59c0 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -249,7 +249,7 @@ class InfractionScheduler:              icon_url=icon,              colour=Colours.soft_red,              title=f"Infraction {log_title}: {' '.join(infr_type.split('_'))}", -            thumbnail=user.avatar_url_as(static_format="png"), +            thumbnail=user.display_avatar.url,              text=textwrap.dedent(f"""                  Member: {messages.format_user(user)}                  Actor: {ctx.author.mention}{dm_log_text}{expiry_log_text} @@ -343,7 +343,7 @@ class InfractionScheduler:              icon_url=_utils.INFRACTION_ICONS[infr_type][1],              colour=Colours.soft_green,              title=f"Infraction {log_title}: {' '.join(infr_type.split('_'))}", -            thumbnail=user.avatar_url_as(static_format="png"), +            thumbnail=user.display_avatar.url,              text="\n".join(f"{k}: {v}" for k, v in log_text.items()),              footer=footer,              content=log_content, @@ -460,7 +460,7 @@ class InfractionScheduler:              log_title = "expiration failed" if "Failure" in log_text else "expired"              user = self.bot.get_user(user_id) -            avatar = user.avatar_url_as(static_format="png") if user else None +            avatar = user.display_avatar.url if user else None              # Move reason to end so when reason is too long, this is not gonna cut out required items.              log_text["Reason"] = log_text.pop("Reason") diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py index a50339ee2..b1c8b64dc 100644 --- a/bot/exts/moderation/infraction/management.py +++ b/bot/exts/moderation/infraction/management.py @@ -196,7 +196,7 @@ class ModManagement(commands.Cog):          if user:              user_text = messages.format_user(user) -            thumbnail = user.avatar_url_as(static_format="png") +            thumbnail = user.display_avatar.url          else:              user_text = f"<@{user_id}>"              thumbnail = None diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py index fbb3684e7..7d80d4ba5 100644 --- a/bot/exts/moderation/modlog.py +++ b/bot/exts/moderation/modlog.py @@ -8,7 +8,7 @@ from itertools import zip_longest  import discord  from dateutil.relativedelta import relativedelta  from deepdiff import DeepDiff -from discord import Colour +from discord import Colour, Message, Thread  from discord.abc import GuildChannel  from discord.ext.commands import Cog, Context  from discord.utils import escape_markdown @@ -394,7 +394,7 @@ class ModLog(Cog, name="ModLog"):          await self.send_log_message(              Icons.user_ban, Colours.soft_red,              "User banned", format_user(member), -            thumbnail=member.avatar_url_as(static_format="png"), +            thumbnail=member.display_avatar.url,              channel_id=Channels.user_log          ) @@ -415,7 +415,7 @@ class ModLog(Cog, name="ModLog"):          await self.send_log_message(              Icons.sign_in, Colours.soft_green,              "User joined", message, -            thumbnail=member.avatar_url_as(static_format="png"), +            thumbnail=member.display_avatar.url,              channel_id=Channels.user_log          ) @@ -432,7 +432,7 @@ class ModLog(Cog, name="ModLog"):          await self.send_log_message(              Icons.sign_out, Colours.soft_red,              "User left", format_user(member), -            thumbnail=member.avatar_url_as(static_format="png"), +            thumbnail=member.display_avatar.url,              channel_id=Channels.user_log          ) @@ -449,7 +449,7 @@ class ModLog(Cog, name="ModLog"):          await self.send_log_message(              Icons.user_unban, Colour.blurple(),              "User unbanned", format_user(member), -            thumbnail=member.avatar_url_as(static_format="png"), +            thumbnail=member.display_avatar.url,              channel_id=Channels.mod_log          ) @@ -515,21 +515,39 @@ class ModLog(Cog, name="ModLog"):              colour=Colour.blurple(),              title="Member updated",              text=message, -            thumbnail=after.avatar_url_as(static_format="png"), +            thumbnail=after.display_avatar.url,              channel_id=Channels.user_log          ) +    def is_message_blacklisted(self, message: Message) -> bool: +        """Return true if the message is in a blacklisted thread or channel.""" +        # Ignore bots or DMs +        if message.author.bot or not message.guild: +            return True + +        return self.is_raw_message_blacklisted(message.guild.id, message.channel.id) + +    def is_raw_message_blacklisted(self, guild_id: t.Optional[int], channel_id: int) -> bool: +        """Return true if the message constructed from raw parameter is in a blacklisted thread or channel.""" +        # Ignore DMs or messages outside of the main guild +        if not guild_id or guild_id != GuildConstant.id: +            return True + +        channel = self.bot.get_channel(channel_id) + +        # Look at the parent channel of a thread +        if isinstance(channel, Thread): +            return channel.parent.id in GuildConstant.modlog_blacklist + +        return channel.id in GuildConstant.modlog_blacklist +      @Cog.listener()      async def on_message_delete(self, message: discord.Message) -> None:          """Log message delete event to message change log."""          channel = message.channel          author = message.author -        # Ignore DMs. -        if not message.guild: -            return - -        if message.guild.id != GuildConstant.id or channel.id in GuildConstant.modlog_blacklist: +        if self.is_message_blacklisted(message):              return          self._cached_deletes.append(message.id) @@ -584,7 +602,7 @@ class ModLog(Cog, name="ModLog"):      @Cog.listener()      async def on_raw_message_delete(self, event: discord.RawMessageDeleteEvent) -> None:          """Log raw message delete event to message change log.""" -        if event.guild_id != GuildConstant.id or event.channel_id in GuildConstant.modlog_blacklist: +        if self.is_raw_message_blacklisted(event.guild_id, event.channel_id):              return          await asyncio.sleep(1)  # Wait here in case the normal event was fired @@ -625,12 +643,7 @@ class ModLog(Cog, name="ModLog"):      @Cog.listener()      async def on_message_edit(self, msg_before: discord.Message, msg_after: discord.Message) -> None:          """Log message edit event to message change log.""" -        if ( -            not msg_before.guild -            or msg_before.guild.id != GuildConstant.id -            or msg_before.channel.id in GuildConstant.modlog_blacklist -            or msg_before.author.bot -        ): +        if self.is_message_blacklisted(msg_before):              return          self._cached_edits.append(msg_before.id) @@ -707,12 +720,7 @@ class ModLog(Cog, name="ModLog"):          except discord.NotFound:  # Was deleted before we got the event              return -        if ( -            not message.guild -            or message.guild.id != GuildConstant.id -            or message.channel.id in GuildConstant.modlog_blacklist -            or message.author.bot -        ): +        if self.is_message_blacklisted(message):              return          await asyncio.sleep(1)  # Wait here in case the normal event was fired @@ -752,6 +760,64 @@ class ModLog(Cog, name="ModLog"):          )      @Cog.listener() +    async def on_thread_update(self, before: Thread, after: Thread) -> None: +        """Log thread archiving, un-archiving and name edits.""" +        if before.name != after.name: +            await self.send_log_message( +                Icons.hash_blurple, +                Colour.blurple(), +                "Thread name edited", +                ( +                    f"Thread {after.mention} (`{after.id}`) from {after.parent.mention} (`{after.parent.id}`): " +                    f"`{before.name}` -> `{after.name}`" +                ) +            ) +            return + +        if not before.archived and after.archived: +            colour = Colour.red() +            action = "archived" +            icon = Icons.hash_red +        elif before.archived and not after.archived: +            colour = Colour.green() +            action = "un-archived" +            icon = Icons.hash_green +        else: +            return + +        await self.send_log_message( +            icon, +            colour, +            f"Thread {action}", +            f"Thread {after.mention} (`{after.id}`) from {after.parent.mention} (`{after.parent.id}`) was {action}" +        ) + +    @Cog.listener() +    async def on_thread_delete(self, thread: Thread) -> None: +        """Log thread deletion.""" +        await self.send_log_message( +            Icons.hash_red, +            Colour.red(), +            "Thread deleted", +            f"Thread {thread.mention} (`{thread.id}`) from {thread.parent.mention} (`{thread.parent.id}`) deleted" +        ) + +    @Cog.listener() +    async def on_thread_join(self, thread: Thread) -> None: +        """Log thread creation.""" +        # If we are in the thread already we can most probably assume we already logged it? +        # We don't really have a better way of doing this since the API doesn't make any difference between the two +        if thread.me: +            return + +        await self.send_log_message( +            Icons.hash_green, +            Colour.green(), +            "Thread created", +            f"Thread {thread.mention} (`{thread.id}`) from {thread.parent.mention} (`{thread.parent.id}`) created" +        ) + +    @Cog.listener()      async def on_voice_state_update(          self,          member: discord.Member, @@ -820,7 +886,7 @@ class ModLog(Cog, name="ModLog"):              colour=colour,              title="Voice state updated",              text=message, -            thumbnail=member.avatar_url_as(static_format="png"), +            thumbnail=member.display_avatar.url,              channel_id=Channels.voice_log          ) diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py index 133ebaba5..511520252 100644 --- a/bot/exts/moderation/silence.py +++ b/bot/exts/moderation/silence.py @@ -5,9 +5,10 @@ from datetime import datetime, timedelta, timezone  from typing import Optional, OrderedDict, Union  from async_rediscache import RedisCache -from discord import Guild, PermissionOverwrite, TextChannel, VoiceChannel +from discord import Guild, PermissionOverwrite, TextChannel, Thread, VoiceChannel  from discord.ext import commands, tasks  from discord.ext.commands import Context +from discord.utils import MISSING  from bot import constants  from bot.bot import Bot @@ -48,7 +49,16 @@ class SilenceNotifier(tasks.Loop):      """Loop notifier for posting notices to `alert_channel` containing added channels."""      def __init__(self, alert_channel: TextChannel): -        super().__init__(self._notifier, seconds=1, minutes=0, hours=0, count=None, reconnect=True, loop=None) +        super().__init__( +            self._notifier, +            seconds=1, +            minutes=0, +            hours=0, +            count=None, +            reconnect=True, +            loop=None, +            time=MISSING +        )          self._silenced_channels = {}          self._alert_channel = alert_channel @@ -173,6 +183,12 @@ class Silence(commands.Cog):          channel_info = f"#{channel} ({channel.id})"          log.debug(f"{ctx.author} is silencing channel {channel_info}.") +        # Since threads don't have specific overrides, we cannot silence them individually. +        # The parent channel has to be muted or the thread should be archived. +        if isinstance(channel, Thread): +            await ctx.send(":x: Threads cannot be silenced.") +            return +          if not await self._set_silence_overwrites(channel, kick=kick):              log.info(f"Tried to silence channel {channel_info} but the channel was already silenced.")              await self.send_message(MSG_SILENCE_FAIL, ctx.channel, channel, alert_target=False) @@ -223,7 +239,13 @@ class Silence(commands.Cog):          if isinstance(channel, TextChannel):              role = self._everyone_role              overwrite = channel.overwrites_for(role) -            prev_overwrites = dict(send_messages=overwrite.send_messages, add_reactions=overwrite.add_reactions) +            prev_overwrites = dict( +                send_messages=overwrite.send_messages, +                add_reactions=overwrite.add_reactions, +                create_private_threads=overwrite.create_private_threads, +                create_public_threads=overwrite.create_public_threads, +                send_messages_in_threads=overwrite.send_messages_in_threads +            )          else:              role = self._verified_voice_role @@ -323,7 +345,15 @@ class Silence(commands.Cog):          # Check if old overwrites were not stored          if prev_overwrites is None:              log.info(f"Missing previous overwrites for #{channel} ({channel.id}); defaulting to None.") -            overwrite.update(send_messages=None, add_reactions=None, speak=None, connect=None) +            overwrite.update( +                send_messages=None, +                add_reactions=None, +                create_private_threads=None, +                create_public_threads=None, +                send_messages_in_threads=None, +                speak=None, +                connect=None +            )          else:              overwrite.update(**json.loads(prev_overwrites)) diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py index 88733176f..8fdc7c76b 100644 --- a/bot/exts/moderation/voice_gate.py +++ b/bot/exts/moderation/voice_gate.py @@ -165,7 +165,10 @@ class VoiceGate(Cog):              return          checks = { -            "joined_at": ctx.author.joined_at > datetime.utcnow() - timedelta(days=GateConf.minimum_days_member), +            "joined_at": ( +                ctx.author.joined_at.replace(tzinfo=None) > datetime.utcnow() +                - timedelta(days=GateConf.minimum_days_member) +            ),              "total_messages": data["total_messages"] < GateConf.minimum_messages,              "voice_banned": data["voice_banned"],              "activity_blocks": data["activity_blocks"] < GateConf.minimum_activity_blocks diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index 3264a6d62..f8b7781c5 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -251,7 +251,7 @@ class WatchChannel(metaclass=CogABCMeta):              await self.webhook_send(                  cleaned_content,                  username=msg.author.display_name, -                avatar_url=msg.author.avatar_url +                avatar_url=msg.author.display_avatar.url              )          if msg.attachments: @@ -265,7 +265,7 @@ class WatchChannel(metaclass=CogABCMeta):                  await self.webhook_send(                      embed=e,                      username=msg.author.display_name, -                    avatar_url=msg.author.avatar_url +                    avatar_url=msg.author.display_avatar.url                  )              except discord.HTTPException as exc:                  self.log.exception( @@ -302,7 +302,7 @@ class WatchChannel(metaclass=CogABCMeta):          embed = Embed(description=f"{msg.author.mention} {message_jump}")          embed.set_footer(text=textwrap.shorten(footer, width=256, placeholder="...")) -        await self.webhook_send(embed=embed, username=msg.author.display_name, avatar_url=msg.author.avatar_url) +        await self.webhook_send(embed=embed, username=msg.author.display_name, avatar_url=msg.author.display_avatar.url)      async def list_watched_users(          self, ctx: Context, oldest_first: bool = False, update_cache: bool = True diff --git a/bot/exts/utils/bot.py b/bot/exts/utils/bot.py index 8f0094bc9..788692777 100644 --- a/bot/exts/utils/bot.py +++ b/bot/exts/utils/bot.py @@ -1,6 +1,7 @@ +from contextlib import suppress  from typing import Optional -from discord import Embed, TextChannel +from discord import Embed, Forbidden, TextChannel, Thread  from discord.ext.commands import Cog, Context, command, group, has_any_role  from bot.bot import Bot @@ -16,6 +17,20 @@ class BotCog(Cog, name="Bot"):      def __init__(self, bot: Bot):          self.bot = bot +    @Cog.listener() +    async def on_thread_join(self, thread: Thread) -> None: +        """ +        Try to join newly created threads. + +        Despite the event name being misleading, this is dispatched when new threads are created. +        """ +        if thread.me: +            # We have already joined this thread +            return + +        with suppress(Forbidden): +            await thread.join() +      @group(invoke_without_command=True, name="bot", hidden=True)      async def botinfo_group(self, ctx: Context) -> None:          """Bot informational commands.""" diff --git a/bot/exts/utils/clean.py b/bot/exts/utils/clean.py index e3d346af5..69cf62f2f 100644 --- a/bot/exts/utils/clean.py +++ b/bot/exts/utils/clean.py @@ -107,7 +107,7 @@ class Clean(Cog):          elif regex:              predicate = predicate_regex          # Delete messages that match regex          else: -            predicate = None                     # Delete all messages +            predicate = lambda *_: True          # Delete all messages          # Default to using the invoking context's channel          if not channels: diff --git a/bot/exts/utils/ping.py b/bot/exts/utils/ping.py index cf0e3265e..43d371d87 100644 --- a/bot/exts/utils/ping.py +++ b/bot/exts/utils/ping.py @@ -32,7 +32,7 @@ class Latency(commands.Cog):          """          # datetime.datetime objects do not have the "milliseconds" attribute.          # It must be converted to seconds before converting to milliseconds. -        bot_ping = (datetime.utcnow() - ctx.message.created_at).total_seconds() * 1000 +        bot_ping = (datetime.utcnow() - ctx.message.created_at.replace(tzinfo=None)).total_seconds() * 1000          if bot_ping <= 0:              bot_ping = "Your clock is out of sync, could not calculate ping."          else: diff --git a/bot/utils/checks.py b/bot/utils/checks.py index 4a7f1d1b5..34d09349b 100644 --- a/bot/utils/checks.py +++ b/bot/utils/checks.py @@ -134,7 +134,7 @@ def cooldown_with_role_bypass(rate: int, per: float, type: BucketType = BucketTy      bypass = set(bypass_roles)      # this handles the actual cooldown logic -    buckets = CooldownMapping(Cooldown(rate, per, type)) +    buckets = CooldownMapping(Cooldown(rate, per), type)      # will be called after the command has been parse but before it has been invoked, ensures that      # the cooldown won't be updated if the user screws up their input to the command @@ -149,7 +149,7 @@ def cooldown_with_role_bypass(rate: int, per: float, type: BucketType = BucketTy          bucket = buckets.get_bucket(ctx.message)          retry_after = bucket.update_rate_limit(current)          if retry_after: -            raise CommandOnCooldown(bucket, retry_after) +            raise CommandOnCooldown(bucket, retry_after, type)      def wrapper(command: Command) -> Command:          # NOTE: this could be changed if a subclass of Command were to be used. I didn't see the need for it diff --git a/bot/utils/messages.py b/bot/utils/messages.py index 053750cc3..e55c07062 100644 --- a/bot/utils/messages.py +++ b/bot/utils/messages.py @@ -121,7 +121,7 @@ async def send_attachments(      """      webhook_send_kwargs = {          'username': message.author.display_name, -        'avatar_url': message.author.avatar_url, +        'avatar_url': message.author.display_avatar.url,      }      webhook_send_kwargs.update(kwargs)      webhook_send_kwargs['username'] = sub_clyde(webhook_send_kwargs['username']) diff --git a/poetry.lock b/poetry.lock index 81b51b8da..4068bec12 100644 --- a/poetry.lock +++ b/poetry.lock @@ -264,19 +264,23 @@ murmur = ["mmh3"]  [[package]]  name = "discord.py" -version = "1.7.3" +version = "2.0.0a0"  description = "A Python wrapper for the Discord API"  category = "main"  optional = false -python-versions = ">=3.5.3" +python-versions = ">=3.8.0"  [package.dependencies]  aiohttp = ">=3.6.0,<3.8.0"  [package.extras] -docs = ["sphinx (==3.0.3)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"] +docs = ["sphinx (==4.0.2)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"] +speed = ["orjson (>=3.5.4)"]  voice = ["PyNaCl (>=1.3.0,<1.5)"] +[package.source] +type = "url" +url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip"  [[package]]  name = "distlib"  version = "0.3.2" @@ -539,7 +543,7 @@ python-versions = "*"  [[package]]  name = "more-itertools" -version = "8.8.0" +version = "8.9.0"  description = "More routines for operating on iterables, beyond itertools"  category = "main"  optional = false @@ -627,7 +631,7 @@ test = ["docutils", "pytest-cov", "pytest-pycodestyle", "pytest-runner"]  [[package]]  name = "platformdirs" -version = "2.2.0" +version = "2.3.0"  description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."  category = "dev"  optional = false @@ -639,18 +643,19 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock  [[package]]  name = "pluggy" -version = "0.13.1" +version = "1.0.0"  description = "plugin and hook calling mechanisms for python"  category = "dev"  optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6"  [package.extras]  dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"]  [[package]]  name = "pre-commit" -version = "2.14.0" +version = "2.15.0"  description = "A framework for managing and maintaining multi-language pre-commit hooks."  category = "dev"  optional = false @@ -761,7 +766,7 @@ python-versions = "*"  [[package]]  name = "pytest" -version = "6.2.4" +version = "6.2.5"  description = "pytest: simple powerful testing with Python"  category = "dev"  optional = false @@ -773,7 +778,7 @@ attrs = ">=19.2.0"  colorama = {version = "*", markers = "sys_platform == \"win32\""}  iniconfig = "*"  packaging = "*" -pluggy = ">=0.12,<1.0.0a1" +pluggy = ">=0.12,<2.0"  py = ">=1.8.2"  toml = "*" @@ -873,7 +878,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"  [[package]]  name = "rapidfuzz" -version = "1.5.0" +version = "1.5.1"  description = "rapid fuzzy string matching"  category = "main"  optional = false @@ -1016,7 +1021,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"  [[package]]  name = "typing-extensions" -version = "3.10.0.0" +version = "3.10.0.2"  description = "Backported and Experimental Type Hints for Python 3.5+"  category = "main"  optional = false @@ -1069,7 +1074,7 @@ multidict = ">=4.0"  [metadata]  lock-version = "1.1"  python-versions = "3.9.*" -content-hash = "ceddbb2621849f480f736985d71f37cebefd08a9b38bc3943a6f72706258b6ee" +content-hash = "f57b80eeba96037ea6ff08d033a7cea7a0b2e47711b64cb0a67fb73d0a03be64"  [metadata.files]  aio-pika = [ @@ -1289,10 +1294,7 @@ deepdiff = [      {file = "deepdiff-4.3.2-py3-none-any.whl", hash = "sha256:59fc1e3e7a28dd0147b0f2b00e3e27181f0f0ef4286b251d5f214a5bcd9a9bc4"},      {file = "deepdiff-4.3.2.tar.gz", hash = "sha256:91360be1d9d93b1d9c13ae9c5048fa83d9cff17a88eb30afaa0d7ff2d0fee17d"},  ] -"discord.py" = [ -    {file = "discord.py-1.7.3-py3-none-any.whl", hash = "sha256:c6f64db136de0e18e090f6752ea68bdd4ab0a61b82dfe7acecefa22d6477bb0c"}, -    {file = "discord.py-1.7.3.tar.gz", hash = "sha256:462cd0fe307aef8b29cbfa8dd613e548ae4b2cb581d46da9ac0d46fb6ea19408"}, -] +"discord.py" = []  distlib = [      {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"},      {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"}, @@ -1470,8 +1472,8 @@ mccabe = [      {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},  ]  more-itertools = [ -    {file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"}, -    {file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"}, +    {file = "more-itertools-8.9.0.tar.gz", hash = "sha256:8c746e0d09871661520da4f1241ba6b908dc903839733c8203b552cffaf173bd"}, +    {file = "more_itertools-8.9.0-py3-none-any.whl", hash = "sha256:70401259e46e216056367a0a6034ee3d3f95e0bf59d3aa6a4eb77837171ed996"},  ]  mslex = [      {file = "mslex-0.3.0-py2.py3-none-any.whl", hash = "sha256:380cb14abf8fabf40e56df5c8b21a6d533dc5cbdcfe42406bbf08dda8f42e42a"}, @@ -1540,16 +1542,16 @@ pip-licenses = [      {file = "pip_licenses-3.5.2-py3-none-any.whl", hash = "sha256:62deafc82d5dccea1a4cab55172706e02f228abcd67f4d53e382fcb1497e9b62"},  ]  platformdirs = [ -    {file = "platformdirs-2.2.0-py3-none-any.whl", hash = "sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c"}, -    {file = "platformdirs-2.2.0.tar.gz", hash = "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e"}, +    {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, +    {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"},  ]  pluggy = [ -    {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, -    {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +    {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, +    {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},  ]  pre-commit = [ -    {file = "pre_commit-2.14.0-py2.py3-none-any.whl", hash = "sha256:ec3045ae62e1aa2eecfb8e86fa3025c2e3698f77394ef8d2011ce0aedd85b2d4"}, -    {file = "pre_commit-2.14.0.tar.gz", hash = "sha256:2386eeb4cf6633712c7cc9ede83684d53c8cafca6b59f79c738098b51c6d206c"}, +    {file = "pre_commit-2.15.0-py2.py3-none-any.whl", hash = "sha256:a4ed01000afcb484d9eb8d504272e642c4c4099bbad3a6b27e519bd6a3e928a6"}, +    {file = "pre_commit-2.15.0.tar.gz", hash = "sha256:3c25add78dbdfb6a28a651780d5c311ac40dd17f160eb3954a0c59da40a505a7"},  ]  psutil = [      {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, @@ -1649,8 +1651,8 @@ pyreadline = [      {file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},  ]  pytest = [ -    {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, -    {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, +    {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, +    {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},  ]  pytest-cov = [      {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, @@ -1708,67 +1710,67 @@ pyyaml = [      {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},  ]  rapidfuzz = [ -    {file = "rapidfuzz-1.5.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:670a330e90e962de5823e01e8ae1b8903af788325fbce1ef3fd5ece4d22e0ba4"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:079afafa6e6b00ee799e16d9fc6c6522132cbd7742a7a9e78bd301321e1b5ad6"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:26cb066e79c9867d313450514bb70124d392ac457640c4ec090d29eb68b75541"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:542fbe8fb4403af36bfffd53e42cb1ff3f8d969a046208373d004804072b744c"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:407a5c4d2af813e803b828b004f8686300baf298e9bf90b3388a568b1637a8dc"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:662b4021951ac9edb9a0d026820529e891cea69c11f280188c5b80fefe6ee257"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:03c97beb1c7ce5cb1d12bbb8eb87777e9a5fad23216dab78d6850cafdd3ecaf1"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:eaafa0349d47850ed2c3ae121b62e078a63daf1d533b1cd43fca0c675a85a025"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-win32.whl", hash = "sha256:f0b7e15209208ee74bc264b97e111a3c73e19336eda7255c406e56cc6fbbd384"}, -    {file = "rapidfuzz-1.5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:0679af3d85082dcb27e75ea30c5047dbcc99340f38490c7d4769ae16909c246a"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3a3ef319fd1162e7e38bf11259d86fc6ea3885d2abae6359e5b4dafad62592db"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:60ea1cee33a5a847aeac91a35865c6f7f35a87613df282bda2e7f984e91526f5"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2ba6ffe8ac66dbeae91a0b2cb50f4836ec16920f58746eaf46ff3e9c4f9c0ad8"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:7c101bafb27436affcaa14c631e2bf99d6a7a7860a201ce17ee98447c9c0e7f4"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a8f3f374b4e8e80516b955a1da6364c526d480311a5c6be48264cf7dc06d2fba"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f2fe161526cce52eae224c2af9ae1b9c475ae3e1001fe76024603b290bc8f719"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:8b086b2f70571c9bf16ead5f65976414f8e75a1c680220a839b8ddf005743060"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:814cd474c31db0383c69eed5b457571f63521f38829955c842b141b4835f067f"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-win32.whl", hash = "sha256:0a901aa223a4b051846cb828c33967a6f9c66b8fe0ba7e2a4dc70f6612006988"}, -    {file = "rapidfuzz-1.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f03a5fa9fe38d7f8d566bff0b66600f488d56700469bf1e5e36078f4b58290b6"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:122b7c25792eb27ca59ab23623a922a7290d881d296556d0c23da63ed1691cd5"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:73509dbfcf556233d62683aed0e5f23282ec7138eeedc3ecda2938ad8e8c969d"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6e8c4fd87361699e0cf5cf7ff075e4cd70a2698e9f914368f0c3e198c77c755c"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d627ec73d324d804af4c95909e2fa30b0e59f7efaf69264e553a0e498034404b"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c57f3b74942ae0d0869336e613cbd0760de61a462ff441095eb5fca6575cf964"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:075b8bf76dd4bbc9ccb5177806c9867424d365898415433bf88e7b8e88dc4dfe"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:8049a500b431724d283ddf97d67fe48aa67b4523d617a203c22fd9da3a496223"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:a2d84fde07c32514758d283dd1227453db3ed5372a3e9eae85d0c29b2953f252"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:0e35b9b92a955018ebd09d4d9d70f8e81a0106fe1ed04bc82e3a05166cd04ea5"}, -    {file = "rapidfuzz-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8ae7bf62f0382d13e9b36babc897742bac5e7ee04b4e5e94cd67085bfccfd2fd"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:466d9c644fa235278ef376eefb1fc4382107b07764fbc3c7280533ad9ce49bb4"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d04a8465738363d0b9ee39abb3b289e1198d1f3cbc98bc43b8e21ec8e0b21774"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2c1ce8e8419ac8462289a6e021b8802701ea0f111ebde7607ba3c9588c3d6f30"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:f44564a29e96af0925e68733859d8247a692968034e1b37407d9cfa746d3a853"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d2d1bea50f54387bc1e82b93f6e3a433084e0fa538a7ada8e4d4d7200bae4b83"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b409f0f86a316b6132253258185c7b011e779ed2170d1ad83c79515fea7d78c8"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:bf5a6f4f2eb44f32271e9c2d1e46b657764dbd1b933dd84d7c0433eab48741f8"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bbdee2e3c2cee9c59e1d1a3f351760a1b510e96379d14ba2fa2484a79f56d0ea"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-win32.whl", hash = "sha256:575a0eceaf84632f2014fd55a42a0621e448115adf6fcbc2b0e5c7ae1c18b501"}, -    {file = "rapidfuzz-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:cd6603b94e2a3d56d143a5100f8f3c1d29ad8f5416bdc2a25b079f96eee3c306"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3fa261479e3828eff1f3d0265def8d0d893f2e2f90692d5dae96b3f4ae44d69e"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7a386fe0aad7e89b5017768492ea085d241c32f6dc5a6774b0a309d28f61e720"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68156a67d541bb4584cb31e366fb7de9326f5b77ed07f9882e9b9aaa40b2e5b8"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b62b2a2d2532d357d1b970107a90e85305bdd8e302995dd251f67a19495033f5"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:190b48ba8e3fbcb1cfc522300dbd6a007f50c13cd71002c95bd3946a63b749f6"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:51f9ac3316e713b4a10554a4d6b75fe6f802dd9b4073082cc98968ace6377cac"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:e00198aa7ca8408616d9821501ff90157c429c952d55a2a53987a9b064f73d49"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5784c24e2de539064d8d5ce3f68756630b54fc33af31e054373a65bbed68823a"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:712a4d510c466d6ca75138dad53a1cbd8db0da4bbfa5fc431fcebb0a426e5323"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:2647e00e2211ed741aecb4e676461b7202ce46d536c3439ede911b088432b7a4"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-win32.whl", hash = "sha256:0b77ca0dacb129e878c2583295b76e12da890bd091115417d23b4049b02c2566"}, -    {file = "rapidfuzz-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:dec0d429d117ffd7df1661e5f6ca56bfb6806e117be0b75b5d414df43aa4b6d5"}, -    {file = "rapidfuzz-1.5.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a533d17d177d11b7c177c849adb728035621462f6ce2baaeb9cf1f42ba3e326c"}, -    {file = "rapidfuzz-1.5.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:ac9a2d5a47a4a4eab060882a162d3626889abdec69f899a59fe7b9e01ce122c9"}, -    {file = "rapidfuzz-1.5.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:0e6e2f02bb67a35d75a5613509bb49f0050c0ec4471a9af14da3ad5488d6d5ff"}, -    {file = "rapidfuzz-1.5.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:8c61ced6729146e695ecad403165bf3a07e60b8e8a18df91962b3abf72aae6d5"}, -    {file = "rapidfuzz-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:360415125e967d8682291f00bcea311c738101e0aee4cb90e5572d7e54483f0d"}, -    {file = "rapidfuzz-1.5.0-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:2fb9d47fc16a2e8f5e900c8334d823a7307148ea764321f861b876f85a880d57"}, -    {file = "rapidfuzz-1.5.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:2134ac91e8951d42c9a7de131d767580b8ac50820475221024e5bd63577a376f"}, -    {file = "rapidfuzz-1.5.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:04c4fd372e858f25e0898ba27b5bb7ed8dc528b0915b7aa02d20237e9cdd4feb"}, -    {file = "rapidfuzz-1.5.0.tar.gz", hash = "sha256:141ee381c16f7e58640ef1f1dbf76beb953d248297a7165f7ba25d81ac1161c7"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:6a951ad31ef121bacf40bbe6fbd387740d5038400ec2bfb41d037e9fd2754ef5"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b64acce4f6e745417218fc0bb6ff31b26fac0d723506b82ee4b9cad448b85ebb"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a834061e6d4dfb9672e89e28583486f60821796cf0d7cc559643a0d597ce33a9"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:50548b919bc7608f7b9b4780415ddad135cfc3a54135bdb4bd0bb7ff2cdf9fdf"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:c39c7f200eef49f4f9d6b808950709334e6f1c22262d570f1f77d6d3d373ad81"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:347973ddf12d66d4d06daf1aca3a096a1bffe12306bcf13b832bdfc8db6d9f4a"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:e6cd6717d87d02dde2088c080b0851bdba970b77085b68e213a7b786dee4be88"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:ba956add4c34da019fb5e8f5e1768604b05569dd68055382795ad9062b9ca55e"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:95164076d8e0433f9f93e218270f19e3020a3a9b8db28a3d74143810d4243600"}, +    {file = "rapidfuzz-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:274878c59440d6ad3efca833da61594836306af7dcdd914cc1b6ceb2d4cea23b"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3b3df0c1a307a64273f6fd64c0f28218e002768eda1d94b9fffdab9371e38a6a"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:55472932a8bcf008855b2cc8e5bc47d60066b504ef02dbf8d8fd43ddd8f20a6e"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:170e71f2ec36a086ce5d2667331721cc9b779370d0ef7248ef6979819cd8fb09"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:00734857b412afc35b29f0ea2f1d9ee26ff93d4cd3fa5f47bb90f6aef385f2a1"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ef0cf038c910a3ed626a3224effde8eb49dd7dcda87af59fcd37bc63b78a9bd1"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9f454f79bc463e3de08c5d5c0f438fce1b1736cd4da1a1f47f72dc37da156552"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:05e8dede642af1b38ebcf8fb5e9bbfdcdf8debba660ae1aafb5c1b0e6ca3e4de"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:f08773adb7f21e1f530bad2c6ababaf472f80283650bc265a7e8f614480cd49c"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:4e1a7fb18d4a6c3d471a3ad8f820f179216de61bef74663342340cf9c685a31e"}, +    {file = "rapidfuzz-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:09e992579c4aae59310e44db99ed848a8437ed1e8810a513d3bbab7ac7a8f215"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e2cd05869bd50f25b6d384e0cc73f8cfd6ebb8f1e7bdf1315384e21611f091"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b173f8d4c9360b8b32b5ab7a669623f239cb85013e1749bdca03e1b3c297faa7"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6ab75111e2216a48c7e01d47d8903fc2d0c1df398e7262a6df544d86812e40c7"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:eb560622d9970eb0c615d5dff26af8a8647ba541a89a927fca1eb0862898f997"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:59246615b819e4aff685aa57359f5bbaf02441cccc83e8899608037542a3fe36"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:7a960dfedcf1acdb8435b5b00aebfc2ee8fd53b7b4f7acf613915b4c24fc0ef7"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:3d727a7e09f1a01b61452c86d687d0564bad923d5d209224549ae790408d6449"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:eb5e43dbef900367b91fb73a4c447efde034656b25b397844c8cf622dae84ac3"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:03ea226734cca3f86bc402fc04b8a38b795795e99dbf02dd834845b80bcf7588"}, +    {file = "rapidfuzz-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5e9beeb6643d663c410ad8ccf88eafbe59ba7aa9b34eea5b51c6312976789803"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0d3cdb6ced024ed1567ba0be4b0909b17f691bd6e9e9f29626e4953ecf7cba9e"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c06f98bb94fbad9b773c38a3e2cf28a315466b41f862917ba4d228052bcc0966"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7bf51eb2ff342c4a0d77ab22b3d7de461ef9d2c480fd863c57fb139e7578fa7b"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:6b0c74f60c03eed4b5d19f866df79c1d1bffc4c61f9bf31b114402c47680997f"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:bbba42e244a0ebc1639c62ab44e4a172767d3721d2af48f2764ca00de7721479"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0b9f76f47b6df8c6aaa02a27fdff52e6aaf64d39296683ed06d0ec9acf2515d2"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:c52ce4b4bfe8e0c2cf102f7b71cca00fc3228113e71712597940c9c340ae31b1"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:0d3ae040c91f500814df6557276462c0c869b16168ef51d01c8a7da150f54513"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-win32.whl", hash = "sha256:112ecc4825c5d362298d1e3c512d3f942c1a74f26ca69dc4b19a4f2cd95cb764"}, +    {file = "rapidfuzz-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:b1feec7407df54045bc9d4dce3431ce20855c1ff4dd170480fbace62164f8f9c"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b352fe56b92bd2aa4ceae550543a923996c16efecf8f981c955dd5f522d2002"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9454f46bc4007be9148f18143bb1b615a740a99737a38cf7b9baf3c495d5d17c"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c1a75c87a2f4c9709c6e3ecdbb2317f0964ac96f845f6a331d8a437a2944d24"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:02f8b282a940cb749b1c51196baab7abb5590fcc8c065ce540c5d8414366036d"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2def32a4228a717c5e6a699f0742546aee4091eb1e59e79781ceacabfc54452c"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2e9d494ff51b942ed1504f84c13476319c89fc9bcc6379cc0816b776a7994199"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:e94a6af7f0cc8ff49ab22842af255d8d927ca3b168b1a7e8e0784f1a2f49bc38"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c4ee8b9baaf46447dcaed925ad1d3606d3a375dfc5c67d1f3e33c46a3008cb5a"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:10e236b3ce5851f584bbf178e7fb04ae5d0fbb008f3bc580ef6185bbbb346cd1"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:068404913619182739fa3fde3079c17e3402744a1117df7f60055db331095a01"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-win32.whl", hash = "sha256:e933e3ce2d88b7584248493abcba2cd27240f42bf73ca040babfd1ce8036750e"}, +    {file = "rapidfuzz-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:46f5931f7441e13574d0fe33e897212d00ff63f69c0db1d449afbc5e87bafd7f"}, +    {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7fb25ee0340cc26dad0bb4a97019bf61b4cefaec67a1be64ac9dac2f98c697cd"}, +    {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:e738ec4e680bebe4442befda5cdd18020c3721d4cd75f9bfe2fb94e78ef55618"}, +    {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:cb083609923bc4ac602e6f1d61be61a25b35cccfb5ee208d2aa89eb0be357c69"}, +    {file = "rapidfuzz-1.5.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:08ecef2995b6ed1187b375d8f28ba4557522f098a1515b6afb0e3b452997a3a4"}, +    {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b6ff10d856fce55e2b1c681e4e7cd7da9b9eb6854571df60d6ed8904c777e64b"}, +    {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:b41c346f16cd1ee71b259106d3cfad3347bd8fff4ff20f334a12738df6736c01"}, +    {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:f7148a53a0fd3466b82b81d94ad91aee7ce7947f37f16f9fb54319ea7df7f4af"}, +    {file = "rapidfuzz-1.5.1-pp37-pypy37_pp73-win32.whl", hash = "sha256:31d83af9ac39f47f47ce4830ee118e6fa53964cccd8161e9a478a326f2a994cf"}, +    {file = "rapidfuzz-1.5.1.tar.gz", hash = "sha256:4ebbd071425ee812548c301c60661a4f8faa5e5bcc97a6f0bef5b562585a8025"},  ]  redis = [      {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, @@ -1857,9 +1859,9 @@ toml = [      {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},  ]  typing-extensions = [ -    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, -    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, -    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, +    {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, +    {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, +    {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},  ]  urllib3 = [      {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, diff --git a/pyproject.toml b/pyproject.toml index 4431a41c5..95634728e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ license = "MIT"  [tool.poetry.dependencies]  python = "3.9.*" +"discord.py" = {url = "https://github.com/Rapptz/discord.py/archive/45d498c1b76deaf3b394d17ccf56112fa691d160.zip"}  aio-pika = "~=6.1"  aiodns = "~=2.0"  aiohttp = "~=3.7" @@ -17,7 +18,6 @@ beautifulsoup4 = "~=4.9"  colorama = { version = "~=0.4.3", markers = "sys_platform == 'win32'" }  coloredlogs = "~=14.0"  deepdiff = "~=4.0" -"discord.py" = "~=1.7.3"  emoji = "~=0.6"  feedparser = "~=6.0.2"  rapidfuzz = "~=1.4" diff --git a/tests/base.py b/tests/base.py index ab9287e9a..5e304ea9d 100644 --- a/tests/base.py +++ b/tests/base.py @@ -103,4 +103,4 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):          with self.assertRaises(commands.MissingPermissions) as cm:              await cmd.can_run(ctx) -        self.assertCountEqual(permissions.keys(), cm.exception.missing_perms) +        self.assertCountEqual(permissions.keys(), cm.exception.missing_permissions) diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 2b0549b98..462f718e6 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -107,7 +107,7 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase):          """Should send error with `ctx.send` when error is `CommandOnCooldown`."""          self.ctx.reset_mock()          cog = ErrorHandler(self.bot) -        error = errors.CommandOnCooldown(10, 9) +        error = errors.CommandOnCooldown(10, 9, type=None)          self.assertIsNone(await cog.on_command_error(self.ctx, error))          self.ctx.send.assert_awaited_once_with(error) diff --git a/tests/bot/exts/filters/test_token_remover.py b/tests/bot/exts/filters/test_token_remover.py index 05e790723..4db27269a 100644 --- a/tests/bot/exts/filters/test_token_remover.py +++ b/tests/bot/exts/filters/test_token_remover.py @@ -26,7 +26,7 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):          self.msg.guild.get_member.return_value.bot = False          self.msg.guild.get_member.return_value.__str__.return_value = "Woody"          self.msg.author.__str__ = MagicMock(return_value=self.msg.author.name) -        self.msg.author.avatar_url_as.return_value = "picture-lemon.png" +        self.msg.author.display_avatar.url = "picture-lemon.png"      def test_extract_user_id_valid(self):          """Should consider user IDs valid if they decode into an integer ID.""" @@ -376,7 +376,7 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):              colour=Colour(constants.Colours.soft_red),              title="Token removed!",              text=log_msg + "\n" + userid_log_message, -            thumbnail=self.msg.author.avatar_url_as.return_value, +            thumbnail=self.msg.author.display_avatar.url,              channel_id=constants.Channels.mod_alerts,              ping_everyone=True,          ) diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index d8250befb..4b50c3fd9 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -84,7 +84,7 @@ class InformationCogTests(unittest.IsolatedAsyncioTestCase):          self.assertEqual(dummy_embed.fields[0].value, str(dummy_role.id))          self.assertEqual(dummy_embed.fields[1].value, f"#{dummy_role.colour.value:0>6x}") -        self.assertEqual(dummy_embed.fields[2].value, "0.63 0.48 218") +        self.assertEqual(dummy_embed.fields[2].value, "0.65 0.64 242")          self.assertEqual(dummy_embed.fields[3].value, "1")          self.assertEqual(dummy_embed.fields[4].value, "10")          self.assertEqual(dummy_embed.fields[5].value, "0") @@ -435,10 +435,9 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          ctx = helpers.MockContext()          user = helpers.MockMember(id=217, colour=0) -        user.avatar_url_as.return_value = "avatar url" +        user.display_avatar.url = "avatar url"          embed = await self.cog.create_user_embed(ctx, user) -        user.avatar_url_as.assert_called_once_with(static_format="png")          self.assertEqual(embed.thumbnail.url, "avatar url") diff --git a/tests/bot/exts/moderation/test_incidents.py b/tests/bot/exts/moderation/test_incidents.py index cbf7f7bcf..583cb8bb3 100644 --- a/tests/bot/exts/moderation/test_incidents.py +++ b/tests/bot/exts/moderation/test_incidents.py @@ -3,7 +3,7 @@ import enum  import logging  import typing as t  import unittest -from unittest.mock import AsyncMock, MagicMock, call, patch +from unittest.mock import AsyncMock, MagicMock, Mock, call, patch  import aiohttp  import discord @@ -379,7 +379,7 @@ class TestArchive(TestIncidents):          # Define our own `incident` to be archived          incident = MockMessage(              content="this is an incident", -            author=MockUser(name="author_name", avatar_url="author_avatar"), +            author=MockUser(name="author_name", display_avatar=Mock(url="author_avatar")),              id=123,          )          built_embed = MagicMock(discord.Embed, id=123)  # We patch `make_embed` to return this diff --git a/tests/bot/exts/moderation/test_silence.py b/tests/bot/exts/moderation/test_silence.py index 59a5893ef..78a12b6d2 100644 --- a/tests/bot/exts/moderation/test_silence.py +++ b/tests/bot/exts/moderation/test_silence.py @@ -438,7 +438,13 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase):          asyncio.run(self.cog._async_init())  # Populate instance attributes.          self.text_channel = MockTextChannel() -        self.text_overwrite = PermissionOverwrite(send_messages=True, add_reactions=False) +        self.text_overwrite = PermissionOverwrite( +            send_messages=True, +            add_reactions=False, +            create_private_threads=True, +            create_public_threads=False, +            send_messages_in_threads=True +        )          self.text_channel.overwrites_for.return_value = self.text_overwrite          self.voice_channel = MockVoiceChannel() @@ -509,9 +515,39 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase):      async def test_skipped_already_silenced(self):          """Permissions were not set and `False` was returned for an already silenced channel."""          subtests = ( -            (False, MockTextChannel(), PermissionOverwrite(send_messages=False, add_reactions=False)), -            (True, MockTextChannel(), PermissionOverwrite(send_messages=True, add_reactions=True)), -            (True, MockTextChannel(), PermissionOverwrite(send_messages=False, add_reactions=False)), +            ( +                False, +                MockTextChannel(), +                PermissionOverwrite( +                    send_messages=False, +                    add_reactions=False, +                    create_private_threads=False, +                    create_public_threads=False, +                    send_messages_in_threads=False +                ) +            ), +            ( +                True, +                MockTextChannel(), +                PermissionOverwrite( +                    send_messages=True, +                    add_reactions=True, +                    create_private_threads=True, +                    create_public_threads=True, +                    send_messages_in_threads=True +                ) +            ), +            ( +                True, +                MockTextChannel(), +                PermissionOverwrite( +                    send_messages=False, +                    add_reactions=False, +                    create_private_threads=False, +                    create_public_threads=False, +                    send_messages_in_threads=False +                ) +            ),              (False, MockVoiceChannel(), PermissionOverwrite(connect=False, speak=False)),              (True, MockVoiceChannel(), PermissionOverwrite(connect=True, speak=True)),              (True, MockVoiceChannel(), PermissionOverwrite(connect=False, speak=False)), @@ -559,11 +595,16 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase):          await self.cog._set_silence_overwrites(self.text_channel)          new_overwrite_dict = dict(self.text_overwrite) -        # Remove 'send_messages' & 'add_reactions' keys because they were changed by the method. -        del prev_overwrite_dict['send_messages'] -        del prev_overwrite_dict['add_reactions'] -        del new_overwrite_dict['send_messages'] -        del new_overwrite_dict['add_reactions'] +        # Remove related permission keys because they were changed by the method. +        for perm_name in ( +                "send_messages", +                "add_reactions", +                "create_private_threads", +                "create_public_threads", +                "send_messages_in_threads" +        ): +            del prev_overwrite_dict[perm_name] +            del new_overwrite_dict[perm_name]          self.assertDictEqual(prev_overwrite_dict, new_overwrite_dict) @@ -601,7 +642,10 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase):      async def test_cached_previous_overwrites(self):          """Channel's previous overwrites were cached.""" -        overwrite_json = '{"send_messages": true, "add_reactions": false}' +        overwrite_json = ( +            '{"send_messages": true, "add_reactions": false, "create_private_threads": true, ' +            '"create_public_threads": false, "send_messages_in_threads": true}' +        )          await self.cog._set_silence_overwrites(self.text_channel)          self.cog.previous_overwrites.set.assert_awaited_once_with(self.text_channel.id, overwrite_json) diff --git a/tests/bot/utils/test_checks.py b/tests/bot/utils/test_checks.py index 883465e0b..4ae11d5d3 100644 --- a/tests/bot/utils/test_checks.py +++ b/tests/bot/utils/test_checks.py @@ -32,6 +32,7 @@ class ChecksTests(unittest.IsolatedAsyncioTestCase):      async def test_has_no_roles_check_without_guild(self):          """`has_no_roles_check` should return `False` when `Context.guild` is None."""          self.ctx.channel = MagicMock(DMChannel) +        self.ctx.guild = None          self.assertFalse(await checks.has_no_roles_check(self.ctx))      async def test_has_no_roles_check_returns_false_with_unwanted_role(self): diff --git a/tests/helpers.py b/tests/helpers.py index 83b9b2363..9d4988d23 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -39,7 +39,7 @@ class HashableMixin(discord.mixins.EqualityComparable):  class ColourMixin: -    """A mixin for Mocks that provides the aliasing of color->colour like discord.py does.""" +    """A mixin for Mocks that provides the aliasing of (accent_)color->(accent_)colour like discord.py does."""      @property      def color(self) -> discord.Colour: @@ -49,6 +49,14 @@ class ColourMixin:      def color(self, color: discord.Colour) -> None:          self.colour = color +    @property +    def accent_color(self) -> discord.Colour: +        return self.accent_colour + +    @accent_color.setter +    def accent_color(self, color: discord.Colour) -> None: +        self.accent_colour = color +  class CustomMockMixin:      """ @@ -242,7 +250,13 @@ class MockMember(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin  # Create a User instance to get a realistic Mock of `discord.User` -user_instance = discord.User(data=unittest.mock.MagicMock(), state=unittest.mock.MagicMock()) +_user_data_mock = collections.defaultdict(unittest.mock.MagicMock, { +    "accent_color": 0 +}) +user_instance = discord.User( +    data=unittest.mock.MagicMock(get=unittest.mock.Mock(side_effect=_user_data_mock.get)), +    state=unittest.mock.MagicMock() +)  class MockUser(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin): @@ -428,7 +442,12 @@ message_instance = discord.Message(state=state, channel=channel, data=message_da  # Create a Context instance to get a realistic MagicMock of `discord.ext.commands.Context` -context_instance = Context(message=unittest.mock.MagicMock(), prefix=unittest.mock.MagicMock()) +context_instance = Context( +    message=unittest.mock.MagicMock(), +    prefix="$", +    bot=MockBot(), +    view=None +)  context_instance.invoked_from_error_handler = None @@ -537,7 +556,7 @@ class MockReaction(CustomMockMixin, unittest.mock.MagicMock):          self.__str__.return_value = str(self.emoji) -webhook_instance = discord.Webhook(data=unittest.mock.MagicMock(), adapter=unittest.mock.MagicMock()) +webhook_instance = discord.Webhook(data=unittest.mock.MagicMock(), session=unittest.mock.MagicMock())  class MockAsyncWebhook(CustomMockMixin, unittest.mock.MagicMock): @@ -5,7 +5,7 @@ import-order-style=pycharm  application_import_names=bot,tests  exclude=.cache,.venv,.git,constants.py  ignore= -    B311,W503,E226,S311,T000 +    B311,W503,E226,S311,T000,E731      # Missing Docstrings      D100,D104,D105,D107,      # Docstring Whitespace  |