From 43b6fee9eba12a6836530029a642cba6e7e505f0 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 19 Mar 2022 16:34:01 +0000 Subject: Use bot-core scheduling and member util functions --- tests/bot/exts/backend/sync/test_cog.py | 2 +- tests/bot/exts/filters/test_filtering.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index fdd0ab74a..7dff38f96 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -60,7 +60,7 @@ class SyncCogTestCase(unittest.IsolatedAsyncioTestCase): class SyncCogTests(SyncCogTestCase): """Tests for the Sync cog.""" - @mock.patch("bot.utils.scheduling.create_task") + @mock.patch("botcore.utils.scheduling.create_task") @mock.patch.object(Sync, "sync_guild", new_callable=mock.MagicMock) def test_sync_cog_init(self, sync_guild, create_task): """Should instantiate syncers and run a sync for the guild.""" diff --git a/tests/bot/exts/filters/test_filtering.py b/tests/bot/exts/filters/test_filtering.py index 8ae59c1f1..bd26532f1 100644 --- a/tests/bot/exts/filters/test_filtering.py +++ b/tests/bot/exts/filters/test_filtering.py @@ -11,7 +11,7 @@ class FilteringCogTests(unittest.IsolatedAsyncioTestCase): def setUp(self): """Instantiate the bot and cog.""" self.bot = MockBot() - with patch("bot.utils.scheduling.create_task", new=lambda task, **_: task.close()): + with patch("botcore.utils.scheduling.create_task", new=lambda task, **_: task.close()): self.cog = filtering.Filtering(self.bot) @autospec(filtering.Filtering, "_get_filterlist_items", pass_mocks=False, return_value=["TOKEN"]) -- cgit v1.2.3 From 047705ac91c2997ccb509ea4e1fb3fad38840412 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 31 Mar 2022 20:46:45 +0100 Subject: Remove async stats and site api wrapper We now source them from bot-core, so no need to have them here too. --- bot/api.py | 102 --------------------- bot/async_stats.py | 40 -------- bot/converters.py | 2 +- bot/exts/backend/error_handler.py | 2 +- bot/exts/backend/sync/_cog.py | 2 +- bot/exts/backend/sync/_syncers.py | 2 +- bot/exts/filters/filter_lists.py | 2 +- bot/exts/filters/filtering.py | 2 +- bot/exts/fun/off_topic_names.py | 2 +- bot/exts/info/doc/_cog.py | 2 +- bot/exts/info/information.py | 2 +- bot/exts/moderation/infraction/_scheduler.py | 2 +- bot/exts/moderation/infraction/_utils.py | 2 +- bot/exts/moderation/voice_gate.py | 2 +- bot/exts/moderation/watchchannels/_watchchannel.py | 2 +- bot/exts/recruitment/talentpool/_cog.py | 2 +- bot/exts/recruitment/talentpool/_review.py | 2 +- tests/bot/exts/backend/sync/test_base.py | 3 +- tests/bot/exts/backend/sync/test_cog.py | 2 +- tests/bot/exts/backend/test_error_handler.py | 2 +- tests/bot/exts/moderation/infraction/test_utils.py | 2 +- tests/bot/test_api.py | 66 ------------- tests/helpers.py | 4 +- 23 files changed, 22 insertions(+), 229 deletions(-) delete mode 100644 bot/api.py delete mode 100644 bot/async_stats.py delete mode 100644 tests/bot/test_api.py (limited to 'tests') diff --git a/bot/api.py b/bot/api.py deleted file mode 100644 index 856f7c865..000000000 --- a/bot/api.py +++ /dev/null @@ -1,102 +0,0 @@ -import asyncio -from typing import Optional -from urllib.parse import quote as quote_url - -import aiohttp - -from bot.log import get_logger - -from .constants import Keys, URLs - -log = get_logger(__name__) - - -class ResponseCodeError(ValueError): - """Raised when a non-OK HTTP response is received.""" - - def __init__( - self, - response: aiohttp.ClientResponse, - response_json: Optional[dict] = None, - response_text: str = "" - ): - self.status = response.status - self.response_json = response_json or {} - self.response_text = response_text - self.response = response - - def __str__(self): - response = self.response_json if self.response_json else self.response_text - return f"Status: {self.status} Response: {response}" - - -class APIClient: - """Django Site API wrapper.""" - - # These are class attributes so they can be seen when being mocked for tests. - # See commit 22a55534ef13990815a6f69d361e2a12693075d5 for details. - session: Optional[aiohttp.ClientSession] = None - loop: asyncio.AbstractEventLoop = None - - def __init__(self, **session_kwargs): - auth_headers = { - 'Authorization': f"Token {Keys.site_api}" - } - - if 'headers' in session_kwargs: - session_kwargs['headers'].update(auth_headers) - else: - session_kwargs['headers'] = auth_headers - - # aiohttp will complain if APIClient gets instantiated outside a coroutine. Thankfully, we - # don't and shouldn't need to do that, so we can avoid scheduling a task to create it. - self.session = aiohttp.ClientSession(**session_kwargs) - - @staticmethod - def _url_for(endpoint: str) -> str: - return f"{URLs.site_api_schema}{URLs.site_api}/{quote_url(endpoint)}" - - async def close(self) -> None: - """Close the aiohttp session.""" - await self.session.close() - - async def maybe_raise_for_status(self, response: aiohttp.ClientResponse, should_raise: bool) -> None: - """Raise ResponseCodeError for non-OK response if an exception should be raised.""" - if should_raise and response.status >= 400: - try: - response_json = await response.json() - raise ResponseCodeError(response=response, response_json=response_json) - except aiohttp.ContentTypeError: - response_text = await response.text() - raise ResponseCodeError(response=response, response_text=response_text) - - async def request(self, method: str, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> dict: - """Send an HTTP request to the site API and return the JSON response.""" - async with self.session.request(method.upper(), self._url_for(endpoint), **kwargs) as resp: - await self.maybe_raise_for_status(resp, raise_for_status) - return await resp.json() - - async def get(self, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> dict: - """Site API GET.""" - return await self.request("GET", endpoint, raise_for_status=raise_for_status, **kwargs) - - async def patch(self, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> dict: - """Site API PATCH.""" - return await self.request("PATCH", endpoint, raise_for_status=raise_for_status, **kwargs) - - async def post(self, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> dict: - """Site API POST.""" - return await self.request("POST", endpoint, raise_for_status=raise_for_status, **kwargs) - - async def put(self, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> dict: - """Site API PUT.""" - return await self.request("PUT", endpoint, raise_for_status=raise_for_status, **kwargs) - - async def delete(self, endpoint: str, *, raise_for_status: bool = True, **kwargs) -> Optional[dict]: - """Site API DELETE.""" - async with self.session.delete(self._url_for(endpoint), **kwargs) as resp: - if resp.status == 204: - return None - - await self.maybe_raise_for_status(resp, raise_for_status) - return await resp.json() diff --git a/bot/async_stats.py b/bot/async_stats.py deleted file mode 100644 index 0303de7a1..000000000 --- a/bot/async_stats.py +++ /dev/null @@ -1,40 +0,0 @@ -import asyncio -import socket - -from botcore.utils import scheduling -from statsd.client.base import StatsClientBase - - -class AsyncStatsClient(StatsClientBase): - """An async transport method for statsd communication.""" - - def __init__( - self, - loop: asyncio.AbstractEventLoop, - host: str = 'localhost', - port: int = 8125, - prefix: str = None - ): - """Create a new client.""" - family, _, _, _, addr = socket.getaddrinfo( - host, port, socket.AF_INET, socket.SOCK_DGRAM)[0] - self._addr = addr - self._prefix = prefix - self._loop = loop - self._transport = None - - async def create_socket(self) -> None: - """Use the loop.create_datagram_endpoint method to create a socket.""" - self._transport, _ = await self._loop.create_datagram_endpoint( - asyncio.DatagramProtocol, - family=socket.AF_INET, - remote_addr=self._addr - ) - - def _send(self, data: str) -> None: - """Start an async task to send data to statsd.""" - scheduling.create_task(self._async_send(data), event_loop=self._loop) - - async def _async_send(self, data: str) -> None: - """Send data to the statsd server using the async transport.""" - self._transport.sendto(data.encode('ascii'), self._addr) diff --git a/bot/converters.py b/bot/converters.py index e819e4713..a3f4630a0 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -8,13 +8,13 @@ from ssl import CertificateError import dateutil.parser import discord from aiohttp import ClientConnectorError +from botcore.site_api import ResponseCodeError from botcore.utils.regex import DISCORD_INVITE from dateutil.relativedelta import relativedelta from discord.ext.commands import BadArgument, Bot, Context, Converter, IDConverter, MemberConverter, UserConverter from discord.utils import escape_markdown, snowflake_time from bot import exts -from bot.api import ResponseCodeError from bot.constants import URLs from bot.errors import InvalidInfraction from bot.exts.info.doc import _inventory_parser diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py index fabb2dbb5..5391a7f15 100644 --- a/bot/exts/backend/error_handler.py +++ b/bot/exts/backend/error_handler.py @@ -1,10 +1,10 @@ import difflib +from botcore.site_api import ResponseCodeError from discord import Embed from discord.ext.commands import ChannelNotFound, Cog, Context, TextChannelConverter, VoiceChannelConverter, errors from sentry_sdk import push_scope -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Colours, Icons, MODERATION_ROLES from bot.errors import InvalidInfractedUserError, LockedResourceError diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py index 58aabc141..a5bf82397 100644 --- a/bot/exts/backend/sync/_cog.py +++ b/bot/exts/backend/sync/_cog.py @@ -1,11 +1,11 @@ from typing import Any, Dict +from botcore.site_api import ResponseCodeError from discord import Member, Role, User from discord.ext import commands from discord.ext.commands import Cog, Context from bot import constants -from bot.api import ResponseCodeError from bot.bot import Bot from bot.exts.backend.sync import _syncers from bot.log import get_logger diff --git a/bot/exts/backend/sync/_syncers.py b/bot/exts/backend/sync/_syncers.py index 45301b098..e1c4541ef 100644 --- a/bot/exts/backend/sync/_syncers.py +++ b/bot/exts/backend/sync/_syncers.py @@ -2,12 +2,12 @@ import abc import typing as t from collections import namedtuple +from botcore.site_api import ResponseCodeError from discord import Guild from discord.ext.commands import Context from more_itertools import chunked import bot -from bot.api import ResponseCodeError from bot.log import get_logger from bot.utils.members import get_or_fetch_member diff --git a/bot/exts/filters/filter_lists.py b/bot/exts/filters/filter_lists.py index 3e3f5c562..fc9cfbeca 100644 --- a/bot/exts/filters/filter_lists.py +++ b/bot/exts/filters/filter_lists.py @@ -1,11 +1,11 @@ import re from typing import Optional +from botcore.site_api import ResponseCodeError from discord import Colour, Embed from discord.ext.commands import BadArgument, Cog, Context, IDConverter, group, has_any_role from bot import constants -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels from bot.converters import ValidDiscordServerInvite, ValidFilterListType diff --git a/bot/exts/filters/filtering.py b/bot/exts/filters/filtering.py index cabb7f0b6..6982f5948 100644 --- a/bot/exts/filters/filtering.py +++ b/bot/exts/filters/filtering.py @@ -9,6 +9,7 @@ import dateutil.parser import regex import tldextract from async_rediscache import RedisCache +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from botcore.utils.regex import DISCORD_INVITE from dateutil.relativedelta import relativedelta @@ -16,7 +17,6 @@ from discord import ChannelType, Colour, Embed, Forbidden, HTTPException, Member from discord.ext.commands import Cog from discord.utils import escape_markdown -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, Colours, Filter, Guild, Icons, URLs from bot.exts.events.code_jams._channels import CATEGORY_NAME as JAM_CATEGORY_NAME diff --git a/bot/exts/fun/off_topic_names.py b/bot/exts/fun/off_topic_names.py index ac172f2a8..d8111bdf5 100644 --- a/bot/exts/fun/off_topic_names.py +++ b/bot/exts/fun/off_topic_names.py @@ -2,12 +2,12 @@ import difflib from datetime import timedelta import arrow +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from discord import Colour, Embed from discord.ext.commands import Cog, Context, group, has_any_role from discord.utils import sleep_until -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, MODERATION_ROLES from bot.converters import OffTopicName diff --git a/bot/exts/info/doc/_cog.py b/bot/exts/info/doc/_cog.py index 8c3038c5b..bbdc4e82a 100644 --- a/bot/exts/info/doc/_cog.py +++ b/bot/exts/info/doc/_cog.py @@ -10,11 +10,11 @@ from typing import Dict, NamedTuple, Optional, Tuple, Union import aiohttp import discord +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from botcore.utils.scheduling import Scheduler from discord.ext import commands -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import MODERATION_ROLES, RedirectOutput from bot.converters import Inventory, PackageName, ValidURL, allowed_strings diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py index b56fd171a..e7d17c971 100644 --- a/bot/exts/info/information.py +++ b/bot/exts/info/information.py @@ -6,12 +6,12 @@ from textwrap import shorten from typing import Any, DefaultDict, Mapping, Optional, Tuple, Union import rapidfuzz +from botcore.site_api import ResponseCodeError from discord import AllowedMentions, Colour, Embed, Guild, Message, Role from discord.ext.commands import BucketType, Cog, Context, Greedy, Paginator, command, group, has_any_role from discord.utils import escape_markdown from bot import constants -from bot.api import ResponseCodeError from bot.bot import Bot from bot.converters import MemberOrUser from bot.decorators import in_whitelist diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 137358ec3..9c73bde5f 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -6,11 +6,11 @@ from gettext import ngettext import arrow import dateutil.parser import discord +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from discord.ext.commands import Context from bot import constants -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Colours from bot.converters import MemberOrUser diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py index c1be18362..3a2485ec2 100644 --- a/bot/exts/moderation/infraction/_utils.py +++ b/bot/exts/moderation/infraction/_utils.py @@ -3,10 +3,10 @@ from datetime import datetime import arrow import discord +from botcore.site_api import ResponseCodeError from discord.ext.commands import Context import bot -from bot.api import ResponseCodeError from bot.constants import Colours, Icons from bot.converters import MemberOrUser from bot.errors import InvalidInfractedUserError diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py index 33096e7e0..9b1621c01 100644 --- a/bot/exts/moderation/voice_gate.py +++ b/bot/exts/moderation/voice_gate.py @@ -5,10 +5,10 @@ from datetime import timedelta import arrow import discord from async_rediscache import RedisCache +from botcore.site_api import ResponseCodeError from discord import Colour, Member, VoiceState from discord.ext.commands import Cog, Context, command -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, MODERATION_ROLES, Roles, VoiceGate as GateConf from bot.decorators import has_no_roles, in_whitelist diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py index ab5ce62f9..bc78b3934 100644 --- a/bot/exts/moderation/watchchannels/_watchchannel.py +++ b/bot/exts/moderation/watchchannels/_watchchannel.py @@ -7,11 +7,11 @@ from dataclasses import dataclass from typing import Any, Dict, Optional import discord +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from discord import Color, DMChannel, Embed, HTTPException, Message, errors from discord.ext.commands import Cog, Context -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import BigBrother as BigBrotherConfig, Guild as GuildConfig, Icons from bot.exts.filters.token_remover import TokenRemover diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py index 8aa124536..24496af54 100644 --- a/bot/exts/recruitment/talentpool/_cog.py +++ b/bot/exts/recruitment/talentpool/_cog.py @@ -5,11 +5,11 @@ from typing import Optional, Union import discord from async_rediscache import RedisCache +from botcore.site_api import ResponseCodeError from botcore.utils import scheduling from discord import Color, Embed, Member, PartialMessage, RawReactionActionEvent, User from discord.ext.commands import BadArgument, Cog, Context, group, has_any_role -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, Emojis, Guild, MODERATION_ROLES, Roles, STAFF_ROLES from bot.converters import MemberOrUser, UnambiguousMemberOrUser diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index d0edf5388..be181d005 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -9,12 +9,12 @@ from datetime import datetime, timedelta from typing import List, Optional, Union import arrow +from botcore.site_api import ResponseCodeError from botcore.utils.scheduling import Scheduler from dateutil.parser import isoparse from discord import Embed, Emoji, Member, Message, NotFound, PartialMessage, TextChannel from discord.ext.commands import Context -from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, Colours, Emojis, Guild, Roles from bot.log import get_logger diff --git a/tests/bot/exts/backend/sync/test_base.py b/tests/bot/exts/backend/sync/test_base.py index 9dc46005b..a17c1fa10 100644 --- a/tests/bot/exts/backend/sync/test_base.py +++ b/tests/bot/exts/backend/sync/test_base.py @@ -1,7 +1,8 @@ import unittest from unittest import mock -from bot.api import ResponseCodeError +from botcore.site_api import ResponseCodeError + from bot.exts.backend.sync._syncers import Syncer from tests import helpers diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index 7dff38f96..4ec36e39f 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -2,9 +2,9 @@ import unittest from unittest import mock import discord +from botcore.site_api import ResponseCodeError from bot import constants -from bot.api import ResponseCodeError from bot.exts.backend import sync from bot.exts.backend.sync._cog import Sync from bot.exts.backend.sync._syncers import Syncer diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 35fa0ee59..04a018289 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -1,9 +1,9 @@ import unittest from unittest.mock import AsyncMock, MagicMock, call, patch +from botcore.site_api import ResponseCodeError from discord.ext.commands import errors -from bot.api import ResponseCodeError from bot.errors import InvalidInfractedUserError, LockedResourceError from bot.exts.backend.error_handler import ErrorHandler, setup from bot.exts.info.tags import Tags diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py index ff81ddd65..5cf02033d 100644 --- a/tests/bot/exts/moderation/infraction/test_utils.py +++ b/tests/bot/exts/moderation/infraction/test_utils.py @@ -3,9 +3,9 @@ from collections import namedtuple from datetime import datetime from unittest.mock import AsyncMock, MagicMock, call, patch +from botcore.site_api import ResponseCodeError from discord import Embed, Forbidden, HTTPException, NotFound -from bot.api import ResponseCodeError from bot.constants import Colours, Icons from bot.exts.moderation.infraction import _utils as utils from tests.helpers import MockBot, MockContext, MockMember, MockUser diff --git a/tests/bot/test_api.py b/tests/bot/test_api.py deleted file mode 100644 index 76bcb481d..000000000 --- a/tests/bot/test_api.py +++ /dev/null @@ -1,66 +0,0 @@ -import unittest -from unittest.mock import MagicMock - -from bot import api - - -class APIClientTests(unittest.IsolatedAsyncioTestCase): - """Tests for the bot's API client.""" - - @classmethod - def setUpClass(cls): - """Sets up the shared fixtures for the tests.""" - cls.error_api_response = MagicMock() - cls.error_api_response.status = 999 - - def test_response_code_error_default_initialization(self): - """Test the default initialization of `ResponseCodeError` without `text` or `json`""" - error = api.ResponseCodeError(response=self.error_api_response) - - self.assertIs(error.status, self.error_api_response.status) - self.assertEqual(error.response_json, {}) - self.assertEqual(error.response_text, "") - self.assertIs(error.response, self.error_api_response) - - def test_response_code_error_string_representation_default_initialization(self): - """Test the string representation of `ResponseCodeError` initialized without text or json.""" - error = api.ResponseCodeError(response=self.error_api_response) - self.assertEqual(str(error), f"Status: {self.error_api_response.status} Response: ") - - def test_response_code_error_initialization_with_json(self): - """Test the initialization of `ResponseCodeError` with json.""" - json_data = {'hello': 'world'} - error = api.ResponseCodeError( - response=self.error_api_response, - response_json=json_data, - ) - self.assertEqual(error.response_json, json_data) - self.assertEqual(error.response_text, "") - - def test_response_code_error_string_representation_with_nonempty_response_json(self): - """Test the string representation of `ResponseCodeError` initialized with json.""" - json_data = {'hello': 'world'} - error = api.ResponseCodeError( - response=self.error_api_response, - response_json=json_data - ) - self.assertEqual(str(error), f"Status: {self.error_api_response.status} Response: {json_data}") - - def test_response_code_error_initialization_with_text(self): - """Test the initialization of `ResponseCodeError` with text.""" - text_data = 'Lemon will eat your soul' - error = api.ResponseCodeError( - response=self.error_api_response, - response_text=text_data, - ) - self.assertEqual(error.response_text, text_data) - self.assertEqual(error.response_json, {}) - - def test_response_code_error_string_representation_with_nonempty_response_text(self): - """Test the string representation of `ResponseCodeError` initialized with text.""" - text_data = 'Lemon will eat your soul' - error = api.ResponseCodeError( - response=self.error_api_response, - response_text=text_data - ) - self.assertEqual(str(error), f"Status: {self.error_api_response.status} Response: {text_data}") diff --git a/tests/helpers.py b/tests/helpers.py index 9d4988d23..3e6290e58 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -9,10 +9,10 @@ from typing import Iterable, Optional import discord from aiohttp import ClientSession +from botcore.async_stats import AsyncStatsClient +from botcore.site_api import APIClient from discord.ext.commands import Context -from bot.api import APIClient -from bot.async_stats import AsyncStatsClient from bot.bot import Bot from tests._autospec import autospec # noqa: F401 other modules import it via this module -- cgit v1.2.3 From 277bb011d8ae6b1c58c9de80d10b61791ee1fc49 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:42:58 +0100 Subject: Adding missing kwargs required by BotBase in test helper --- tests/helpers.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests') diff --git a/tests/helpers.py b/tests/helpers.py index 3e6290e58..e6e95c20c 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -312,6 +312,9 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock): command_prefix=unittest.mock.MagicMock(), loop=_get_mock_loop(), redis_session=unittest.mock.MagicMock(), + http_session=unittest.mock.MagicMock(), + allowed_roles=[1], + guild_id=1, ) additional_spec_asyncs = ("wait_for", "redis_ready") -- cgit v1.2.3 From 56e38eeb38de10611611f0f81f5cbc429d7f2bc8 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:44:53 +0100 Subject: Update test helpers with breaking d.py changes region was removed from the guild object, so this has been replaced with features add_cog is now async, so it is now an async_mock during tests Two new required voice_channel attrs were added channel.type is required to be set to ChannelType due to a new isinstance check in d.py --- tests/helpers.py | 4 ++++ tests/test_helpers.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/helpers.py b/tests/helpers.py index e6e95c20c..2f0c9b4ad 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -325,6 +325,7 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock): self.api_client = MockAPIClient(loop=self.loop) self.http_session = unittest.mock.create_autospec(spec=ClientSession, spec_set=True) self.stats = unittest.mock.create_autospec(spec=AsyncStatsClient, spec_set=True) + self.add_cog = unittest.mock.AsyncMock() # Create a TextChannel instance to get a realistic MagicMock of `discord.TextChannel` @@ -337,6 +338,8 @@ channel_data = { 'position': 1, 'nsfw': False, 'last_message_id': 1, + 'bitrate': 1337, + 'user_limit': 25, } state = unittest.mock.MagicMock() guild = unittest.mock.MagicMock() @@ -441,6 +444,7 @@ message_data = { } state = unittest.mock.MagicMock() channel = unittest.mock.MagicMock() +channel.type = discord.ChannelType.text message_instance = discord.Message(state=state, channel=channel, data=message_data) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 81285e009..f3040b305 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -327,7 +327,7 @@ class MockObjectTests(unittest.TestCase): def test_spec_propagation_of_mock_subclasses(self): """Test if the `spec` does not propagate to attributes of the mock object.""" test_values = ( - (helpers.MockGuild, "region"), + (helpers.MockGuild, "features"), (helpers.MockRole, "mentionable"), (helpers.MockMember, "display_name"), (helpers.MockBot, "owner_id"), -- cgit v1.2.3 From 450c9ce5b9bb711681ce87508d5b33a0ad6aed52 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:47:13 +0100 Subject: Update tests to use new async cog setup function --- tests/bot/exts/backend/sync/test_cog.py | 6 +++--- tests/bot/exts/backend/test_error_handler.py | 8 ++++---- tests/bot/exts/events/test_code_jams.py | 8 ++++---- tests/bot/exts/filters/test_antimalware.py | 8 ++++---- tests/bot/exts/filters/test_security.py | 11 +++++------ tests/bot/exts/filters/test_token_remover.py | 8 ++++---- tests/bot/exts/utils/test_snekbox.py | 8 ++++---- 7 files changed, 28 insertions(+), 29 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index 4ec36e39f..ce620aa8d 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -16,11 +16,11 @@ class SyncExtensionTests(unittest.IsolatedAsyncioTestCase): """Tests for the sync extension.""" @staticmethod - def test_extension_setup(): + async def test_extension_setup(): """The Sync cog should be added.""" bot = helpers.MockBot() - sync.setup(bot) - bot.add_cog.assert_called_once() + await sync.setup(bot) + bot.add_cog.assert_awaited_once() class SyncCogTestCase(unittest.IsolatedAsyncioTestCase): diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 04a018289..193f1d822 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -544,11 +544,11 @@ class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): push_scope_mock.set_extra.has_calls(set_extra_calls) -class ErrorHandlerSetupTests(unittest.TestCase): +class ErrorHandlerSetupTests(unittest.IsolatedAsyncioTestCase): """Tests for `ErrorHandler` `setup` function.""" - def test_setup(self): + async def test_setup(self): """Should call `bot.add_cog` with `ErrorHandler`.""" bot = MockBot() - setup(bot) - bot.add_cog.assert_called_once() + await setup(bot) + bot.add_cog.assert_awaited_once() diff --git a/tests/bot/exts/events/test_code_jams.py b/tests/bot/exts/events/test_code_jams.py index 0856546af..684f7abcd 100644 --- a/tests/bot/exts/events/test_code_jams.py +++ b/tests/bot/exts/events/test_code_jams.py @@ -160,11 +160,11 @@ class JamCodejamCreateTests(unittest.IsolatedAsyncioTestCase): member.add_roles.assert_not_awaited() -class CodeJamSetup(unittest.TestCase): +class CodeJamSetup(unittest.IsolatedAsyncioTestCase): """Test for `setup` function of `CodeJam` cog.""" - def test_setup(self): + async def test_setup(self): """Should call `bot.add_cog`.""" bot = MockBot() - code_jams.setup(bot) - bot.add_cog.assert_called_once() + await code_jams.setup(bot) + bot.add_cog.assert_awaited_once() diff --git a/tests/bot/exts/filters/test_antimalware.py b/tests/bot/exts/filters/test_antimalware.py index 06d78de9d..7282334e2 100644 --- a/tests/bot/exts/filters/test_antimalware.py +++ b/tests/bot/exts/filters/test_antimalware.py @@ -192,11 +192,11 @@ class AntiMalwareCogTests(unittest.IsolatedAsyncioTestCase): self.assertCountEqual(disallowed_extensions, expected_disallowed_extensions) -class AntiMalwareSetupTests(unittest.TestCase): +class AntiMalwareSetupTests(unittest.IsolatedAsyncioTestCase): """Tests setup of the `AntiMalware` cog.""" - def test_setup(self): + async def test_setup(self): """Setup of the extension should call add_cog.""" bot = MockBot() - antimalware.setup(bot) - bot.add_cog.assert_called_once() + await antimalware.setup(bot) + bot.add_cog.assert_awaited_once() diff --git a/tests/bot/exts/filters/test_security.py b/tests/bot/exts/filters/test_security.py index c0c3baa42..007b7b1eb 100644 --- a/tests/bot/exts/filters/test_security.py +++ b/tests/bot/exts/filters/test_security.py @@ -1,5 +1,4 @@ import unittest -from unittest.mock import MagicMock from discord.ext.commands import NoPrivateMessage @@ -44,11 +43,11 @@ class SecurityCogTests(unittest.TestCase): self.assertTrue(self.cog.check_on_guild(self.ctx)) -class SecurityCogLoadTests(unittest.TestCase): +class SecurityCogLoadTests(unittest.IsolatedAsyncioTestCase): """Tests loading the `Security` cog.""" - def test_security_cog_load(self): + async def test_security_cog_load(self): """Setup of the extension should call add_cog.""" - bot = MagicMock() - security.setup(bot) - bot.add_cog.assert_called_once() + bot = MockBot() + await security.setup(bot) + bot.add_cog.assert_awaited_once() diff --git a/tests/bot/exts/filters/test_token_remover.py b/tests/bot/exts/filters/test_token_remover.py index 4db27269a..c1f3762ac 100644 --- a/tests/bot/exts/filters/test_token_remover.py +++ b/tests/bot/exts/filters/test_token_remover.py @@ -395,15 +395,15 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase): self.msg.channel.send.assert_not_awaited() -class TokenRemoverExtensionTests(unittest.TestCase): +class TokenRemoverExtensionTests(unittest.IsolatedAsyncioTestCase): """Tests for the token_remover extension.""" @autospec("bot.exts.filters.token_remover", "TokenRemover") - def test_extension_setup(self, cog): + async def test_extension_setup(self, cog): """The TokenRemover cog should be added.""" bot = MockBot() - token_remover.setup(bot) + await token_remover.setup(bot) cog.assert_called_once_with(bot) - bot.add_cog.assert_called_once() + bot.add_cog.assert_awaited_once() self.assertTrue(isinstance(bot.add_cog.call_args.args[0], TokenRemover)) diff --git a/tests/bot/exts/utils/test_snekbox.py b/tests/bot/exts/utils/test_snekbox.py index f68a20089..3c555c051 100644 --- a/tests/bot/exts/utils/test_snekbox.py +++ b/tests/bot/exts/utils/test_snekbox.py @@ -403,11 +403,11 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase): self.assertEqual(actual, expected) -class SnekboxSetupTests(unittest.TestCase): +class SnekboxSetupTests(unittest.IsolatedAsyncioTestCase): """Tests setup of the `Snekbox` cog.""" - def test_setup(self): + async def test_setup(self): """Setup of the extension should call add_cog.""" bot = MockBot() - snekbox.setup(bot) - bot.add_cog.assert_called_once() + await snekbox.setup(bot) + bot.add_cog.assert_awaited_once() -- cgit v1.2.3 From 4db508e7abdc9d5835940f15d5faecdd2f045d0a Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:49:36 +0100 Subject: Update tests to use new async cog_load function --- tests/bot/exts/backend/sync/test_cog.py | 2 +- tests/bot/exts/moderation/test_silence.py | 40 +++++++++++++------------------ 2 files changed, 17 insertions(+), 25 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index ce620aa8d..4e9941d88 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -87,7 +87,7 @@ class SyncCogTests(SyncCogTestCase): self.bot.get_guild = mock.MagicMock(return_value=guild) - await self.cog.sync_guild() + await self.cog.cog_load() self.bot.wait_until_guild_available.assert_called_once() self.bot.get_guild.assert_called_once_with(constants.Guild.id) diff --git a/tests/bot/exts/moderation/test_silence.py b/tests/bot/exts/moderation/test_silence.py index 92ce3418a..2ebb16978 100644 --- a/tests/bot/exts/moderation/test_silence.py +++ b/tests/bot/exts/moderation/test_silence.py @@ -114,44 +114,36 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): self.cog = silence.Silence(self.bot) @autospec(silence, "SilenceNotifier", pass_mocks=False) - async def test_async_init_got_guild(self): + async def testcog_load_got_guild(self): """Bot got guild after it became available.""" - await self.cog._async_init() + await self.cog.cog_load() self.bot.wait_until_guild_available.assert_awaited_once() self.bot.get_guild.assert_called_once_with(Guild.id) @autospec(silence, "SilenceNotifier", pass_mocks=False) - async def test_async_init_got_channels(self): + async def testcog_load_got_channels(self): """Got channels from bot.""" self.bot.get_channel.side_effect = lambda id_: MockTextChannel(id=id_) - await self.cog._async_init() + await self.cog.cog_load() self.assertEqual(self.cog._mod_alerts_channel.id, Channels.mod_alerts) @autospec(silence, "SilenceNotifier") - async def test_async_init_got_notifier(self, notifier): + async def testcog_load_got_notifier(self, notifier): """Notifier was started with channel.""" self.bot.get_channel.side_effect = lambda id_: MockTextChannel(id=id_) - await self.cog._async_init() + await self.cog.cog_load() notifier.assert_called_once_with(MockTextChannel(id=Channels.mod_log)) self.assertEqual(self.cog.notifier, notifier.return_value) @autospec(silence, "SilenceNotifier", pass_mocks=False) - async def test_async_init_rescheduled(self): + async def testcog_load_rescheduled(self): """`_reschedule_` coroutine was awaited.""" self.cog._reschedule = mock.create_autospec(self.cog._reschedule) - await self.cog._async_init() + await self.cog.cog_load() self.cog._reschedule.assert_awaited_once_with() - def test_cog_unload_cancelled_tasks(self): - """The init task was cancelled.""" - self.cog._init_task = asyncio.Future() - self.cog.cog_unload() - - # It's too annoying to test cancel_all since it's a done callback and wrapped in a lambda. - self.assertTrue(self.cog._init_task.cancelled()) - @autospec("discord.ext.commands", "has_any_role") @mock.patch.object(silence.constants, "MODERATION_ROLES", new=(1, 2, 3)) async def test_cog_check(self, role_check): @@ -165,7 +157,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): async def test_force_voice_sync(self): """Tests the _force_voice_sync helper function.""" - await self.cog._async_init() + await self.cog.cog_load() # Create a regular member, and one member for each of the moderation roles moderation_members = [MockMember(roles=[MockRole(id=role)]) for role in MODERATION_ROLES] @@ -187,7 +179,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): async def test_force_voice_sync_no_channel(self): """Test to ensure _force_voice_sync can create its own voice channel if one is not available.""" - await self.cog._async_init() + await self.cog.cog_load() channel = MockVoiceChannel(guild=MockGuild(afk_channel=None)) new_channel = MockVoiceChannel(delete=AsyncMock()) @@ -206,7 +198,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): async def test_voice_kick(self): """Test to ensure kick function can remove all members from a voice channel.""" - await self.cog._async_init() + await self.cog.cog_load() # Create a regular member, and one member for each of the moderation roles moderation_members = [MockMember(roles=[MockRole(id=role)]) for role in MODERATION_ROLES] @@ -236,7 +228,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): async def test_kick_move_to_error(self): """Test to ensure move_to gets called on all members during kick, even if some fail.""" - await self.cog._async_init() + await self.cog.cog_load() _, members = self.create_erroneous_members() await self.cog._kick_voice_members(MockVoiceChannel(members=members)) @@ -245,7 +237,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): async def test_sync_move_to_error(self): """Test to ensure move_to gets called on all members during sync, even if some fail.""" - await self.cog._async_init() + await self.cog.cog_load() failing_member, members = self.create_erroneous_members() await self.cog._force_voice_sync(MockVoiceChannel(members=members)) @@ -339,7 +331,7 @@ class RescheduleTests(unittest.IsolatedAsyncioTestCase): self.cog._unsilence_wrapper = mock.create_autospec(self.cog._unsilence_wrapper) with mock.patch.object(self.cog, "_reschedule", autospec=True): - asyncio.run(self.cog._async_init()) # Populate instance attributes. + asyncio.run(self.cog.cog_load()) # Populate instance attributes. async def test_skipped_missing_channel(self): """Did nothing because the channel couldn't be retrieved.""" @@ -428,7 +420,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): # Avoid unawaited coroutine warnings. self.cog.scheduler.schedule_later.side_effect = lambda delay, task_id, coro: coro.close() - asyncio.run(self.cog._async_init()) # Populate instance attributes. + asyncio.run(self.cog.cog_load()) # Populate instance attributes. self.text_channel = MockTextChannel() self.text_overwrite = PermissionOverwrite( @@ -701,7 +693,7 @@ class UnsilenceTests(unittest.IsolatedAsyncioTestCase): overwrites_cache = mock.create_autospec(self.cog.previous_overwrites, spec_set=True) self.cog.previous_overwrites = overwrites_cache - asyncio.run(self.cog._async_init()) # Populate instance attributes. + asyncio.run(self.cog.cog_load()) # Populate instance attributes. self.cog.scheduler.__contains__.return_value = True overwrites_cache.get.return_value = '{"send_messages": true, "add_reactions": false}' -- cgit v1.2.3 From 0afe07d0734e50854d7abd8685086e79858fcadf Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:50:33 +0100 Subject: Remove sync cog init test Discord.py now implicitly calls the new async cog_load function from within it's internals on load. There is no longer a need to test that this happens. --- tests/bot/exts/backend/sync/test_cog.py | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index 4e9941d88..28afeebeb 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -60,23 +60,6 @@ class SyncCogTestCase(unittest.IsolatedAsyncioTestCase): class SyncCogTests(SyncCogTestCase): """Tests for the Sync cog.""" - @mock.patch("botcore.utils.scheduling.create_task") - @mock.patch.object(Sync, "sync_guild", new_callable=mock.MagicMock) - def test_sync_cog_init(self, sync_guild, create_task): - """Should instantiate syncers and run a sync for the guild.""" - # Reset because a Sync cog was already instantiated in setUp. - self.RoleSyncer.reset_mock() - self.UserSyncer.reset_mock() - - mock_sync_guild_coro = mock.MagicMock() - sync_guild.return_value = mock_sync_guild_coro - - Sync(self.bot) - - sync_guild.assert_called_once_with() - create_task.assert_called_once() - self.assertEqual(create_task.call_args.args[0], mock_sync_guild_coro) - async def test_sync_cog_sync_guild(self): """Roles and users should be synced only if a guild is successfully retrieved.""" for guild in (helpers.MockGuild(), None): -- cgit v1.2.3 From 4a9e2819929908182f8c6a148502671f281357ca Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Sat, 2 Apr 2022 22:51:01 +0100 Subject: Don't try to overwrite a read-only attr in help command test --- tests/bot/exts/info/test_help.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/exts/info/test_help.py b/tests/bot/exts/info/test_help.py index 604c69671..21d124f3a 100644 --- a/tests/bot/exts/info/test_help.py +++ b/tests/bot/exts/info/test_help.py @@ -1,4 +1,5 @@ import unittest +import unittest.mock import rapidfuzz @@ -12,7 +13,6 @@ class HelpCogTests(unittest.IsolatedAsyncioTestCase): self.bot = MockBot() self.cog = help.Help(self.bot) self.ctx = MockContext(bot=self.bot) - self.bot.help_command.context = self.ctx @autospec(help.CustomHelpCommand, "get_all_help_choices", return_value={"help"}, pass_mocks=False) async def test_help_fuzzy_matching(self): -- cgit v1.2.3 From 87edeff7347f011c2317cd4b3681bea5bbe07185 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 18 Apr 2022 17:39:20 +0100 Subject: Test that sync cog syncers run when sync cog is loaded --- tests/bot/exts/backend/sync/test_cog.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tests') diff --git a/tests/bot/exts/backend/sync/test_cog.py b/tests/bot/exts/backend/sync/test_cog.py index 28afeebeb..87b76c6b4 100644 --- a/tests/bot/exts/backend/sync/test_cog.py +++ b/tests/bot/exts/backend/sync/test_cog.py @@ -60,6 +60,19 @@ class SyncCogTestCase(unittest.IsolatedAsyncioTestCase): class SyncCogTests(SyncCogTestCase): """Tests for the Sync cog.""" + async def test_sync_cog_sync_on_load(self): + """Roles and users should be synced on cog load.""" + guild = helpers.MockGuild() + self.bot.get_guild = mock.MagicMock(return_value=guild) + + self.RoleSyncer.reset_mock() + self.UserSyncer.reset_mock() + + await self.cog.cog_load() + + self.RoleSyncer.sync.assert_called_once_with(guild) + self.UserSyncer.sync.assert_called_once_with(guild) + async def test_sync_cog_sync_guild(self): """Roles and users should be synced only if a guild is successfully retrieved.""" for guild in (helpers.MockGuild(), None): -- cgit v1.2.3 From 267f6d94cb10a45f873ea1d0e22f812267be5e69 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Mon, 18 Apr 2022 17:40:41 +0100 Subject: Add missing underscores to test function names --- tests/bot/exts/moderation/test_silence.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/moderation/test_silence.py b/tests/bot/exts/moderation/test_silence.py index 2ebb16978..65aecad28 100644 --- a/tests/bot/exts/moderation/test_silence.py +++ b/tests/bot/exts/moderation/test_silence.py @@ -114,14 +114,14 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): self.cog = silence.Silence(self.bot) @autospec(silence, "SilenceNotifier", pass_mocks=False) - async def testcog_load_got_guild(self): + async def test_cog_load_got_guild(self): """Bot got guild after it became available.""" await self.cog.cog_load() self.bot.wait_until_guild_available.assert_awaited_once() self.bot.get_guild.assert_called_once_with(Guild.id) @autospec(silence, "SilenceNotifier", pass_mocks=False) - async def testcog_load_got_channels(self): + async def test_cog_load_got_channels(self): """Got channels from bot.""" self.bot.get_channel.side_effect = lambda id_: MockTextChannel(id=id_) @@ -129,7 +129,7 @@ class SilenceCogTests(unittest.IsolatedAsyncioTestCase): self.assertEqual(self.cog._mod_alerts_channel.id, Channels.mod_alerts) @autospec(silence, "SilenceNotifier") - async def testcog_load_got_notifier(self, notifier): + async def test_cog_load_got_notifier(self, notifier): """Notifier was started with channel.""" self.bot.get_channel.side_effect = lambda id_: MockTextChannel(id=id_) -- cgit v1.2.3 From 4c1a076dd0b7c021ac1b352589bb353139f86a6f Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 19 Apr 2022 17:23:28 +0100 Subject: Pass the now required intents kwarg when creating MockBot --- tests/helpers.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/helpers.py b/tests/helpers.py index 2f0c9b4ad..a6e4bdd66 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -315,6 +315,7 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock): http_session=unittest.mock.MagicMock(), allowed_roles=[1], guild_id=1, + intents=discord.Intents.all(), ) additional_spec_asyncs = ("wait_for", "redis_ready") -- cgit v1.2.3 From 03a8c8138c53b6582a0921b3dcf7a1b7d55877de Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Wed, 20 Apr 2022 21:06:13 +0100 Subject: remove unneeded import in tests --- tests/bot/exts/info/test_help.py | 1 - 1 file changed, 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/exts/info/test_help.py b/tests/bot/exts/info/test_help.py index 21d124f3a..2644ae40d 100644 --- a/tests/bot/exts/info/test_help.py +++ b/tests/bot/exts/info/test_help.py @@ -1,5 +1,4 @@ import unittest -import unittest.mock import rapidfuzz -- cgit v1.2.3