diff options
Diffstat (limited to '')
24 files changed, 446 insertions, 440 deletions
| diff --git a/tests/_autospec.py b/tests/_autospec.py index ecff6bcbe..6f990a580 100644 --- a/tests/_autospec.py +++ b/tests/_autospec.py @@ -2,7 +2,7 @@ import contextlib  import functools  import pkgutil  import unittest.mock -from typing import Callable +from collections.abc import Callable  @functools.wraps(unittest.mock._patch.decoration_helper) diff --git a/tests/base.py b/tests/base.py index 4863a1821..cad187b6a 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,7 +1,6 @@  import logging  import unittest  from contextlib import contextmanager -from typing import Dict  import discord  from async_rediscache import RedisSession @@ -86,7 +85,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):      async def assertHasPermissionsCheck(  # noqa: N802          self,          cmd: commands.Command, -        permissions: Dict[str, bool], +        permissions: dict[str, bool],      ) -> None:          """          Test that `cmd` raises a `MissingPermissions` exception if author lacks `permissions`. diff --git a/tests/bot/exts/filtering/test_discord_token_filter.py b/tests/bot/exts/filtering/test_discord_token_filter.py index a5cddf8d9..1cb9e16fa 100644 --- a/tests/bot/exts/filtering/test_discord_token_filter.py +++ b/tests/bot/exts/filtering/test_discord_token_filter.py @@ -222,8 +222,8 @@ class DiscordTokenFilterTests(unittest.IsolatedAsyncioTestCase):      def test_regex_matches_multiple_valid(self):          """Should support multiple matches in the middle of a string.""" -        token_1 = "NDY3MjIzMjMwNjUwNzc3NjQx.XsyWGg.uFNEQPCc4ePwGh7egG8UicQssz8" -        token_2 = "NDcyMjY1OTQzMDYyNDEzMzMy.XsyWMw.l8XPnDqb0lp-EiQ2g_0xVFT1pyc" +        token_1 = "NDY3MjIzMjMwNjUwNzc3NjQx.XsyWGg.uFNEQPCc4ePwGh7egG8UicQssz8"  # noqa: S105 +        token_2 = "NDcyMjY1OTQzMDYyNDEzMzMy.XsyWMw.l8XPnDqb0lp-EiQ2g_0xVFT1pyc"  # noqa: S105          message = f"garbage {token_1} hello {token_2} world"          results = discord_token.TOKEN_RE.finditer(message) diff --git a/tests/bot/exts/filtering/test_extension_filter.py b/tests/bot/exts/filtering/test_extension_filter.py index 827d267d2..f71de1e1b 100644 --- a/tests/bot/exts/filtering/test_extension_filter.py +++ b/tests/bot/exts/filtering/test_extension_filter.py @@ -25,7 +25,7 @@ class ExtensionsListTests(unittest.IsolatedAsyncioTestCase):          for i, filter_content in enumerate(self.whitelist, start=1):              filters.append({                  "id": i, "content": filter_content, "description": None, "settings": {}, -                "additional_settings": {}, "created_at": now, "updated_at": now  # noqa: P103 +                "additional_settings": {}, "created_at": now, "updated_at": now              })          self.filter_list.add_list({              "id": 1, diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index 65595e959..e90291f62 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -1,7 +1,7 @@  import textwrap  import unittest  import unittest.mock -from datetime import datetime +from datetime import UTC, datetime  from textwrap import shorten  import discord @@ -41,7 +41,7 @@ class InformationCogTests(unittest.IsolatedAsyncioTestCase):          self.ctx.send.assert_called_once()          _, kwargs = self.ctx.send.call_args -        embed = kwargs.pop('embed') +        embed = kwargs.pop("embed")          self.assertEqual(embed.title, "Role information (Total 1 role)")          self.assertEqual(embed.colour, discord.Colour.og_blurple()) @@ -110,15 +110,15 @@ class UserInfractionHelperMethodTests(unittest.IsolatedAsyncioTestCase):          test_values = (              {                  "helper_method": self.cog.basic_user_infraction_counts, -                "expected_args": ("bot/infractions", {'hidden': 'False', 'user__id': str(self.member.id)}), +                "expected_args": ("bot/infractions", {"hidden": "False", "user__id": str(self.member.id)}),              },              {                  "helper_method": self.cog.expanded_user_infraction_counts, -                "expected_args": ("bot/infractions", {'user__id': str(self.member.id)}), +                "expected_args": ("bot/infractions", {"user__id": str(self.member.id)}),              },              {                  "helper_method": self.cog.user_nomination_counts, -                "expected_args": ("bot/nominations", {'user__id': str(self.member.id)}), +                "expected_args": ("bot/nominations", {"user__id": str(self.member.id)}),              },          ) @@ -241,19 +241,19 @@ class UserInfractionHelperMethodTests(unittest.IsolatedAsyncioTestCase):                  "expected_lines": ["No nominations"],              },              { -                "api response": [{'active': True}], +                "api response": [{"active": True}],                  "expected_lines": ["This user is **currently** nominated", "(1 nomination in total)"],              },              { -                "api response": [{'active': True}, {'active': False}], +                "api response": [{"active": True}, {"active": False}],                  "expected_lines": ["This user is **currently** nominated", "(2 nominations in total)"],              },              { -                "api response": [{'active': False}], +                "api response": [{"active": False}],                  "expected_lines": ["This user has 1 historical nomination, but is currently not nominated."],              },              { -                "api response": [{'active': False}, {'active': False}], +                "api response": [{"active": False}, {"active": False}],                  "expected_lines": ["This user has 2 historical nominations, but is currently not nominated."],              }, @@ -290,7 +290,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          user.nick = None          user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")          user.colour = 0 -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          embed = await self.cog.create_user_embed(ctx, user, False) @@ -312,7 +312,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          user.nick = "Cat lover"          user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")          user.colour = 0 -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          embed = await self.cog.create_user_embed(ctx, user, False) @@ -329,11 +329,11 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):      async def test_create_user_embed_ignores_everyone_role(self):          """Created `!user` embeds should not contain mention of the @everyone-role."""          ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=1)) -        admins_role = helpers.MockRole(name='Admins') +        admins_role = helpers.MockRole(name="Admins")          # A `MockMember` has the @Everyone role by default; we add the Admins to that.          user = helpers.MockMember(roles=[admins_role], colour=100) -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          embed = await self.cog.create_user_embed(ctx, user, False) @@ -354,13 +354,13 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          """The embed should contain expanded infractions and nomination info in mod channels."""          ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=50)) -        moderators_role = helpers.MockRole(name='Moderators') +        moderators_role = helpers.MockRole(name="Moderators")          infraction_counts.return_value = ("Infractions", "expanded infractions info")          nomination_counts.return_value = ("Nominations", "nomination info")          user = helpers.MockMember(id=314, roles=[moderators_role], colour=100) -        user.created_at = user.joined_at = datetime.utcfromtimestamp(1) +        user.created_at = user.joined_at = datetime.fromtimestamp(1, tz=UTC)          embed = await self.cog.create_user_embed(ctx, user, False)          infraction_counts.assert_called_once_with(user) @@ -394,13 +394,13 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          """The embed should contain only basic infraction data outside of mod channels."""          ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=100)) -        moderators_role = helpers.MockRole(name='Moderators') +        moderators_role = helpers.MockRole(name="Moderators")          infraction_counts.return_value = ("Infractions", "basic infractions info")          user_messages.return_value = ("Messages", "user message counts")          user = helpers.MockMember(id=314, roles=[moderators_role], colour=100) -        user.created_at = user.joined_at = datetime.utcfromtimestamp(1) +        user.created_at = user.joined_at = datetime.fromtimestamp(1, tz=UTC)          embed = await self.cog.create_user_embed(ctx, user, False)          infraction_counts.assert_called_once_with(user) @@ -444,10 +444,10 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          """The embed should be created with the colour of the top role, if a top role is available."""          ctx = helpers.MockContext() -        moderators_role = helpers.MockRole(name='Moderators') +        moderators_role = helpers.MockRole(name="Moderators")          user = helpers.MockMember(id=314, roles=[moderators_role], colour=100) -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          embed = await self.cog.create_user_embed(ctx, user, False)          self.assertEqual(embed.colour, discord.Colour(100)) @@ -465,7 +465,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          ctx = helpers.MockContext()          user = helpers.MockMember(id=217, colour=discord.Colour.default()) -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          embed = await self.cog.create_user_embed(ctx, user, False)          self.assertEqual(embed.colour, discord.Colour.og_blurple()) @@ -483,7 +483,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):          ctx = helpers.MockContext()          user = helpers.MockMember(id=217, colour=0) -        user.created_at = user.joined_at = datetime.utcnow() +        user.created_at = user.joined_at = datetime.now(UTC)          user.display_avatar.url = "avatar url"          embed = await self.cog.create_user_embed(ctx, user, False) @@ -644,6 +644,6 @@ class RuleCommandTests(unittest.IsolatedAsyncioTestCase):          for raw_user_input, expected_matched_rule_numbers in test_cases:              with self.subTest(identifier=raw_user_input):                  final_rule_numbers = await self.cog.rules(self.cog, self.ctx, args=raw_user_input) -                embed = self.ctx.send.call_args.kwargs['embed'] +                embed = self.ctx.send.call_args.kwargs["embed"]                  self.assertEqual(information.DEFAULT_RULES_DESCRIPTION, embed.description)                  self.assertEqual(expected_matched_rule_numbers, final_rule_numbers) diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py index b78328137..26ba770dc 100644 --- a/tests/bot/exts/moderation/infraction/test_infractions.py +++ b/tests/bot/exts/moderation/infraction/test_infractions.py @@ -270,10 +270,9 @@ class CleanBanTests(unittest.IsolatedAsyncioTestCase):          def inner(name):              if name == "ModManagement":                  return self.management_cog if enable_manage else None -            elif name == "Clean": +            if name == "Clean":                  return self.clean_cog if enable_clean else None -            else: -                return DEFAULT +            return DEFAULT          return inner      async def test_cleanban_falls_back_to_native_purge_without_clean_cog(self): diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py index 122935e37..25337673e 100644 --- a/tests/bot/exts/moderation/infraction/test_utils.py +++ b/tests/bot/exts/moderation/infraction/test_utils.py @@ -1,6 +1,6 @@  import unittest  from collections import namedtuple -from datetime import datetime +from datetime import UTC, datetime  from unittest.mock import AsyncMock, MagicMock, patch  from discord import Embed, Forbidden, HTTPException, NotFound @@ -136,7 +136,10 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):          """          test_cases = [              { -                "args": (dict(id=0, type="ban", reason=None, expires_at=datetime(2020, 2, 26, 9, 20)), self.user), +                "args": ( +                    dict(id=0, type="ban", reason=None, expires_at=datetime(2020, 2, 26, 9, 20, tzinfo=UTC)), +                    self.user, +                ),                  "expected_output": Embed(                      title=utils.INFRACTION_TITLE,                      description=utils.INFRACTION_DESCRIPTION_TEMPLATE.format( @@ -192,7 +195,10 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):                  "send_result": False              },              { -                "args": (dict(id=0, type="mute", reason="Test", expires_at=datetime(2020, 2, 26, 9, 20)), self.user), +                "args": ( +                    dict(id=0, type="mute", reason="Test", expires_at=datetime(2020, 2, 26, 9, 20, tzinfo=UTC)), +                    self.user, +                ),                  "expected_output": Embed(                      title=utils.INFRACTION_TITLE,                      description=utils.INFRACTION_DESCRIPTION_TEMPLATE.format( @@ -309,7 +315,7 @@ class TestPostInfraction(unittest.IsolatedAsyncioTestCase):      async def test_normal_post_infraction(self):          """Should return response from POST request if there are no errors.""" -        now = datetime.utcnow() +        now = datetime.now(UTC)          expected = {              "actor": self.ctx.author.id,              "hidden": True, diff --git a/tests/bot/exts/moderation/test_incidents.py b/tests/bot/exts/moderation/test_incidents.py index 53d98360c..1a02339d4 100644 --- a/tests/bot/exts/moderation/test_incidents.py +++ b/tests/bot/exts/moderation/test_incidents.py @@ -20,7 +20,7 @@ from tests.helpers import (      MockUser  ) -CURRENT_TIME = datetime.datetime(2022, 1, 1, tzinfo=datetime.timezone.utc) +CURRENT_TIME = datetime.datetime(2022, 1, 1, tzinfo=datetime.UTC)  class MockAsyncIterable: @@ -799,7 +799,7 @@ class TestMessageLinkEmbeds(TestIncidents):              "\n".join("Lets make a new line test".split()): "Lets\nmake\na...", -            'Hello, World!' * 300: ( +            "Hello, World!" * 300: (                  "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!"                  "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!"                  "Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!" diff --git a/tests/bot/exts/moderation/test_silence.py b/tests/bot/exts/moderation/test_silence.py index 2622f46a7..ec0b3bf43 100644 --- a/tests/bot/exts/moderation/test_silence.py +++ b/tests/bot/exts/moderation/test_silence.py @@ -1,7 +1,6 @@  import itertools  import unittest -from datetime import datetime, timezone -from typing import List, Tuple +from datetime import UTC, datetime  from unittest import mock  from unittest.mock import AsyncMock, Mock @@ -97,10 +96,12 @@ class SilenceNotifierTests(SilenceTest):          """Alert is skipped on first loop or not an increment of 900."""          test_cases = (0, 15, 5000)          for current_loop in test_cases: -            with self.subTest(current_loop=current_loop): -                with mock.patch.object(self.notifier, "_current_loop", new=current_loop): -                    await self.notifier._notifier() -                    self.alert_channel.send.assert_not_called() +            with ( +                self.subTest(current_loop=current_loop), +                mock.patch.object(self.notifier, "_current_loop", new=current_loop), +            ): +                await self.notifier._notifier() +                self.alert_channel.send.assert_not_called()  @autospec(silence.Silence, "previous_overwrites", "unsilence_timestamps", pass_mocks=False) @@ -203,7 +204,7 @@ class SilenceCogTests(SilenceTest):                  self.assertEqual((None,), member.move_to.call_args_list[0].args)      @staticmethod -    def create_erroneous_members() -> Tuple[List[MockMember], List[MockMember]]: +    def create_erroneous_members() -> tuple[list[MockMember], list[MockMember]]:          """          Helper method to generate a list of members that error out on move_to call. @@ -363,7 +364,7 @@ class RescheduleTests(RedisTestCase):          channels = [MockTextChannel(id=123), MockTextChannel(id=456)]          self.bot.get_channel.side_effect = channels          self.cog.unsilence_timestamps.items.return_value = [(123, 2000), (456, 3000)] -        silence.datetime.now.return_value = datetime.fromtimestamp(1000, tz=timezone.utc) +        silence.datetime.now.return_value = datetime.fromtimestamp(1000, tz=UTC)          self.cog._unsilence_wrapper = mock.MagicMock()          unsilence_return = self.cog._unsilence_wrapper.return_value @@ -426,17 +427,19 @@ class SilenceTests(SilenceTest):          targets = (MockTextChannel(), MockVoiceChannel(), None)          for (duration, message, was_silenced), target in itertools.product(test_cases, targets): -            with mock.patch.object(self.cog, "_set_silence_overwrites", return_value=was_silenced): -                with self.subTest(was_silenced=was_silenced, target=target, message=message): -                    with mock.patch.object(self.cog, "send_message") as send_message: -                        ctx = MockContext() -                        await self.cog.silence.callback(self.cog, ctx, target, duration) -                        send_message.assert_called_once_with( -                            message, -                            ctx.channel, -                            target or ctx.channel, -                            alert_target=was_silenced -                        ) +            with ( +                mock.patch.object(self.cog, "_set_silence_overwrites", return_value=was_silenced), +                self.subTest(was_silenced=was_silenced, target=target, message=message), +                mock.patch.object(self.cog, "send_message") as send_message +            ): +                ctx = MockContext() +                await self.cog.silence.callback(self.cog, ctx, target, duration) +                send_message.assert_called_once_with( +                    message, +                    ctx.channel, +                    target or ctx.channel, +                    alert_target=was_silenced +                )      @voice_sync_helper      async def test_sync_called(self, ctx, sync, kick): @@ -577,10 +580,10 @@ class SilenceTests(SilenceTest):          new_overwrite_dict = dict(self.voice_overwrite)          # Remove 'connect' & 'speak' keys because they were changed by the method. -        del prev_overwrite_dict['connect'] -        del prev_overwrite_dict['speak'] -        del new_overwrite_dict['connect'] -        del new_overwrite_dict['speak'] +        del prev_overwrite_dict["connect"] +        del prev_overwrite_dict["speak"] +        del new_overwrite_dict["connect"] +        del new_overwrite_dict["speak"]          self.assertDictEqual(prev_overwrite_dict, new_overwrite_dict) @@ -617,13 +620,13 @@ class SilenceTests(SilenceTest):          now_timestamp = 100          duration = 15          timestamp = now_timestamp + duration * 60 -        datetime_mock.now.return_value = datetime.fromtimestamp(now_timestamp, tz=timezone.utc) +        datetime_mock.now.return_value = datetime.fromtimestamp(now_timestamp, tz=UTC)          ctx = MockContext(channel=self.text_channel)          await self.cog.silence.callback(self.cog, ctx, duration)          self.cog.unsilence_timestamps.set.assert_awaited_once_with(ctx.channel.id, timestamp) -        datetime_mock.now.assert_called_once_with(tz=timezone.utc)  # Ensure it's using an aware dt. +        datetime_mock.now.assert_called_once_with(tz=UTC)  # Ensure it's using an aware dt.      async def test_cached_indefinite_time(self):          """A value of -1 was cached for a permanent silence.""" @@ -697,13 +700,15 @@ class UnsilenceTests(SilenceTest):              if target:                  target.overwrites_for.return_value = overwrite -            with mock.patch.object(self.cog, "_unsilence", return_value=was_unsilenced): -                with mock.patch.object(self.cog, "send_message") as send_message: -                    with self.subTest(was_unsilenced=was_unsilenced, overwrite=overwrite, target=target): -                        await self.cog.unsilence.callback(self.cog, ctx, channel=target) +            with ( +                mock.patch.object(self.cog, "_unsilence", return_value=was_unsilenced), +                mock.patch.object(self.cog, "send_message") as send_message, +                self.subTest(was_unsilenced=was_unsilenced, overwrite=overwrite, target=target), +            ): +                await self.cog.unsilence.callback(self.cog, ctx, channel=target) -                        call_args = (message, ctx.channel, target or ctx.channel) -                        send_message.assert_awaited_once_with(*call_args, alert_target=was_unsilenced) +                call_args = (message, ctx.channel, target or ctx.channel) +                send_message.assert_awaited_once_with(*call_args, alert_target=was_unsilenced)      async def test_skipped_already_unsilenced(self):          """Permissions were not set and `False` was returned for an already unsilenced channel.""" @@ -808,10 +813,10 @@ class UnsilenceTests(SilenceTest):                  new_overwrite_dict = dict(self.text_overwrite)                  # Remove these keys because they were modified by the unsilence. -                del prev_overwrite_dict['send_messages'] -                del prev_overwrite_dict['add_reactions'] -                del new_overwrite_dict['send_messages'] -                del new_overwrite_dict['add_reactions'] +                del prev_overwrite_dict["send_messages"] +                del prev_overwrite_dict["add_reactions"] +                del new_overwrite_dict["send_messages"] +                del new_overwrite_dict["add_reactions"]                  self.assertDictEqual(prev_overwrite_dict, new_overwrite_dict) @@ -826,10 +831,10 @@ class UnsilenceTests(SilenceTest):                  new_overwrite_dict = dict(self.voice_overwrite)                  # Remove these keys because they were modified by the unsilence. -                del prev_overwrite_dict['connect'] -                del prev_overwrite_dict['speak'] -                del new_overwrite_dict['connect'] -                del new_overwrite_dict['speak'] +                del prev_overwrite_dict["connect"] +                del prev_overwrite_dict["speak"] +                del new_overwrite_dict["connect"] +                del new_overwrite_dict["speak"]                  self.assertDictEqual(prev_overwrite_dict, new_overwrite_dict) diff --git a/tests/bot/exts/moderation/test_slowmode.py b/tests/bot/exts/moderation/test_slowmode.py index 5483b7a64..cf5101e16 100644 --- a/tests/bot/exts/moderation/test_slowmode.py +++ b/tests/bot/exts/moderation/test_slowmode.py @@ -17,24 +17,24 @@ class SlowmodeTests(unittest.IsolatedAsyncioTestCase):      async def test_get_slowmode_no_channel(self) -> None:          """Get slowmode without a given channel.""" -        self.ctx.channel = MockTextChannel(name='python-general', slowmode_delay=5) +        self.ctx.channel = MockTextChannel(name="python-general", slowmode_delay=5)          await self.cog.get_slowmode(self.cog, self.ctx, None)          self.ctx.send.assert_called_once_with("The slowmode delay for #python-general is 5 seconds.")      async def test_get_slowmode_with_channel(self) -> None:          """Get slowmode with a given channel.""" -        text_channel = MockTextChannel(name='python-language', slowmode_delay=2) +        text_channel = MockTextChannel(name="python-language", slowmode_delay=2)          await self.cog.get_slowmode(self.cog, self.ctx, text_channel) -        self.ctx.send.assert_called_once_with('The slowmode delay for #python-language is 2 seconds.') +        self.ctx.send.assert_called_once_with("The slowmode delay for #python-language is 2 seconds.")      async def test_set_slowmode_no_channel(self) -> None:          """Set slowmode without a given channel."""          test_cases = ( -            ('helpers', 23, True, f'{Emojis.check_mark} The slowmode delay for #helpers is now 23 seconds.'), -            ('mods', 76526, False, f'{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.'), -            ('admins', 97, True, f'{Emojis.check_mark} The slowmode delay for #admins is now 1 minute and 37 seconds.') +            ("helpers", 23, True, f"{Emojis.check_mark} The slowmode delay for #helpers is now 23 seconds."), +            ("mods", 76526, False, f"{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours."), +            ("admins", 97, True, f"{Emojis.check_mark} The slowmode delay for #admins is now 1 minute and 37 seconds.")          )          for channel_name, seconds, edited, result_msg in test_cases: @@ -60,9 +60,9 @@ class SlowmodeTests(unittest.IsolatedAsyncioTestCase):      async def test_set_slowmode_with_channel(self) -> None:          """Set slowmode with a given channel."""          test_cases = ( -            ('bot-commands', 12, True, f'{Emojis.check_mark} The slowmode delay for #bot-commands is now 12 seconds.'), -            ('mod-spam', 21, True, f'{Emojis.check_mark} The slowmode delay for #mod-spam is now 21 seconds.'), -            ('admin-spam', 4323598, False, f'{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.') +            ("bot-commands", 12, True, f"{Emojis.check_mark} The slowmode delay for #bot-commands is now 12 seconds."), +            ("mod-spam", 21, True, f"{Emojis.check_mark} The slowmode delay for #mod-spam is now 21 seconds."), +            ("admin-spam", 4323598, False, f"{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.")          )          for channel_name, seconds, edited, result_msg in test_cases: @@ -87,7 +87,7 @@ class SlowmodeTests(unittest.IsolatedAsyncioTestCase):      async def test_reset_slowmode_sets_delay_to_zero(self) -> None:          """Reset slowmode with a given channel.""" -        text_channel = MockTextChannel(name='meta', slowmode_delay=1) +        text_channel = MockTextChannel(name="meta", slowmode_delay=1)          self.cog.set_slowmode = mock.AsyncMock()          await self.cog.reset_slowmode(self.cog, self.ctx, text_channel) diff --git a/tests/bot/exts/recruitment/talentpool/test_review.py b/tests/bot/exts/recruitment/talentpool/test_review.py index f726fccc7..25622e91f 100644 --- a/tests/bot/exts/recruitment/talentpool/test_review.py +++ b/tests/bot/exts/recruitment/talentpool/test_review.py @@ -1,5 +1,5 @@  import unittest -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta  from unittest.mock import AsyncMock, Mock, patch  from bot.exts.recruitment.talentpool import _review @@ -61,8 +61,8 @@ class ReviewerTests(unittest.IsolatedAsyncioTestCase):      @patch("bot.exts.recruitment.talentpool._review.MIN_REVIEW_INTERVAL", timedelta(days=1))      async def test_is_ready_for_review(self):          """Tests for the `is_ready_for_review` function.""" -        too_recent = datetime.now(timezone.utc) - timedelta(hours=1) -        not_too_recent = datetime.now(timezone.utc) - timedelta(days=7) +        too_recent = datetime.now(UTC) - timedelta(hours=1) +        not_too_recent = datetime.now(UTC) - timedelta(days=7)          cases = (              # Only one review, and not too recent, so ready.              ( @@ -126,7 +126,7 @@ class ReviewerTests(unittest.IsolatedAsyncioTestCase):      @patch("bot.exts.recruitment.talentpool._review.MIN_NOMINATION_TIME", timedelta(days=7))      async def test_get_nomination_to_review(self):          """Test get_nomination_to_review function.""" -        now = datetime.now(timezone.utc) +        now = datetime.now(UTC)          # Each case contains a list of nominations, followed by the index in that list          # of the one that should be selected, or None if None should be returned @@ -184,7 +184,7 @@ class ReviewerTests(unittest.IsolatedAsyncioTestCase):      @patch("bot.exts.recruitment.talentpool._review.MIN_NOMINATION_TIME", timedelta(days=0))      async def test_get_nomination_to_review_order(self): -        now = datetime.now(timezone.utc) +        now = datetime.now(UTC)          # Each case in cases is a list of nominations in the order they should be chosen from first to last          cases = [ diff --git a/tests/bot/exts/test_cogs.py b/tests/bot/exts/test_cogs.py index f8e120262..99bc87120 100644 --- a/tests/bot/exts/test_cogs.py +++ b/tests/bot/exts/test_cogs.py @@ -50,7 +50,7 @@ class CommandNameTests(unittest.TestCase):                  yield obj      @staticmethod -    def get_qualified_names(command: commands.Command) -> t.List[str]: +    def get_qualified_names(command: commands.Command) -> list[str]:          """Return a list of all qualified names, including aliases, for the `command`."""          names = [f"{command.full_parent_name} {alias}".strip() for alias in command.aliases]          names.append(command.qualified_name) diff --git a/tests/bot/exts/utils/snekbox/test_io.py b/tests/bot/exts/utils/snekbox/test_io.py index bcf1162b8..4f7f49a5e 100644 --- a/tests/bot/exts/utils/snekbox/test_io.py +++ b/tests/bot/exts/utils/snekbox/test_io.py @@ -19,7 +19,7 @@ class SnekboxIOTests(TestCase):              (r"A\0\tB", "A__B"),              # Any other disallowed chars -> underscore              (r"\\.txt", "_.txt"), -            (r"A!@#$%^&*B, C()[]{}+=D.txt", "A_B_C_D.txt"),  # noqa: P103 +            (r"A!@#$%^&*B, C()[]{}+=D.txt", "A_B_C_D.txt"),              (" ", "_"),              # Normal file names should be unchanged              ("legal_file-name.txt", "legal_file-name.txt"), diff --git a/tests/bot/exts/utils/snekbox/test_snekbox.py b/tests/bot/exts/utils/snekbox/test_snekbox.py index 79ac8ea2c..fa28aade8 100644 --- a/tests/bot/exts/utils/snekbox/test_snekbox.py +++ b/tests/bot/exts/utils/snekbox/test_snekbox.py @@ -43,7 +43,7 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):              "files": [                  {                      "path": "main.py", -                    "content": b64encode("import random".encode()).decode() +                    "content": b64encode(b"import random").decode()                  }              ]          } @@ -72,45 +72,45 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):      async def test_codeblock_converter(self):          ctx = MockContext()          cases = ( -            ('print("Hello world!")', 'print("Hello world!")', 'non-formatted'), -            ('`print("Hello world!")`', 'print("Hello world!")', 'one line code block'), -            ('```\nprint("Hello world!")```', 'print("Hello world!")', 'multiline code block'), -            ('```py\nprint("Hello world!")```', 'print("Hello world!")', 'multiline python code block'), -            ('text```print("Hello world!")```text', 'print("Hello world!")', 'code block surrounded by text'), +            ('print("Hello world!")', 'print("Hello world!")', "non-formatted"), +            ('`print("Hello world!")`', 'print("Hello world!")', "one line code block"), +            ('```\nprint("Hello world!")```', 'print("Hello world!")', "multiline code block"), +            ('```py\nprint("Hello world!")```', 'print("Hello world!")', "multiline python code block"), +            ('text```print("Hello world!")```text', 'print("Hello world!")', "code block surrounded by text"),              ('```print("Hello world!")```\ntext\n```py\nprint("Hello world!")```', -             'print("Hello world!")\nprint("Hello world!")', 'two code blocks with text in-between'), +             'print("Hello world!")\nprint("Hello world!")', "two code blocks with text in-between"),              ('`print("Hello world!")`\ntext\n```print("How\'s it going?")```', -             'print("How\'s it going?")', 'code block preceded by inline code'), +             'print("How\'s it going?")', "code block preceded by inline code"),              ('`print("Hello world!")`\ntext\n`print("Hello world!")`', -             'print("Hello world!")', 'one inline code block of two') +             'print("Hello world!")', "one inline code block of two")          )          for case, expected, testname in cases: -            with self.subTest(msg=f'Extract code from {testname}.'): +            with self.subTest(msg=f"Extract code from {testname}."):                  self.assertEqual( -                    '\n'.join(await snekbox.CodeblockConverter.convert(ctx, case)), expected +                    "\n".join(await snekbox.CodeblockConverter.convert(ctx, case)), expected                  )      def test_prepare_timeit_input(self):          """Test the prepare_timeit_input codeblock detection.""" -        base_args = ('-m', 'timeit', '-s') +        base_args = ("-m", "timeit", "-s")          cases = ( -            (['print("Hello World")'], '', 'single block of code'), -            (['x = 1', 'print(x)'], 'x = 1', 'two blocks of code'), -            (['x = 1', 'print(x)', 'print("Some other code.")'], 'x = 1', 'three blocks of code') +            (['print("Hello World")'], "", "single block of code"), +            (["x = 1", "print(x)"], "x = 1", "two blocks of code"), +            (["x = 1", "print(x)", 'print("Some other code.")'], "x = 1", "three blocks of code")          )          for case, setup_code, test_name in cases:              setup = snekbox._cog.TIMEIT_SETUP_WRAPPER.format(setup=setup_code) -            expected = [*base_args, setup, '\n'.join(case[1:] if setup_code else case)] -            with self.subTest(msg=f'Test with {test_name} and expected return {expected}'): +            expected = [*base_args, setup, "\n".join(case[1:] if setup_code else case)] +            with self.subTest(msg=f"Test with {test_name} and expected return {expected}"):                  self.assertEqual(self.cog.prepare_timeit_input(case), expected)      def test_eval_result_message(self):          """EvalResult.get_message(), should return message."""          cases = ( -            ('ERROR', None, ('Your 3.11 eval job has failed', 'ERROR', '')), -            ('', 128 + snekbox._eval.SIGKILL, ('Your 3.11 eval job timed out or ran out of memory', '', '')), -            ('', 255, ('Your 3.11 eval job has failed', 'A fatal NsJail error occurred', '')) +            ("ERROR", None, ("Your 3.11 eval job has failed", "ERROR", "")), +            ("", 128 + snekbox._eval.SIGKILL, ("Your 3.11 eval job timed out or ran out of memory", "", "")), +            ("", 255, ("Your 3.11 eval job has failed", "A fatal NsJail error occurred", ""))          )          for stdout, returncode, expected in cases:              exp_msg, exp_err, exp_files_err = expected @@ -167,7 +167,7 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):                  msg = result.get_failed_files_str(char_max=10)                  self.assertEqual(msg, expected) -    @patch('bot.exts.utils.snekbox._eval.Signals', side_effect=ValueError) +    @patch("bot.exts.utils.snekbox._eval.Signals", side_effect=ValueError)      def test_eval_result_message_invalid_signal(self, _mock_signals: Mock):          result = EvalResult(stdout="", returncode=127)          self.assertEqual( @@ -177,7 +177,7 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          self.assertEqual(result.error_message, "")          self.assertEqual(result.files_error_message, "") -    @patch('bot.exts.utils.snekbox._eval.Signals') +    @patch("bot.exts.utils.snekbox._eval.Signals")      def test_eval_result_message_valid_signal(self, mock_signals: Mock):          mock_signals.return_value.name = "SIGTEST"          result = EvalResult(stdout="", returncode=127) @@ -189,9 +189,9 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):      def test_eval_result_status_emoji(self):          """Return emoji according to the eval result."""          cases = ( -            (' ', -1, ':warning:'), -            ('Hello world!', 0, ':white_check_mark:'), -            ('Invalid beard size', -1, ':x:') +            (" ", -1, ":warning:"), +            ("Hello world!", 0, ":white_check_mark:"), +            ("Invalid beard size", -1, ":x:")          )          for stdout, returncode, expected in cases:              with self.subTest(stdout=stdout, returncode=returncode, expected=expected): @@ -200,48 +200,48 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):      async def test_format_output(self):          """Test output formatting.""" -        self.cog.upload_output = AsyncMock(return_value='https://testificate.com/') +        self.cog.upload_output = AsyncMock(return_value="https://testificate.com/")          too_many_lines = ( -            '001 | v\n002 | e\n003 | r\n004 | y\n005 | l\n006 | o\n' -            '007 | n\n008 | g\n009 | b\n010 | e\n011 | a\n... (truncated - too many lines)' +            "001 | v\n002 | e\n003 | r\n004 | y\n005 | l\n006 | o\n" +            "007 | n\n008 | g\n009 | b\n010 | e\n011 | a\n... (truncated - too many lines)"          )          too_long_too_many_lines = (              "\n".join( -                f"{i:03d} | {line}" for i, line in enumerate(['verylongbeard' * 10] * 15, 1) +                f"{i:03d} | {line}" for i, line in enumerate(["verylongbeard" * 10] * 15, 1)              )[:1000] + "\n... (truncated - too long, too many lines)"          )          cases = ( -            ('', ('[No output]', None), 'No output'), -            ('My awesome output', ('My awesome output', None), 'One line output'), -            ('<@', ("<@\u200B", None), r'Convert <@ to <@\u200B'), -            ('<!@', ("<!@\u200B", None), r'Convert <!@ to <!@\u200B'), +            ("", ("[No output]", None), "No output"), +            ("My awesome output", ("My awesome output", None), "One line output"), +            ("<@", ("<@\u200B", None), r"Convert <@ to <@\u200B"), +            ("<!@", ("<!@\u200B", None), r"Convert <!@ to <!@\u200B"),              ( -                '\u202E\u202E\u202E', -                ('Code block escape attempt detected; will not output result', 'https://testificate.com/'), -                'Detect RIGHT-TO-LEFT OVERRIDE' +                "\u202E\u202E\u202E", +                ("Code block escape attempt detected; will not output result", "https://testificate.com/"), +                "Detect RIGHT-TO-LEFT OVERRIDE"              ),              ( -                '\u200B\u200B\u200B', -                ('Code block escape attempt detected; will not output result', 'https://testificate.com/'), -                'Detect ZERO WIDTH SPACE' +                "\u200B\u200B\u200B", +                ("Code block escape attempt detected; will not output result", "https://testificate.com/"), +                "Detect ZERO WIDTH SPACE"              ), -            ('long\nbeard', ('001 | long\n002 | beard', None), 'Two line output'), +            ("long\nbeard", ("001 | long\n002 | beard", None), "Two line output"),              ( -                'v\ne\nr\ny\nl\no\nn\ng\nb\ne\na\nr\nd', -                (too_many_lines, 'https://testificate.com/'), -                '12 lines output' +                "v\ne\nr\ny\nl\no\nn\ng\nb\ne\na\nr\nd", +                (too_many_lines, "https://testificate.com/"), +                "12 lines output"              ),              ( -                'verylongbeard' * 100, -                ('verylongbeard' * 76 + 'verylongbear\n... (truncated - too long)', 'https://testificate.com/'), -                '1300 characters output' +                "verylongbeard" * 100, +                ("verylongbeard" * 76 + "verylongbear\n... (truncated - too long)", "https://testificate.com/"), +                "1300 characters output"              ),              ( -                ('verylongbeard' * 10 + '\n') * 15, -                (too_long_too_many_lines, 'https://testificate.com/'), -                '15 lines, 1965 characters output' +                ("verylongbeard" * 10 + "\n") * 15, +                (too_long_too_many_lines, "https://testificate.com/"), +                "15 lines, 1965 characters output"              ),          )          for case, expected, testname in cases: @@ -257,10 +257,10 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          self.cog.send_job = AsyncMock(return_value=response)          self.cog.continue_job = AsyncMock(return_value=None) -        await self.cog.eval_command(self.cog, ctx=ctx, python_version='3.11', code=['MyAwesomeCode']) +        await self.cog.eval_command(self.cog, ctx=ctx, python_version="3.11", code=["MyAwesomeCode"])          job = EvalJob.from_code("MyAwesomeCode")          self.cog.send_job.assert_called_once_with(ctx, job) -        self.cog.continue_job.assert_called_once_with(ctx, response, 'eval') +        self.cog.continue_job.assert_called_once_with(ctx, response, "eval")      async def test_eval_command_evaluate_twice(self):          """Test the eval and re-eval command procedure.""" @@ -269,9 +269,9 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          ctx.command = MagicMock()          self.cog.send_job = AsyncMock(return_value=response)          self.cog.continue_job = AsyncMock() -        self.cog.continue_job.side_effect = (EvalJob.from_code('MyAwesomeFormattedCode'), None) +        self.cog.continue_job.side_effect = (EvalJob.from_code("MyAwesomeFormattedCode"), None) -        await self.cog.eval_command(self.cog, ctx=ctx, python_version='3.11', code=['MyAwesomeCode']) +        await self.cog.eval_command(self.cog, ctx=ctx, python_version="3.11", code=["MyAwesomeCode"])          expected_job = EvalJob.from_code("MyAwesomeFormattedCode")          self.cog.send_job.assert_called_with(ctx, expected_job) @@ -285,7 +285,7 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          async def delay_with_side_effect(*args, **kwargs) -> dict:              """Delay the post_job call to ensure the job runs long enough to conflict."""              await asyncio.sleep(1) -            return {'stdout': '', 'returncode': 0} +            return {"stdout": "", "returncode": 0}          self.cog.post_job = AsyncMock(side_effect=delay_with_side_effect)          with self.assertRaises(LockedResourceError): @@ -299,32 +299,32 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          ctx = MockContext()          ctx.message = MockMessage()          ctx.send = AsyncMock() -        ctx.author = MockUser(mention='@LemonLemonishBeard#0042') +        ctx.author = MockUser(mention="@LemonLemonishBeard#0042")          eval_result = EvalResult("", 0)          self.cog.post_job = AsyncMock(return_value=eval_result) -        self.cog.format_output = AsyncMock(return_value=('[No output]', None)) +        self.cog.format_output = AsyncMock(return_value=("[No output]", None))          self.cog.upload_output = AsyncMock()  # Should not be called          mocked_filter_cog = MagicMock()          mocked_filter_cog.filter_snekbox_output = AsyncMock(return_value=(False, []))          self.bot.get_cog.return_value = mocked_filter_cog -        job = EvalJob.from_code('MyAwesomeCode') +        job = EvalJob.from_code("MyAwesomeCode")          await self.cog.send_job(ctx, job),          ctx.send.assert_called_once()          self.assertEqual(              ctx.send.call_args.args[0], -            '@LemonLemonishBeard#0042 :warning: Your 3.11 eval job has completed ' -            'with return code 0.\n\n```\n[No output]\n```' +            "@LemonLemonishBeard#0042 :warning: Your 3.11 eval job has completed " +            "with return code 0.\n\n```\n[No output]\n```"          ) -        allowed_mentions = ctx.send.call_args.kwargs['allowed_mentions'] +        allowed_mentions = ctx.send.call_args.kwargs["allowed_mentions"]          expected_allowed_mentions = AllowedMentions(everyone=False, roles=False, users=[ctx.author])          self.assertEqual(allowed_mentions.to_dict(), expected_allowed_mentions.to_dict())          self.cog.post_job.assert_called_once_with(job) -        self.cog.format_output.assert_called_once_with('') +        self.cog.format_output.assert_called_once_with("")          self.cog.upload_output.assert_not_called()      async def test_send_job_with_paste_link(self): @@ -332,11 +332,11 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          ctx = MockContext()          ctx.message = MockMessage()          ctx.send = AsyncMock() -        ctx.author.mention = '@LemonLemonishBeard#0042' +        ctx.author.mention = "@LemonLemonishBeard#0042"          eval_result = EvalResult("Way too long beard", 0)          self.cog.post_job = AsyncMock(return_value=eval_result) -        self.cog.format_output = AsyncMock(return_value=('Way too long beard', 'lookatmybeard.com')) +        self.cog.format_output = AsyncMock(return_value=("Way too long beard", "lookatmybeard.com"))          mocked_filter_cog = MagicMock()          mocked_filter_cog.filter_snekbox_output = AsyncMock(return_value=(False, [])) @@ -348,20 +348,20 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          ctx.send.assert_called_once()          self.assertEqual(              ctx.send.call_args.args[0], -            '@LemonLemonishBeard#0042 :white_check_mark: Your 3.11 eval job ' -            'has completed with return code 0.' -            '\n\n```\nWay too long beard\n```\nFull output: lookatmybeard.com' +            "@LemonLemonishBeard#0042 :white_check_mark: Your 3.11 eval job " +            "has completed with return code 0." +            "\n\n```\nWay too long beard\n```\nFull output: lookatmybeard.com"          )          self.cog.post_job.assert_called_once_with(job) -        self.cog.format_output.assert_called_once_with('Way too long beard') +        self.cog.format_output.assert_called_once_with("Way too long beard")      async def test_send_job_with_non_zero_eval(self):          """Test the send_job function with a code returning a non-zero code."""          ctx = MockContext()          ctx.message = MockMessage()          ctx.send = AsyncMock() -        ctx.author.mention = '@LemonLemonishBeard#0042' +        ctx.author.mention = "@LemonLemonishBeard#0042"          eval_result = EvalResult("ERROR", 127)          self.cog.post_job = AsyncMock(return_value=eval_result) @@ -377,8 +377,8 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          ctx.send.assert_called_once()          self.assertEqual(              ctx.send.call_args.args[0], -            '@LemonLemonishBeard#0042 :x: Your 3.11 eval job has completed with return code 127.' -            '\n\n```\nERROR\n```' +            "@LemonLemonishBeard#0042 :x: Your 3.11 eval job has completed with return code 127." +            "\n\n```\nERROR\n```"          )          self.cog.post_job.assert_called_once_with(job) @@ -436,11 +436,11 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          self.bot.wait_for.assert_has_awaits(              (                  call( -                    'message_edit', +                    "message_edit",                      check=partial_mock(snekbox._cog.predicate_message_edit, ctx),                      timeout=snekbox._cog.REDO_TIMEOUT,                  ), -                call('reaction_add', check=partial_mock(snekbox._cog.predicate_emoji_reaction, ctx), timeout=10) +                call("reaction_add", check=partial_mock(snekbox._cog.predicate_emoji_reaction, ctx), timeout=10)              )          )          ctx.message.add_reaction.assert_called_once_with(snekbox._cog.REDO_EMOJI) @@ -483,17 +483,17 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):      def test_predicate_message_edit(self):          """Test the predicate_message_edit function.""" -        msg0 = MockMessage(id=1, content='abc') -        msg1 = MockMessage(id=2, content='abcdef') -        msg2 = MockMessage(id=1, content='abcdef') +        msg0 = MockMessage(id=1, content="abc") +        msg1 = MockMessage(id=2, content="abcdef") +        msg2 = MockMessage(id=1, content="abcdef")          cases = ( -            (msg0, msg0, False, 'same ID, same content'), -            (msg0, msg1, False, 'different ID, different content'), -            (msg0, msg2, True, 'same ID, different content') +            (msg0, msg0, False, "same ID, same content"), +            (msg0, msg1, False, "different ID, different content"), +            (msg0, msg2, True, "same ID, different content")          )          for ctx_msg, new_msg, expected, testname in cases: -            with self.subTest(msg=f'Messages with {testname} return {expected}'): +            with self.subTest(msg=f"Messages with {testname} return {expected}"):                  ctx = MockContext(message=ctx_msg)                  actual = snekbox._cog.predicate_message_edit(ctx, ctx_msg, new_msg)                  self.assertEqual(actual, expected) @@ -509,16 +509,16 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase):          invalid_reaction_id.__str__.return_value = snekbox._cog.REDO_EMOJI          invalid_user_id = MockUser(id=42)          invalid_reaction_str = MockReaction(message=MockMessage(id=1)) -        invalid_reaction_str.__str__.return_value = ':longbeard:' +        invalid_reaction_str.__str__.return_value = ":longbeard:"          cases = ( -            (invalid_reaction_id, valid_user, False, 'invalid reaction ID'), -            (valid_reaction, invalid_user_id, False, 'invalid user ID'), -            (invalid_reaction_str, valid_user, False, 'invalid reaction __str__'), -            (valid_reaction, valid_user, True, 'matching attributes') +            (invalid_reaction_id, valid_user, False, "invalid reaction ID"), +            (valid_reaction, invalid_user_id, False, "invalid user ID"), +            (invalid_reaction_str, valid_user, False, "invalid reaction __str__"), +            (valid_reaction, valid_user, True, "matching attributes")          )          for reaction, user, expected, testname in cases: -            with self.subTest(msg=f'Test with {testname} and expected return {expected}'): +            with self.subTest(msg=f"Test with {testname} and expected return {expected}"):                  actual = snekbox._cog.predicate_emoji_reaction(valid_ctx, reaction, user)                  self.assertEqual(actual, expected) diff --git a/tests/bot/resources/test_resources.py b/tests/bot/resources/test_resources.py index 73937cfa6..77f92f100 100644 --- a/tests/bot/resources/test_resources.py +++ b/tests/bot/resources/test_resources.py @@ -7,7 +7,7 @@ class ResourceValidationTests(unittest.TestCase):      """Validates resources used by the bot."""      def test_stars_valid(self):          """The resource `bot/resources/stars.json` should contain a list of strings.""" -        path = Path('bot', 'resources', 'stars.json') +        path = Path("bot", "resources", "stars.json")          content = path.read_text()          data = json.loads(content) diff --git a/tests/bot/test_constants.py b/tests/bot/test_constants.py index f10d6fbe8..3492021ce 100644 --- a/tests/bot/test_constants.py +++ b/tests/bot/test_constants.py @@ -23,11 +23,7 @@ def is_annotation_instance(value: typing.Any, annotation: typing.Any) -> bool:  def is_any_instance(value: typing.Any, types: typing.Collection) -> bool:      """Return True if `value` is an instance of any type in `types`.""" -    for type_ in types: -        if is_annotation_instance(value, type_): -            return True - -    return False +    return any(is_annotation_instance(value, type_) for type_ in types)  class ConstantsTests(unittest.TestCase): @@ -39,7 +35,7 @@ class ConstantsTests(unittest.TestCase):          sections = (              cls              for (name, cls) in inspect.getmembers(constants) -            if hasattr(cls, 'section') and isinstance(cls, type) +            if hasattr(cls, "section") and isinstance(cls, type)          )          for section in sections:              for name, annotation in section.__annotations__.items(): diff --git a/tests/bot/test_converters.py b/tests/bot/test_converters.py index 1bb678db2..e5ccf27f7 100644 --- a/tests/bot/test_converters.py +++ b/tests/bot/test_converters.py @@ -1,6 +1,6 @@  import re  import unittest -from datetime import MAXYEAR, datetime, timezone +from datetime import MAXYEAR, UTC, datetime  from unittest.mock import MagicMock, patch  from dateutil.relativedelta import relativedelta @@ -15,13 +15,13 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):      @classmethod      def setUpClass(cls):          cls.context = MagicMock -        cls.context.author = 'bob' +        cls.context.author = "bob" -        cls.fixed_utc_now = datetime.fromisoformat('2019-01-01T00:00:00+00:00') +        cls.fixed_utc_now = datetime.fromisoformat("2019-01-01T00:00:00+00:00")      async def test_package_name_for_valid(self):          """PackageName returns valid package names unchanged.""" -        test_values = ('foo', 'le_mon', 'num83r') +        test_values = ("foo", "le_mon", "num83r")          for name in test_values:              with self.subTest(identifier=name): @@ -30,47 +30,46 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):      async def test_package_name_for_invalid(self):          """PackageName raises the proper exception for invalid package names.""" -        test_values = ('text_with_a_dot.', 'UpperCaseName', 'dashed-name') +        test_values = ("text_with_a_dot.", "UpperCaseName", "dashed-name")          for name in test_values: -            with self.subTest(identifier=name): -                with self.assertRaises(BadArgument): -                    await PackageName.convert(self.context, name) +            with self.subTest(identifier=name), self.assertRaises(BadArgument): +                await PackageName.convert(self.context, name)      async def test_duration_converter_for_valid(self):          """Duration returns the correct `datetime` for valid duration strings."""          test_values = (              # Simple duration strings -            ('1Y', {"years": 1}), -            ('1y', {"years": 1}), -            ('1year', {"years": 1}), -            ('1years', {"years": 1}), -            ('1m', {"months": 1}), -            ('1month', {"months": 1}), -            ('1months', {"months": 1}), -            ('1w', {"weeks": 1}), -            ('1W', {"weeks": 1}), -            ('1week', {"weeks": 1}), -            ('1weeks', {"weeks": 1}), -            ('1d', {"days": 1}), -            ('1D', {"days": 1}), -            ('1day', {"days": 1}), -            ('1days', {"days": 1}), -            ('1h', {"hours": 1}), -            ('1H', {"hours": 1}), -            ('1hour', {"hours": 1}), -            ('1hours', {"hours": 1}), -            ('1M', {"minutes": 1}), -            ('1minute', {"minutes": 1}), -            ('1minutes', {"minutes": 1}), -            ('1s', {"seconds": 1}), -            ('1S', {"seconds": 1}), -            ('1second', {"seconds": 1}), -            ('1seconds', {"seconds": 1}), +            ("1Y", {"years": 1}), +            ("1y", {"years": 1}), +            ("1year", {"years": 1}), +            ("1years", {"years": 1}), +            ("1m", {"months": 1}), +            ("1month", {"months": 1}), +            ("1months", {"months": 1}), +            ("1w", {"weeks": 1}), +            ("1W", {"weeks": 1}), +            ("1week", {"weeks": 1}), +            ("1weeks", {"weeks": 1}), +            ("1d", {"days": 1}), +            ("1D", {"days": 1}), +            ("1day", {"days": 1}), +            ("1days", {"days": 1}), +            ("1h", {"hours": 1}), +            ("1H", {"hours": 1}), +            ("1hour", {"hours": 1}), +            ("1hours", {"hours": 1}), +            ("1M", {"minutes": 1}), +            ("1minute", {"minutes": 1}), +            ("1minutes", {"minutes": 1}), +            ("1s", {"seconds": 1}), +            ("1S", {"seconds": 1}), +            ("1second", {"seconds": 1}), +            ("1seconds", {"seconds": 1}),              # Complex duration strings              ( -                '1y1m1w1d1H1M1S', +                "1y1m1w1d1H1M1S",                  {                      "years": 1,                      "months": 1, @@ -81,13 +80,13 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):                      "seconds": 1                  }              ), -            ('5y100S', {"years": 5, "seconds": 100}), -            ('2w28H', {"weeks": 2, "hours": 28}), +            ("5y100S", {"years": 5, "seconds": 100}), +            ("2w28H", {"weeks": 2, "hours": 28}),              # Duration strings with spaces -            ('1 year 2 months', {"years": 1, "months": 2}), -            ('1d 2H', {"days": 1, "hours": 2}), -            ('1 week2 days', {"weeks": 1, "days": 2}), +            ("1 year 2 months", {"years": 1, "months": 2}), +            ("1d 2H", {"days": 1, "hours": 2}), +            ("1 week2 days", {"weeks": 1, "days": 2}),          )          converter = Duration() @@ -95,7 +94,7 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):          for duration, duration_dict in test_values:              expected_datetime = self.fixed_utc_now + relativedelta(**duration_dict) -            with patch('bot.converters.datetime') as mock_datetime: +            with patch("bot.converters.datetime") as mock_datetime:                  mock_datetime.now.return_value = self.fixed_utc_now                  with self.subTest(duration=duration, duration_dict=duration_dict): @@ -106,19 +105,19 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):          """Duration raises the right exception for invalid duration strings."""          test_values = (              # Units in wrong order -            '1d1w', -            '1s1y', +            "1d1w", +            "1s1y",              # Duplicated units -            '1 year 2 years', -            '1 M 10 minutes', +            "1 year 2 years", +            "1 M 10 minutes",              # Unknown substrings -            '1MVes', -            '1y3breads', +            "1MVes", +            "1y3breads",              # Missing amount -            'ym', +            "ym",              # Incorrect whitespace              " 1y", @@ -126,15 +125,15 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):              "1y  1m",              # Garbage -            'Guido van Rossum', -            'lemon lemon lemon lemon lemon lemon lemon', +            "Guido van Rossum", +            "lemon lemon lemon lemon lemon lemon lemon",          )          converter = Duration()          for invalid_duration in test_values:              with self.subTest(invalid_duration=invalid_duration): -                exception_message = f'`{invalid_duration}` is not a valid duration string.' +                exception_message = f"`{invalid_duration}` is not a valid duration string."                  with self.assertRaisesRegex(BadArgument, re.escape(exception_message)):                      await converter.convert(self.context, invalid_duration) @@ -151,44 +150,43 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):      async def test_isodatetime_converter_for_valid(self):          """ISODateTime converter returns correct datetime for valid datetime string.""" -        utc = timezone.utc          test_values = (              # `YYYY-mm-ddTHH:MM:SSZ` | `YYYY-mm-dd HH:MM:SSZ` -            ('2019-09-02T02:03:05Z', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 02:03:05Z', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), +            ("2019-09-02T02:03:05Z", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 02:03:05Z", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)),              # `YYYY-mm-ddTHH:MM:SS±HH:MM` | `YYYY-mm-dd HH:MM:SS±HH:MM` -            ('2019-09-02T03:18:05+01:15', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 03:18:05+01:15', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02T00:48:05-01:15', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 00:48:05-01:15', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), +            ("2019-09-02T03:18:05+01:15", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 03:18:05+01:15", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02T00:48:05-01:15", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 00:48:05-01:15", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)),              # `YYYY-mm-ddTHH:MM:SS±HHMM` | `YYYY-mm-dd HH:MM:SS±HHMM` -            ('2019-09-02T03:18:05+0115', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 03:18:05+0115', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02T00:48:05-0115', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 00:48:05-0115', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), +            ("2019-09-02T03:18:05+0115", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 03:18:05+0115", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02T00:48:05-0115", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 00:48:05-0115", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)),              # `YYYY-mm-ddTHH:MM:SS±HH` | `YYYY-mm-dd HH:MM:SS±HH` -            ('2019-09-02 03:03:05+01', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02T01:03:05-01', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), +            ("2019-09-02 03:03:05+01", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02T01:03:05-01", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)),              # `YYYY-mm-ddTHH:MM:SS` | `YYYY-mm-dd HH:MM:SS` -            ('2019-09-02T02:03:05', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), -            ('2019-09-02 02:03:05', datetime(2019, 9, 2, 2, 3, 5, tzinfo=utc)), +            ("2019-09-02T02:03:05", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)), +            ("2019-09-02 02:03:05", datetime(2019, 9, 2, 2, 3, 5, tzinfo=UTC)),              # `YYYY-mm-ddTHH:MM` | `YYYY-mm-dd HH:MM` -            ('2019-11-12T09:15', datetime(2019, 11, 12, 9, 15, tzinfo=utc)), -            ('2019-11-12 09:15', datetime(2019, 11, 12, 9, 15, tzinfo=utc)), +            ("2019-11-12T09:15", datetime(2019, 11, 12, 9, 15, tzinfo=UTC)), +            ("2019-11-12 09:15", datetime(2019, 11, 12, 9, 15, tzinfo=UTC)),              # `YYYY-mm-dd` -            ('2019-04-01', datetime(2019, 4, 1, tzinfo=utc)), +            ("2019-04-01", datetime(2019, 4, 1, tzinfo=UTC)),              # `YYYY-mm` -            ('2019-02-01', datetime(2019, 2, 1, tzinfo=utc)), +            ("2019-02-01", datetime(2019, 2, 1, tzinfo=UTC)),              # `YYYY` -            ('2025', datetime(2025, 1, 1, tzinfo=utc)), +            ("2025", datetime(2025, 1, 1, tzinfo=UTC)),          )          converter = ISODateTime() @@ -202,19 +200,19 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):          """ISODateTime converter raises the correct exception for invalid datetime strings."""          test_values = (              # Make sure it doesn't interfere with the Duration converter -            '1Y', -            '1d', -            '1H', +            "1Y", +            "1d", +            "1H",              # Check if it fails when only providing the optional time part -            '10:10:10', -            '10:00', +            "10:10:10", +            "10:00",              # Invalid date format -            '19-01-01', +            "19-01-01",              # Other non-valid strings -            'fisk the tag master', +            "fisk the tag master",          )          converter = ISODateTime() @@ -249,6 +247,8 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):          )          converter = HushDurationConverter()          for invalid_minutes_string, exception_message in test_values: -            with self.subTest(invalid_minutes_string=invalid_minutes_string, exception_message=exception_message): -                with self.assertRaisesRegex(BadArgument, re.escape(exception_message)): -                    await converter.convert(self.context, invalid_minutes_string) +            with ( +                self.subTest(invalid_minutes_string=invalid_minutes_string, exception_message=exception_message), +                self.assertRaisesRegex(BadArgument, re.escape(exception_message)), +            ): +                await converter.convert(self.context, invalid_minutes_string) diff --git a/tests/bot/test_decorators.py b/tests/bot/test_decorators.py index 3d450caa0..6a04123a7 100644 --- a/tests/bot/test_decorators.py +++ b/tests/bot/test_decorators.py @@ -142,6 +142,8 @@ class InWhitelistTests(unittest.TestCase):              with unittest.mock.patch("bot.decorators.commands.check", new=lambda predicate: predicate):                  predicate = in_whitelist(**test_case.kwargs) -            with self.subTest(test_description=test_case.description): -                with self.assertRaisesRegex(InWhitelistCheckFailure, exception_message): -                    predicate(test_case.ctx) +            with ( +                self.subTest(test_description=test_case.description), +                self.assertRaisesRegex(InWhitelistCheckFailure, exception_message), +            ): +                predicate(test_case.ctx) diff --git a/tests/bot/test_pagination.py b/tests/bot/test_pagination.py index 630f2516d..cf23f1948 100644 --- a/tests/bot/test_pagination.py +++ b/tests/bot/test_pagination.py @@ -8,39 +8,39 @@ class LinePaginatorTests(TestCase):      def setUp(self):          """Create a paginator for the test method.""" -        self.paginator = pagination.LinePaginator(prefix='', suffix='', max_size=30, +        self.paginator = pagination.LinePaginator(prefix="", suffix="", max_size=30,                                                    scale_to_size=50)      def test_add_line_works_on_small_lines(self):          """`add_line` should allow small lines to be added.""" -        self.paginator.add_line('x' * (self.paginator.max_size - 3)) +        self.paginator.add_line("x" * (self.paginator.max_size - 3))          # Note that the page isn't added to _pages until it's full.          self.assertEqual(len(self.paginator._pages), 0)      def test_add_line_works_on_long_lines(self):          """After additional lines after `max_size` is exceeded should go on the next page.""" -        self.paginator.add_line('x' * self.paginator.max_size) +        self.paginator.add_line("x" * self.paginator.max_size)          self.assertEqual(len(self.paginator._pages), 0)          # Any additional lines should start a new page after `max_size` is exceeded. -        self.paginator.add_line('x') +        self.paginator.add_line("x")          self.assertEqual(len(self.paginator._pages), 1)      def test_add_line_continuation(self):          """When `scale_to_size` is exceeded, remaining words should be split onto the next page.""" -        self.paginator.add_line('zyz ' * (self.paginator.scale_to_size//4 + 1)) +        self.paginator.add_line("zyz " * (self.paginator.scale_to_size//4 + 1))          self.assertEqual(len(self.paginator._pages), 1)      def test_add_line_no_continuation(self):          """If adding a new line to an existing page would exceed `max_size`, it should start a new          page rather than using continuation.          """ -        self.paginator.add_line('z' * (self.paginator.max_size - 3)) -        self.paginator.add_line('z') +        self.paginator.add_line("z" * (self.paginator.max_size - 3)) +        self.paginator.add_line("z")          self.assertEqual(len(self.paginator._pages), 1)      def test_add_line_truncates_very_long_words(self):          """`add_line` should truncate if a single long word exceeds `scale_to_size`.""" -        self.paginator.add_line('x' * (self.paginator.scale_to_size + 1)) +        self.paginator.add_line("x" * (self.paginator.scale_to_size + 1))          # Note: item at index 1 is the truncated line, index 0 is prefix -        self.assertEqual(self.paginator._current_page[1], 'x' * self.paginator.scale_to_size) +        self.assertEqual(self.paginator._current_page[1], "x" * self.paginator.scale_to_size) diff --git a/tests/bot/utils/test_message_cache.py b/tests/bot/utils/test_message_cache.py index 04bfd28d1..ad3f4e8b6 100644 --- a/tests/bot/utils/test_message_cache.py +++ b/tests/bot/utils/test_message_cache.py @@ -157,9 +157,8 @@ class TestMessageCache(unittest.TestCase):              cache.append(msg)          for current_loop in test_cases: -            with self.subTest(current_loop=current_loop): -                with self.assertRaises(IndexError): -                    cache[current_loop] +            with self.subTest(current_loop=current_loop), self.assertRaises(IndexError): +                cache[current_loop]      def test_slicing_with_unfilled_cache(self):          """Test if slicing returns the correct messages if the cache is not yet fully filled.""" diff --git a/tests/bot/utils/test_time.py b/tests/bot/utils/test_time.py index 120d65176..6244a3548 100644 --- a/tests/bot/utils/test_time.py +++ b/tests/bot/utils/test_time.py @@ -1,5 +1,5 @@  import unittest -from datetime import datetime, timezone +from datetime import UTC, datetime  from dateutil.relativedelta import relativedelta @@ -13,23 +13,23 @@ class TimeTests(unittest.TestCase):          """humanize_delta should be able to handle unknown units, and will not abort."""          # Does not abort for unknown units, as the unit name is checked          # against the attribute of the relativedelta instance. -        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision='elephants', max_units=2) -        self.assertEqual(actual, '2 days and 2 hours') +        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision="elephants", max_units=2) +        self.assertEqual(actual, "2 days and 2 hours")      def test_humanize_delta_handle_high_units(self):          """humanize_delta should be able to handle very high units."""          # Very high maximum units, but it only ever iterates over          # each value the relativedelta might have. -        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision='hours', max_units=20) -        self.assertEqual(actual, '2 days and 2 hours') +        actual = time.humanize_delta(relativedelta(days=2, hours=2), precision="hours", max_units=20) +        self.assertEqual(actual, "2 days and 2 hours")      def test_humanize_delta_should_normal_usage(self):          """Testing humanize delta."""          test_cases = ( -            (relativedelta(days=2), 'seconds', 1, '2 days'), -            (relativedelta(days=2, hours=2), 'seconds', 2, '2 days and 2 hours'), -            (relativedelta(days=2, hours=2), 'seconds', 1, '2 days'), -            (relativedelta(days=2, hours=2), 'days', 2, '2 days'), +            (relativedelta(days=2), "seconds", 1, "2 days"), +            (relativedelta(days=2, hours=2), "seconds", 2, "2 days and 2 hours"), +            (relativedelta(days=2, hours=2), "seconds", 1, "2 days"), +            (relativedelta(days=2, hours=2), "days", 2, "2 days"),          )          for delta, precision, max_units, expected in test_cases: @@ -43,8 +43,8 @@ class TimeTests(unittest.TestCase):          for max_units in test_cases:              with self.subTest(max_units=max_units), self.assertRaises(ValueError) as error: -                time.humanize_delta(relativedelta(days=2, hours=2), precision='hours', max_units=max_units) -            self.assertEqual(str(error.exception), 'max_units must be positive.') +                time.humanize_delta(relativedelta(days=2, hours=2), precision="hours", max_units=max_units) +            self.assertEqual(str(error.exception), "max_units must be positive.")      def test_format_with_duration_none_expiry(self):          """format_with_duration should work for None expiry.""" @@ -52,9 +52,9 @@ class TimeTests(unittest.TestCase):              (None, None, None, None),              # To make sure that date_from and max_units are not touched -            (None, 'Why hello there!', None, None), -            (None, None, float('inf'), None), -            (None, 'Why hello there!', float('inf'), None), +            (None, "Why hello there!", None, None), +            (None, None, float("inf"), None), +            (None, "Why hello there!", float("inf"), None),          )          for expiry, date_from, max_units, expected in test_cases: @@ -64,10 +64,10 @@ class TimeTests(unittest.TestCase):      def test_format_with_duration_custom_units(self):          """format_with_duration should work for custom max_units."""          test_cases = ( -            ('3000-12-12T00:01:00Z', datetime(3000, 12, 11, 12, 5, 5, tzinfo=timezone.utc), 6, -             '<t:32533488060:f> (11 hours, 55 minutes and 55 seconds)'), -            ('3000-11-23T20:09:00Z', datetime(3000, 4, 25, 20, 15, tzinfo=timezone.utc), 20, -             '<t:32531918940:f> (6 months, 28 days, 23 hours and 54 minutes)') +            ("3000-12-12T00:01:00Z", datetime(3000, 12, 11, 12, 5, 5, tzinfo=UTC), 6, +             "<t:32533488060:f> (11 hours, 55 minutes and 55 seconds)"), +            ("3000-11-23T20:09:00Z", datetime(3000, 4, 25, 20, 15, tzinfo=UTC), 20, +             "<t:32531918940:f> (6 months, 28 days, 23 hours and 54 minutes)")          )          for expiry, date_from, max_units, expected in test_cases: @@ -76,23 +76,22 @@ class TimeTests(unittest.TestCase):      def test_format_with_duration_normal_usage(self):          """format_with_duration should work for normal usage, across various durations.""" -        utc = timezone.utc          test_cases = ( -            ('2019-12-12T00:01:00Z', datetime(2019, 12, 11, 12, 0, 5, tzinfo=utc), 2, -                '<t:1576108860:f> (12 hours and 55 seconds)'), -            ('2019-12-12T00:01:00Z', datetime(2019, 12, 11, 12, 0, 5, tzinfo=utc), 1, '<t:1576108860:f> (12 hours)'), -            ('2019-12-12T00:00:00Z', datetime(2019, 12, 11, 23, 59, tzinfo=utc), 2, '<t:1576108800:f> (1 minute)'), -            ('2019-11-23T20:09:00Z', datetime(2019, 11, 15, 20, 15, tzinfo=utc), 2, -                '<t:1574539740:f> (7 days and 23 hours)'), -            ('2019-11-23T20:09:00Z', datetime(2019, 4, 25, 20, 15, tzinfo=utc), 2, -                '<t:1574539740:f> (6 months and 28 days)'), -            ('2019-11-23T20:58:00Z', datetime(2019, 11, 23, 20, 53, tzinfo=utc), 2, '<t:1574542680:f> (5 minutes)'), -            ('2019-11-24T00:00:00Z', datetime(2019, 11, 23, 23, 59, 0, tzinfo=utc), 2, '<t:1574553600:f> (1 minute)'), -            ('2019-11-23T23:59:00Z', datetime(2017, 7, 21, 23, 0, tzinfo=utc), 2, -             '<t:1574553540:f> (2 years and 4 months)'), -            ('2019-11-23T23:59:00Z', datetime(2019, 11, 23, 23, 49, 5, tzinfo=utc), 2, -             '<t:1574553540:f> (9 minutes and 55 seconds)'), -            (None, datetime(2019, 11, 23, 23, 49, 5), 2, None), +            ("2019-12-12T00:01:00Z", datetime(2019, 12, 11, 12, 0, 5, tzinfo=UTC), 2, +                "<t:1576108860:f> (12 hours and 55 seconds)"), +            ("2019-12-12T00:01:00Z", datetime(2019, 12, 11, 12, 0, 5, tzinfo=UTC), 1, "<t:1576108860:f> (12 hours)"), +            ("2019-12-12T00:00:00Z", datetime(2019, 12, 11, 23, 59, tzinfo=UTC), 2, "<t:1576108800:f> (1 minute)"), +            ("2019-11-23T20:09:00Z", datetime(2019, 11, 15, 20, 15, tzinfo=UTC), 2, +                "<t:1574539740:f> (7 days and 23 hours)"), +            ("2019-11-23T20:09:00Z", datetime(2019, 4, 25, 20, 15, tzinfo=UTC), 2, +                "<t:1574539740:f> (6 months and 28 days)"), +            ("2019-11-23T20:58:00Z", datetime(2019, 11, 23, 20, 53, tzinfo=UTC), 2, "<t:1574542680:f> (5 minutes)"), +            ("2019-11-24T00:00:00Z", datetime(2019, 11, 23, 23, 59, 0, tzinfo=UTC), 2, "<t:1574553600:f> (1 minute)"), +            ("2019-11-23T23:59:00Z", datetime(2017, 7, 21, 23, 0, tzinfo=UTC), 2, +             "<t:1574553540:f> (2 years and 4 months)"), +            ("2019-11-23T23:59:00Z", datetime(2019, 11, 23, 23, 49, 5, tzinfo=UTC), 2, +             "<t:1574553540:f> (9 minutes and 55 seconds)"), +            (None, datetime(2019, 11, 23, 23, 49, 5, tzinfo=UTC), 2, None),          )          for expiry, date_from, max_units, expected in test_cases: @@ -106,8 +105,8 @@ class TimeTests(unittest.TestCase):      def test_until_expiration_with_duration_custom_units(self):          """until_expiration should work for custom max_units."""          test_cases = ( -            ('3000-12-12T00:01:00Z', '<t:32533488060:R>'), -            ('3000-11-23T20:09:00Z', '<t:32531918940:R>') +            ("3000-12-12T00:01:00Z", "<t:32533488060:R>"), +            ("3000-11-23T20:09:00Z", "<t:32531918940:R>")          )          for expiry, expected in test_cases: @@ -117,11 +116,11 @@ class TimeTests(unittest.TestCase):      def test_until_expiration_normal_usage(self):          """until_expiration should work for normal usage, across various durations."""          test_cases = ( -            ('3000-12-12T00:01:00Z', '<t:32533488060:R>'), -            ('3000-12-12T00:01:00Z', '<t:32533488060:R>'), -            ('3000-12-12T00:00:00Z', '<t:32533488000:R>'), -            ('3000-11-23T20:09:00Z', '<t:32531918940:R>'), -            ('3000-11-23T20:09:00Z', '<t:32531918940:R>'), +            ("3000-12-12T00:01:00Z", "<t:32533488060:R>"), +            ("3000-12-12T00:01:00Z", "<t:32533488060:R>"), +            ("3000-12-12T00:00:00Z", "<t:32533488000:R>"), +            ("3000-11-23T20:09:00Z", "<t:32531918940:R>"), +            ("3000-11-23T20:09:00Z", "<t:32531918940:R>"),          )          for expiry, expected in test_cases: diff --git a/tests/helpers.py b/tests/helpers.py index 020f1aee5..bb12c4977 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -5,7 +5,7 @@ import itertools  import logging  import unittest.mock  from asyncio import AbstractEventLoop -from typing import Iterable, Optional +from collections.abc import Iterable  import discord  from aiohttp import ClientSession @@ -79,7 +79,7 @@ class CustomMockMixin:      additional_spec_asyncs = None      def __init__(self, **kwargs): -        name = kwargs.pop('name', None)  # `name` has special meaning for Mock classes, so we need to set it manually. +        name = kwargs.pop("name", None)  # `name` has special meaning for Mock classes, so we need to set it manually.          super().__init__(spec_set=self.spec_set, **kwargs)          if self.additional_spec_asyncs: @@ -101,7 +101,7 @@ class CustomMockMixin:          This override will look for an attribute called `child_mock_type` and use that as the type of the child mock.          """          _new_name = kw.get("_new_name") -        if _new_name in self.__dict__['_spec_asyncs']: +        if _new_name in self.__dict__["_spec_asyncs"]:              return unittest.mock.AsyncMock(**kw)          _type = type(self) @@ -121,23 +121,23 @@ class CustomMockMixin:  # Create a guild instance to get a realistic Mock of `discord.Guild`  guild_data = { -    'id': 1, -    'name': 'guild', -    'region': 'Europe', -    'verification_level': 2, -    'default_notications': 1, -    'afk_timeout': 100, -    'icon': "icon.png", -    'banner': 'banner.png', -    'mfa_level': 1, -    'splash': 'splash.png', -    'system_channel_id': 464033278631084042, -    'description': 'mocking is fun', -    'max_presences': 10_000, -    'max_members': 100_000, -    'preferred_locale': 'UTC', -    'owner_id': 1, -    'afk_channel_id': 464033278631084042, +    "id": 1, +    "name": "guild", +    "region": "Europe", +    "verification_level": 2, +    "default_notications": 1, +    "afk_timeout": 100, +    "icon": "icon.png", +    "banner": "banner.png", +    "mfa_level": 1, +    "splash": "splash.png", +    "system_channel_id": 464033278631084042, +    "description": "mocking is fun", +    "max_presences": 10_000, +    "max_members": 100_000, +    "preferred_locale": "UTC", +    "owner_id": 1, +    "afk_channel_id": 464033278631084042,  }  guild_instance = discord.Guild(data=guild_data, state=unittest.mock.MagicMock()) @@ -170,8 +170,8 @@ class MockGuild(CustomMockMixin, unittest.mock.Mock, HashableMixin):      """      spec_set = guild_instance -    def __init__(self, roles: Optional[Iterable[MockRole]] = None, **kwargs) -> None: -        default_kwargs = {'id': next(self.discord_id), 'members': [], "chunked": True} +    def __init__(self, roles: Iterable[MockRole] | None = None, **kwargs) -> None: +        default_kwargs = {"id": next(self.discord_id), "members": [], "chunked": True}          super().__init__(**collections.ChainMap(kwargs, default_kwargs))          self.roles = [MockRole(name="@everyone", position=1, id=0)] @@ -180,7 +180,7 @@ class MockGuild(CustomMockMixin, unittest.mock.Mock, HashableMixin):  # Create a Role instance to get a realistic Mock of `discord.Role` -role_data = {'name': 'role', 'id': 1} +role_data = {"name": "role", "id": 1}  role_instance = discord.Role(guild=guild_instance, state=unittest.mock.MagicMock(), data=role_data) @@ -195,11 +195,11 @@ class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):      def __init__(self, **kwargs) -> None:          default_kwargs = { -            'id': next(self.discord_id), -            'name': 'role', -            'position': 1, -            'colour': discord.Colour(0xdeadbf), -            'permissions': discord.Permissions(), +            "id": next(self.discord_id), +            "name": "role", +            "position": 1, +            "colour": discord.Colour(0xdeadbf), +            "permissions": discord.Permissions(),          }          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) @@ -209,8 +209,8 @@ class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):          if isinstance(self.permissions, int):              self.permissions = discord.Permissions(self.permissions) -        if 'mention' not in kwargs: -            self.mention = f'&{self.name}' +        if "mention" not in kwargs: +            self.mention = f"&{self.name}"      def __lt__(self, other):          """Simplified position-based comparisons similar to those of `discord.Role`.""" @@ -222,7 +222,7 @@ class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):  # Create a Member instance to get a realistic Mock of `discord.Member` -member_data = {'user': 'lemon', 'roles': [1], 'flags': 2} +member_data = {"user": "lemon", "roles": [1], "flags": 2}  state_mock = unittest.mock.MagicMock()  member_instance = discord.Member(data=member_data, guild=guild_instance, state=state_mock) @@ -236,8 +236,8 @@ class MockMember(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin      """      spec_set = member_instance -    def __init__(self, roles: Optional[Iterable[MockRole]] = None, **kwargs) -> None: -        default_kwargs = {'name': 'member', 'id': next(self.discord_id), 'bot': False, "pending": False} +    def __init__(self, roles: Iterable[MockRole] | None = None, **kwargs) -> None: +        default_kwargs = {"name": "member", "id": next(self.discord_id), "bot": False, "pending": False}          super().__init__(**collections.ChainMap(kwargs, default_kwargs))          self.roles = [MockRole(name="@everyone", position=1, id=0)] @@ -245,7 +245,7 @@ class MockMember(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin              self.roles.extend(roles)          self.top_role = max(self.roles) -        if 'mention' not in kwargs: +        if "mention" not in kwargs:              self.mention = f"@{self.name}" @@ -269,10 +269,10 @@ class MockUser(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):      spec_set = user_instance      def __init__(self, **kwargs) -> None: -        default_kwargs = {'name': 'user', 'id': next(self.discord_id), 'bot': False} +        default_kwargs = {"name": "user", "id": next(self.discord_id), "bot": False}          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) -        if 'mention' not in kwargs: +        if "mention" not in kwargs:              self.mention = f"@{self.name}" @@ -331,16 +331,16 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock):  # Create a TextChannel instance to get a realistic MagicMock of `discord.TextChannel`  channel_data = { -    'id': 1, -    'type': 'TextChannel', -    'name': 'channel', -    'parent_id': 1234567890, -    'topic': 'topic', -    'position': 1, -    'nsfw': False, -    'last_message_id': 1, -    'bitrate': 1337, -    'user_limit': 25, +    "id": 1, +    "type": "TextChannel", +    "name": "channel", +    "parent_id": 1234567890, +    "topic": "topic", +    "position": 1, +    "nsfw": False, +    "last_message_id": 1, +    "bitrate": 1337, +    "user_limit": 25,  }  state = unittest.mock.MagicMock()  guild = unittest.mock.MagicMock() @@ -360,10 +360,10 @@ class MockTextChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):      spec_set = text_channel_instance      def __init__(self, **kwargs) -> None: -        default_kwargs = {'id': next(self.discord_id), 'name': 'channel', 'guild': MockGuild()} +        default_kwargs = {"id": next(self.discord_id), "name": "channel", "guild": MockGuild()}          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) -        if 'mention' not in kwargs: +        if "mention" not in kwargs:              self.mention = f"#{self.name}" @@ -377,10 +377,10 @@ class MockVoiceChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):      spec_set = voice_channel_instance      def __init__(self, **kwargs) -> None: -        default_kwargs = {'id': next(self.discord_id), 'name': 'channel', 'guild': MockGuild()} +        default_kwargs = {"id": next(self.discord_id), "name": "channel", "guild": MockGuild()}          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) -        if 'mention' not in kwargs: +        if "mention" not in kwargs:              self.mention = f"#{self.name}" @@ -401,16 +401,16 @@ class MockDMChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):      spec_set = dm_channel_instance      def __init__(self, **kwargs) -> None: -        default_kwargs = {'id': next(self.discord_id), 'recipient': MockUser(), "me": MockUser(), 'guild': None} +        default_kwargs = {"id": next(self.discord_id), "recipient": MockUser(), "me": MockUser(), "guild": None}          super().__init__(**collections.ChainMap(kwargs, default_kwargs))  # Create CategoryChannel instance to get a realistic MagicMock of `discord.CategoryChannel`  category_channel_data = { -    'id': 1, -    'type': discord.ChannelType.category, -    'name': 'category', -    'position': 1, +    "id": 1, +    "type": discord.ChannelType.category, +    "name": "category", +    "position": 1,  }  state = unittest.mock.MagicMock() @@ -422,26 +422,26 @@ category_channel_instance = discord.CategoryChannel(  class MockCategoryChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):      def __init__(self, **kwargs) -> None: -        default_kwargs = {'id': next(self.discord_id)} +        default_kwargs = {"id": next(self.discord_id)}          super().__init__(**collections.ChainMap(kwargs, default_kwargs))  # Create a Message instance to get a realistic MagicMock of `discord.Message`  message_data = { -    'id': 1, -    'webhook_id': 431341013479718912, -    'attachments': [], -    'embeds': [], -    'application': {"id": 4, "description": "A Python Bot", "name": "Python Discord", "icon": None}, -    'activity': 'mocking', -    'channel': unittest.mock.MagicMock(), -    'edited_timestamp': '2019-10-14T15:33:48+00:00', -    'type': 'message', -    'pinned': False, -    'mention_everyone': False, -    'tts': None, -    'content': 'content', -    'nonce': None, +    "id": 1, +    "webhook_id": 431341013479718912, +    "attachments": [], +    "embeds": [], +    "application": {"id": 4, "description": "A Python Bot", "name": "Python Discord", "icon": None}, +    "activity": "mocking", +    "channel": unittest.mock.MagicMock(), +    "edited_timestamp": "2019-10-14T15:33:48+00:00", +    "type": "message", +    "pinned": False, +    "mention_everyone": False, +    "tts": None, +    "content": "content", +    "nonce": None,  }  state = unittest.mock.MagicMock()  channel = unittest.mock.MagicMock() @@ -470,13 +470,13 @@ class MockContext(CustomMockMixin, unittest.mock.MagicMock):      def __init__(self, **kwargs) -> None:          super().__init__(**kwargs) -        self.me = kwargs.get('me', MockMember()) -        self.bot = kwargs.get('bot', MockBot()) -        self.guild = kwargs.get('guild', MockGuild()) -        self.author = kwargs.get('author', MockMember()) -        self.channel = kwargs.get('channel', MockTextChannel()) -        self.message = kwargs.get('message', MockMessage()) -        self.invoked_from_error_handler = kwargs.get('invoked_from_error_handler', False) +        self.me = kwargs.get("me", MockMember()) +        self.bot = kwargs.get("bot", MockBot()) +        self.guild = kwargs.get("guild", MockGuild()) +        self.author = kwargs.get("author", MockMember()) +        self.channel = kwargs.get("channel", MockTextChannel()) +        self.message = kwargs.get("message", MockMessage()) +        self.invoked_from_error_handler = kwargs.get("invoked_from_error_handler", False)  class MockInteraction(CustomMockMixin, unittest.mock.MagicMock): @@ -489,13 +489,13 @@ class MockInteraction(CustomMockMixin, unittest.mock.MagicMock):      def __init__(self, **kwargs) -> None:          super().__init__(**kwargs) -        self.me = kwargs.get('me', MockMember()) -        self.client = kwargs.get('client', MockBot()) -        self.guild = kwargs.get('guild', MockGuild()) -        self.user = kwargs.get('user', MockMember()) -        self.channel = kwargs.get('channel', MockTextChannel()) -        self.message = kwargs.get('message', MockMessage()) -        self.invoked_from_error_handler = kwargs.get('invoked_from_error_handler', False) +        self.me = kwargs.get("me", MockMember()) +        self.client = kwargs.get("client", MockBot()) +        self.guild = kwargs.get("guild", MockGuild()) +        self.user = kwargs.get("user", MockMember()) +        self.channel = kwargs.get("channel", MockTextChannel()) +        self.message = kwargs.get("message", MockMessage()) +        self.invoked_from_error_handler = kwargs.get("invoked_from_error_handler", False)  attachment_instance = discord.Attachment(data=unittest.mock.MagicMock(id=1), state=unittest.mock.MagicMock()) @@ -543,10 +543,10 @@ class MockMessage(CustomMockMixin, unittest.mock.MagicMock):      spec_set = message_instance      def __init__(self, **kwargs) -> None: -        default_kwargs = {'attachments': []} +        default_kwargs = {"attachments": []}          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) -        self.author = kwargs.get('author', MockMember()) -        self.channel = kwargs.get('channel', MockTextChannel()) +        self.author = kwargs.get("author", MockMember()) +        self.channel = kwargs.get("channel", MockTextChannel())  class MockInteractionMessage(MockMessage): @@ -556,10 +556,9 @@ class MockInteractionMessage(MockMessage):      Instances of this class will follow the specifications of `discord.InteractionMessage` instances. For more      information, see the `MockGuild` docstring.      """ -    pass -emoji_data = {'require_colons': True, 'managed': True, 'id': 1, 'name': 'hyperlemon'} +emoji_data = {"require_colons": True, "managed": True, "id": 1, "name": "hyperlemon"}  emoji_instance = discord.Emoji(guild=MockGuild(), state=unittest.mock.MagicMock(), data=emoji_data) @@ -574,10 +573,10 @@ class MockEmoji(CustomMockMixin, unittest.mock.MagicMock):      def __init__(self, **kwargs) -> None:          super().__init__(**kwargs) -        self.guild = kwargs.get('guild', MockGuild()) +        self.guild = kwargs.get("guild", MockGuild()) -partial_emoji_instance = discord.PartialEmoji(animated=False, name='guido') +partial_emoji_instance = discord.PartialEmoji(animated=False, name="guido")  class MockPartialEmoji(CustomMockMixin, unittest.mock.MagicMock): @@ -590,7 +589,7 @@ class MockPartialEmoji(CustomMockMixin, unittest.mock.MagicMock):      spec_set = partial_emoji_instance -reaction_instance = discord.Reaction(message=MockMessage(), data={'me': True}, emoji=MockEmoji()) +reaction_instance = discord.Reaction(message=MockMessage(), data={"me": True}, emoji=MockEmoji())  class MockReaction(CustomMockMixin, unittest.mock.MagicMock): @@ -605,8 +604,8 @@ class MockReaction(CustomMockMixin, unittest.mock.MagicMock):      def __init__(self, **kwargs) -> None:          _users = kwargs.pop("users", [])          super().__init__(**kwargs) -        self.emoji = kwargs.get('emoji', MockEmoji()) -        self.message = kwargs.get('message', MockMessage()) +        self.emoji = kwargs.get("emoji", MockEmoji()) +        self.message = kwargs.get("message", MockMessage())          user_iterator = unittest.mock.AsyncMock()          user_iterator.__aiter__.return_value = _users diff --git a/tests/test_base.py b/tests/test_base.py index 365805a71..f1fb1a514 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -30,15 +30,19 @@ class LoggingTestCaseTests(unittest.TestCase):              r"1 logs of DEBUG or higher were triggered on root:\n"              r'<LogRecord: tests\.test_base, [\d]+, .+[/\\]tests[/\\]test_base\.py, [\d]+, "Log!">'          ) -        with self.assertRaisesRegex(AssertionError, msg_regex): -            with LoggingTestCase.assertNotLogs(self, level=logging.DEBUG): -                self.log.debug("Log!") +        with ( +            self.assertRaisesRegex(AssertionError, msg_regex), +            LoggingTestCase.assertNotLogs(self, level=logging.DEBUG), +        ): +            self.log.debug("Log!")      def test_assert_not_logs_reraises_unexpected_exception_in_managed_context(self):          """Test if LoggingTestCase.assertNotLogs reraises an unexpected exception.""" -        with self.assertRaises(ValueError, msg="test exception"): -            with LoggingTestCase.assertNotLogs(self, level=logging.DEBUG): -                raise ValueError("test exception") +        with ( +            self.assertRaises(ValueError, msg="test exception"), +            LoggingTestCase.assertNotLogs(self, level=logging.DEBUG), +        ): +            raise ValueError("test exception")      def test_assert_not_logs_restores_old_logging_settings(self):          """Test if LoggingTestCase.assertNotLogs reraises an unexpected exception.""" @@ -56,9 +60,8 @@ class LoggingTestCaseTests(unittest.TestCase):      def test_logging_test_case_works_with_logger_instance(self):          """Test if the LoggingTestCase captures logging for provided logger."""          log = get_logger("new_logger") -        with self.assertRaises(AssertionError): -            with LoggingTestCase.assertNotLogs(self, logger=log): -                log.info("Hello, this should raise an AssertionError") +        with self.assertRaises(AssertionError), LoggingTestCase.assertNotLogs(self, logger=log): +            log.info("Hello, this should raise an AssertionError")      def test_logging_test_case_respects_alternative_logger(self):          """Test if LoggingTestCase only checks the provided logger.""" diff --git a/tests/test_helpers.py b/tests/test_helpers.py index b2686b1d0..fa7d0eb44 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -144,13 +144,13 @@ class DiscordMocksTests(unittest.TestCase):      def test_mocks_allows_access_to_attributes_part_of_spec(self):          """Accessing attributes that are valid for the objects they mock should succeed."""          mocks = ( -            (helpers.MockGuild(), 'name'), -            (helpers.MockRole(), 'hoist'), -            (helpers.MockMember(), 'display_name'), -            (helpers.MockBot(), 'user'), -            (helpers.MockContext(), 'invoked_with'), -            (helpers.MockTextChannel(), 'last_message'), -            (helpers.MockMessage(), 'mention_everyone'), +            (helpers.MockGuild(), "name"), +            (helpers.MockRole(), "hoist"), +            (helpers.MockMember(), "display_name"), +            (helpers.MockBot(), "user"), +            (helpers.MockContext(), "invoked_with"), +            (helpers.MockTextChannel(), "last_message"), +            (helpers.MockMessage(), "mention_everyone"),          )          for mock, valid_attribute in mocks: @@ -161,8 +161,8 @@ class DiscordMocksTests(unittest.TestCase):                      msg = f"accessing valid attribute `{valid_attribute}` raised an AttributeError"                      self.fail(msg) -    @unittest.mock.patch(f'{__name__}.DiscordMocksTests.subTest') -    @unittest.mock.patch(f'{__name__}.getattr') +    @unittest.mock.patch(f"{__name__}.DiscordMocksTests.subTest") +    @unittest.mock.patch(f"{__name__}.getattr")      def test_mock_allows_access_to_attributes_test(self, mock_getattr, mock_subtest):          """The valid attribute test should raise an AssertionError after an AttributeError."""          mock_getattr.side_effect = AttributeError @@ -184,9 +184,8 @@ class DiscordMocksTests(unittest.TestCase):          )          for mock in mocks: -            with self.subTest(mock=mock): -                with self.assertRaises(AttributeError): -                    mock.the_cake_is_a_lie +            with self.subTest(mock=mock), self.assertRaises(AttributeError): +                mock.the_cake_is_a_lie  # noqa: B018      def test_mocks_use_mention_when_provided_as_kwarg(self):          """The mock should use the passed `mention` instead of the default one if present.""" @@ -333,9 +332,9 @@ class MockObjectTests(unittest.TestCase):              (helpers.MockBot, "owner_id"),              (helpers.MockContext, "command_failed"),              (helpers.MockMessage, "mention_everyone"), -            (helpers.MockEmoji, 'managed'), -            (helpers.MockPartialEmoji, 'url'), -            (helpers.MockReaction, 'me'), +            (helpers.MockEmoji, "managed"), +            (helpers.MockPartialEmoji, "url"), +            (helpers.MockReaction, "me"),          )          for mock_type, valid_attribute in test_values: | 
