aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/exts/backend/sync/_syncers.py3
-rw-r--r--bot/exts/events/code_jams/_cog.py7
-rw-r--r--bot/exts/filters/antimalware.py2
-rw-r--r--bot/exts/filters/antispam.py2
-rw-r--r--bot/exts/filters/token_remover.py7
-rw-r--r--bot/exts/help_channels/_channel.py4
-rw-r--r--bot/exts/help_channels/_cog.py10
-rw-r--r--bot/exts/info/information.py9
-rw-r--r--bot/exts/moderation/infraction/infractions.py5
-rw-r--r--bot/exts/moderation/infraction/management.py3
-rw-r--r--bot/exts/moderation/infraction/superstarify.py3
-rw-r--r--bot/exts/moderation/stream.py23
-rw-r--r--bot/exts/moderation/watchchannels/_watchchannel.py5
-rw-r--r--bot/exts/recruitment/talentpool/_cog.py9
-rw-r--r--bot/exts/recruitment/talentpool/_review.py3
-rw-r--r--bot/exts/utils/reminders.py18
-rw-r--r--bot/utils/channel.py2
-rw-r--r--bot/utils/members.py24
-rw-r--r--pyproject.toml3
-rw-r--r--tests/bot/exts/backend/sync/test_users.py5
-rw-r--r--tests/bot/exts/filters/test_token_remover.py13
-rw-r--r--tests/bot/exts/moderation/infraction/test_infractions.py3
22 files changed, 102 insertions, 61 deletions
diff --git a/bot/exts/backend/sync/_syncers.py b/bot/exts/backend/sync/_syncers.py
index c9f2d2da8..50016df0c 100644
--- a/bot/exts/backend/sync/_syncers.py
+++ b/bot/exts/backend/sync/_syncers.py
@@ -9,6 +9,7 @@ from more_itertools import chunked
import bot
from bot.api import ResponseCodeError
+from bot.utils.members import get_or_fetch_member
log = logging.getLogger(__name__)
@@ -156,7 +157,7 @@ class UserSyncer(Syncer):
if db_user[db_field] != guild_value:
updated_fields[db_field] = guild_value
- if guild_user := guild.get_member(db_user["id"]):
+ if guild_user := await get_or_fetch_member(guild, db_user["id"]):
seen_guild_users.add(guild_user.id)
maybe_update("name", guild_user.name)
diff --git a/bot/exts/events/code_jams/_cog.py b/bot/exts/events/code_jams/_cog.py
index e099f7dfa..7b0831ab4 100644
--- a/bot/exts/events/code_jams/_cog.py
+++ b/bot/exts/events/code_jams/_cog.py
@@ -11,6 +11,7 @@ from discord.ext import commands
from bot.bot import Bot
from bot.constants import Emojis, Roles
from bot.exts.events.code_jams import _channels
+from bot.utils.members import get_or_fetch_member
from bot.utils.services import send_to_paste_service
log = logging.getLogger(__name__)
@@ -59,7 +60,7 @@ class CodeJams(commands.Cog):
reader = csv.DictReader(csv_file.splitlines())
for row in reader:
- member = ctx.guild.get_member(int(row["Team Member Discord ID"]))
+ member = await get_or_fetch_member(ctx.guild, int(row["Team Member Discord ID"]))
if member is None:
log.trace(f"Got an invalid member ID: {row['Team Member Discord ID']}")
@@ -69,8 +70,8 @@ class CodeJams(commands.Cog):
team_leaders = await ctx.guild.create_role(name="Code Jam Team Leaders", colour=TEAM_LEADERS_COLOUR)
- for team_name, members in teams.items():
- await _channels.create_team_channel(ctx.guild, team_name, members, team_leaders)
+ for team_name, team_members in teams.items():
+ await _channels.create_team_channel(ctx.guild, team_name, team_members, team_leaders)
await _channels.create_team_leader_channel(ctx.guild, team_leaders)
await ctx.send(f"{Emojis.check_mark} Created Code Jam with {len(teams)} teams.")
diff --git a/bot/exts/filters/antimalware.py b/bot/exts/filters/antimalware.py
index 0eedeb0fb..e708e5149 100644
--- a/bot/exts/filters/antimalware.py
+++ b/bot/exts/filters/antimalware.py
@@ -63,7 +63,7 @@ class AntiMalware(Cog):
return
# Ignore code jam channels
- if hasattr(message.channel, "category") and message.channel.category.name == JAM_CATEGORY_NAME:
+ if getattr(message.channel, "category", None) and message.channel.category.name == JAM_CATEGORY_NAME:
return
# Check if user is staff, if is, return
diff --git a/bot/exts/filters/antispam.py b/bot/exts/filters/antispam.py
index fe79a5d62..70c1168bf 100644
--- a/bot/exts/filters/antispam.py
+++ b/bot/exts/filters/antispam.py
@@ -166,7 +166,7 @@ class AntiSpam(Cog):
not message.guild
or message.guild.id != GuildConfig.id
or message.author.bot
- or (hasattr(message.channel, "category") and message.channel.category.name == JAM_CATEGORY_NAME)
+ or (getattr(message.channel, "category", None) and message.channel.category.name == JAM_CATEGORY_NAME)
or (message.channel.id in Filter.channel_whitelist and not DEBUG_MODE)
or (any(role.id in Filter.role_whitelist for role in message.author.roles) and not DEBUG_MODE)
):
diff --git a/bot/exts/filters/token_remover.py b/bot/exts/filters/token_remover.py
index 93f1f3c33..6c86ff849 100644
--- a/bot/exts/filters/token_remover.py
+++ b/bot/exts/filters/token_remover.py
@@ -11,6 +11,7 @@ from bot import utils
from bot.bot import Bot
from bot.constants import Channels, Colours, Event, Icons
from bot.exts.moderation.modlog import ModLog
+from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
log = logging.getLogger(__name__)
@@ -99,7 +100,7 @@ class TokenRemover(Cog):
await msg.channel.send(DELETION_MESSAGE_TEMPLATE.format(mention=msg.author.mention))
log_message = self.format_log_message(msg, found_token)
- userid_message, mention_everyone = self.format_userid_log_message(msg, found_token)
+ userid_message, mention_everyone = await self.format_userid_log_message(msg, found_token)
log.debug(log_message)
# Send pretty mod log embed to mod-alerts
@@ -116,7 +117,7 @@ class TokenRemover(Cog):
self.bot.stats.incr("tokens.removed_tokens")
@classmethod
- def format_userid_log_message(cls, msg: Message, token: Token) -> t.Tuple[str, bool]:
+ async def format_userid_log_message(cls, msg: Message, token: Token) -> t.Tuple[str, bool]:
"""
Format the portion of the log message that includes details about the detected user ID.
@@ -128,7 +129,7 @@ class TokenRemover(Cog):
Returns a tuple of (log_message, mention_everyone)
"""
user_id = cls.extract_user_id(token.user_id)
- user = msg.guild.get_member(user_id)
+ user = await get_or_fetch_member(msg.guild, user_id)
if user:
return KNOWN_USER_LOG_MESSAGE.format(
diff --git a/bot/exts/help_channels/_channel.py b/bot/exts/help_channels/_channel.py
index 0846b28c8..f1bcea171 100644
--- a/bot/exts/help_channels/_channel.py
+++ b/bot/exts/help_channels/_channel.py
@@ -10,7 +10,7 @@ from arrow import Arrow
import bot
from bot import constants
from bot.exts.help_channels import _caches, _message
-from bot.utils.channel import try_get_channel
+from bot.utils.channel import get_or_fetch_channel
log = logging.getLogger(__name__)
@@ -133,7 +133,7 @@ async def move_to_bottom(channel: discord.TextChannel, category_id: int, **optio
options should be avoided, as it may interfere with the category move we perform.
"""
# Get a fresh copy of the category from the bot to avoid the cache mismatch issue we had.
- category = await try_get_channel(category_id)
+ category = await get_or_fetch_channel(category_id)
payload = [{"id": c.id, "position": c.position} for c in category.channels]
diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py
index 8612f9866..7c39bc132 100644
--- a/bot/exts/help_channels/_cog.py
+++ b/bot/exts/help_channels/_cog.py
@@ -14,7 +14,7 @@ from bot import constants
from bot.bot import Bot
from bot.constants import Channels, RedirectOutput
from bot.exts.help_channels import _caches, _channel, _message, _name, _stats
-from bot.utils import channel as channel_utils, lock, scheduling
+from bot.utils import channel as channel_utils, lock, members, scheduling
log = logging.getLogger(__name__)
@@ -278,13 +278,13 @@ class HelpChannels(commands.Cog):
log.trace("Getting the CategoryChannel objects for the help categories.")
try:
- self.available_category = await channel_utils.try_get_channel(
+ self.available_category = await channel_utils.get_or_fetch_channel(
constants.Categories.help_available
)
- self.in_use_category = await channel_utils.try_get_channel(
+ self.in_use_category = await channel_utils.get_or_fetch_channel(
constants.Categories.help_in_use
)
- self.dormant_category = await channel_utils.try_get_channel(
+ self.dormant_category = await channel_utils.get_or_fetch_channel(
constants.Categories.help_dormant
)
except discord.HTTPException:
@@ -434,7 +434,7 @@ class HelpChannels(commands.Cog):
await _caches.claimants.delete(channel.id)
await _caches.session_participants.delete(channel.id)
- claimant = self.bot.get_guild(constants.Guild.id).get_member(claimant_id)
+ claimant = await members.get_or_fetch_member(self.bot.get_guild(constants.Guild.id), claimant_id)
if claimant is None:
log.info(f"{claimant_id} left the guild during their help session; the cooldown role won't be removed")
else:
diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py
index be67910a6..c60fd2127 100644
--- a/bot/exts/info/information.py
+++ b/bot/exts/info/information.py
@@ -19,6 +19,7 @@ from bot.errors import NonExistentRoleError
from bot.pagination import LinePaginator
from bot.utils.channel import is_mod_channel, is_staff_channel
from bot.utils.checks import cooldown_with_role_bypass, has_no_roles_check, in_whitelist_check
+from bot.utils.members import get_or_fetch_member
from bot.utils.time import TimestampFormats, discord_timestamp, humanize_delta
log = logging.getLogger(__name__)
@@ -46,13 +47,13 @@ class Information(Cog):
@staticmethod
def join_role_stats(role_ids: list[int], guild: Guild, name: Optional[str] = None) -> dict[str, int]:
"""Return a dictionary with the number of `members` of each role given, and the `name` for this joined group."""
- members = 0
+ member_count = 0
for role_id in role_ids:
if (role := guild.get_role(role_id)) is not None:
- members += len(role.members)
+ member_count += len(role.members)
else:
raise NonExistentRoleError(role_id)
- return {name or role.name.title(): members}
+ return {name or role.name.title(): member_count}
@staticmethod
def get_member_counts(guild: Guild) -> dict[str, int]:
@@ -244,7 +245,7 @@ class Information(Cog):
async def create_user_embed(self, ctx: Context, user: MemberOrUser) -> Embed:
"""Creates an embed containing information on the `user`."""
- on_server = bool(ctx.guild.get_member(user.id))
+ on_server = bool(await get_or_fetch_member(ctx.guild, user.id))
created = discord_timestamp(user.created_at, TimestampFormats.RELATIVE)
diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py
index eaba97703..b58b09250 100644
--- a/bot/exts/moderation/infraction/infractions.py
+++ b/bot/exts/moderation/infraction/infractions.py
@@ -14,6 +14,7 @@ from bot.converters import Duration, Expiry, MemberOrUser, UnambiguousMemberOrUs
from bot.decorators import respect_role_hierarchy
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.infraction._scheduler import InfractionScheduler
+from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
log = logging.getLogger(__name__)
@@ -422,7 +423,7 @@ class Infractions(InfractionScheduler, commands.Cog):
notify: bool = True
) -> t.Dict[str, str]:
"""Remove a user's muted role, optionally DM them a notification, and return a log dict."""
- user = guild.get_member(user_id)
+ user = await get_or_fetch_member(guild, user_id)
log_text = {}
if user:
@@ -470,7 +471,7 @@ class Infractions(InfractionScheduler, commands.Cog):
notify: bool = True
) -> t.Dict[str, str]:
"""Optionally DM the user a pardon notification and return a log dict."""
- user = guild.get_member(user_id)
+ user = await get_or_fetch_member(guild, user_id)
log_text = {}
if user:
diff --git a/bot/exts/moderation/infraction/management.py b/bot/exts/moderation/infraction/management.py
index d72cf8f89..0cb2a8b60 100644
--- a/bot/exts/moderation/infraction/management.py
+++ b/bot/exts/moderation/infraction/management.py
@@ -19,6 +19,7 @@ from bot.exts.moderation.modlog import ModLog
from bot.pagination import LinePaginator
from bot.utils import messages, time
from bot.utils.channel import is_mod_channel
+from bot.utils.members import get_or_fetch_member
from bot.utils.time import humanize_delta, until_expiration
log = logging.getLogger(__name__)
@@ -190,7 +191,7 @@ class ModManagement(commands.Cog):
# Get information about the infraction's user
user_id = new_infraction['user']
- user = ctx.guild.get_member(user_id)
+ user = await get_or_fetch_member(ctx.guild, user_id)
if user:
user_text = messages.format_user(user)
diff --git a/bot/exts/moderation/infraction/superstarify.py b/bot/exts/moderation/infraction/superstarify.py
index 05a2bbe10..aa2fd367b 100644
--- a/bot/exts/moderation/infraction/superstarify.py
+++ b/bot/exts/moderation/infraction/superstarify.py
@@ -14,6 +14,7 @@ from bot.bot import Bot
from bot.converters import Duration, Expiry
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.infraction._scheduler import InfractionScheduler
+from bot.utils.members import get_or_fetch_member
from bot.utils.messages import format_user
from bot.utils.time import format_infraction
@@ -198,7 +199,7 @@ class Superstarify(InfractionScheduler, Cog):
return
guild = self.bot.get_guild(constants.Guild.id)
- user = guild.get_member(infraction["user"])
+ user = await get_or_fetch_member(guild, infraction["user"])
# Don't bother sending a notification if the user left the guild.
if not user:
diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py
index b5bd62a71..a179a9acc 100644
--- a/bot/exts/moderation/stream.py
+++ b/bot/exts/moderation/stream.py
@@ -16,6 +16,7 @@ from bot.constants import (
from bot.converters import Expiry
from bot.pagination import LinePaginator
from bot.utils import scheduling
+from bot.utils.members import get_or_fetch_member
from bot.utils.time import discord_timestamp, format_infraction_with_duration
log = logging.getLogger(__name__)
@@ -47,23 +48,17 @@ class Stream(commands.Cog):
"""Reload outstanding tasks from redis on startup, delete the task if the member has since left the server."""
await self.bot.wait_until_guild_available()
items = await self.task_cache.items()
+ guild = self.bot.get_guild(Guild.id)
for key, value in items:
- member = self.bot.get_guild(Guild.id).get_member(key)
+ member = await get_or_fetch_member(guild, key)
if not member:
- # Member isn't found in the cache
- try:
- member = await self.bot.get_guild(Guild.id).fetch_member(key)
- except discord.errors.NotFound:
- log.debug(
- f"Member {key} left the guild before we could schedule "
- "the revoking of their streaming permissions."
- )
- await self.task_cache.delete(key)
- continue
- except discord.HTTPException:
- log.exception(f"Exception while trying to retrieve member {key} from Discord.")
- continue
+ log.debug(
+ "User with ID %d left the guild before their streaming permissions could be revoked.",
+ key
+ )
+ await self.task_cache.delete(key)
+ continue
revoke_time = Arrow.utcfromtimestamp(value)
log.debug(f"Scheduling {member} ({member.id}) to have streaming permission revoked at {revoke_time}")
diff --git a/bot/exts/moderation/watchchannels/_watchchannel.py b/bot/exts/moderation/watchchannels/_watchchannel.py
index a42e1f518..3fafd097b 100644
--- a/bot/exts/moderation/watchchannels/_watchchannel.py
+++ b/bot/exts/moderation/watchchannels/_watchchannel.py
@@ -19,6 +19,7 @@ from bot.exts.filters.webhook_remover import WEBHOOK_URL_RE
from bot.exts.moderation.modlog import ModLog
from bot.pagination import LinePaginator
from bot.utils import CogABCMeta, messages, scheduling
+from bot.utils.members import get_or_fetch_member
from bot.utils.time import get_time_delta
log = logging.getLogger(__name__)
@@ -281,7 +282,7 @@ class WatchChannel(metaclass=CogABCMeta):
user_id = msg.author.id
guild = self.bot.get_guild(GuildConfig.id)
- actor = guild.get_member(self.watched_users[user_id]['actor'])
+ actor = await get_or_fetch_member(guild, self.watched_users[user_id]['actor'])
actor = actor.display_name if actor else self.watched_users[user_id]['actor']
inserted_at = self.watched_users[user_id]['inserted_at']
@@ -355,7 +356,7 @@ class WatchChannel(metaclass=CogABCMeta):
list_data["info"] = {}
for user_id, user_data in watched_iter:
- member = ctx.guild.get_member(user_id)
+ member = await get_or_fetch_member(ctx.guild, user_id)
line = f"• `{user_id}`"
if member:
line += f" ({member.name}#{member.discriminator})"
diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py
index 193be2095..f9c836bbd 100644
--- a/bot/exts/recruitment/talentpool/_cog.py
+++ b/bot/exts/recruitment/talentpool/_cog.py
@@ -16,6 +16,7 @@ from bot.converters import MemberOrUser, UnambiguousMemberOrUser
from bot.exts.recruitment.talentpool._review import Reviewer
from bot.pagination import LinePaginator
from bot.utils import scheduling, time
+from bot.utils.members import get_or_fetch_member
from bot.utils.time import get_time_delta
AUTOREVIEW_ENABLED_KEY = "autoreview_enabled"
@@ -175,7 +176,7 @@ class TalentPool(Cog, name="Talentpool"):
lines = []
for user_id, user_data in nominations:
- member = ctx.guild.get_member(user_id)
+ member = await get_or_fetch_member(ctx.guild, user_id)
line = f"• `{user_id}`"
if member:
line += f" ({member.name}#{member.discriminator})"
@@ -314,7 +315,7 @@ class TalentPool(Cog, name="Talentpool"):
title=f"Nominations for {user.display_name} `({user.id})`",
color=Color.blue()
)
- lines = [self._nomination_to_string(nomination) for nomination in result]
+ lines = [await self._nomination_to_string(nomination) for nomination in result]
await LinePaginator.paginate(
lines,
ctx=ctx,
@@ -552,13 +553,13 @@ class TalentPool(Cog, name="Talentpool"):
return True
- def _nomination_to_string(self, nomination_object: dict) -> str:
+ async def _nomination_to_string(self, nomination_object: dict) -> str:
"""Creates a string representation of a nomination."""
guild = self.bot.get_guild(Guild.id)
entries = []
for site_entry in nomination_object["entries"]:
actor_id = site_entry["actor"]
- actor = guild.get_member(actor_id)
+ actor = await get_or_fetch_member(guild, actor_id)
reason = site_entry["reason"] or "*None*"
created = time.format_infraction(site_entry["inserted_at"])
diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py
index f4aa73e75..14a8dd4c0 100644
--- a/bot/exts/recruitment/talentpool/_review.py
+++ b/bot/exts/recruitment/talentpool/_review.py
@@ -16,6 +16,7 @@ from discord.ext.commands import Context
from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import Channels, Colours, Emojis, Guild
+from bot.utils.members import get_or_fetch_member
from bot.utils.messages import count_unique_users_reaction, pin_no_system_message
from bot.utils.scheduling import Scheduler
from bot.utils.time import get_time_delta, time_since
@@ -111,7 +112,7 @@ class Reviewer:
return "", None
guild = self.bot.get_guild(Guild.id)
- member = guild.get_member(user_id)
+ member = await get_or_fetch_member(guild, user_id)
if not member:
return (
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 1030357fd..95f3661af 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -19,6 +19,7 @@ from bot.pagination import LinePaginator
from bot.utils import scheduling
from bot.utils.checks import has_any_role_check, has_no_roles_check
from bot.utils.lock import lock_arg
+from bot.utils.members import get_or_fetch_member
from bot.utils.messages import send_denial
from bot.utils.scheduling import Scheduler
from bot.utils.time import TimestampFormats, discord_timestamp
@@ -136,11 +137,12 @@ class Reminders(Cog):
await send_denial(ctx, f"You can't mention other {disallowed_mentions} in your reminder!")
return False
- def get_mentionables(self, mention_ids: t.List[int]) -> t.Iterator[Mentionable]:
+ async def get_mentionables(self, mention_ids: t.List[int]) -> t.Iterator[Mentionable]:
"""Converts Role and Member ids to their corresponding objects if possible."""
guild = self.bot.get_guild(Guild.id)
for mention_id in mention_ids:
- if mentionable := (guild.get_member(mention_id) or guild.get_role(mention_id)):
+ member = await get_or_fetch_member(guild, mention_id)
+ if mentionable := (member or guild.get_role(mention_id)):
yield mentionable
def schedule_reminder(self, reminder: dict) -> None:
@@ -194,9 +196,9 @@ class Reminders(Cog):
embed.description = f"Here's your reminder: {reminder['content']}"
# Here the jump URL is in the format of base_url/guild_id/channel_id/message_id
- additional_mentions = ' '.join(
- mentionable.mention for mentionable in self.get_mentionables(reminder["mentions"])
- )
+ additional_mentions = ' '.join([
+ mentionable.mention async for mentionable in self.get_mentionables(reminder["mentions"])
+ ])
jump_url = reminder.get("jump_url")
embed.description += f"\n[Jump back to when you created the reminder]({jump_url})"
@@ -337,10 +339,10 @@ class Reminders(Cog):
remind_datetime = isoparse(remind_at).replace(tzinfo=None)
time = discord_timestamp(remind_datetime, TimestampFormats.RELATIVE)
- mentions = ", ".join(
+ mentions = ", ".join([
# Both Role and User objects have the `name` attribute
- mention.name for mention in self.get_mentionables(mentions)
- )
+ mention.name async for mention in self.get_mentionables(mentions)
+ ])
mention_string = f"\n**Mentions:** {mentions}" if mentions else ""
text = textwrap.dedent(f"""
diff --git a/bot/utils/channel.py b/bot/utils/channel.py
index 72603c521..6d2356679 100644
--- a/bot/utils/channel.py
+++ b/bot/utils/channel.py
@@ -53,7 +53,7 @@ def is_in_category(channel: discord.TextChannel, category_id: int) -> bool:
return getattr(channel, "category_id", None) == category_id
-async def try_get_channel(channel_id: int) -> discord.abc.GuildChannel:
+async def get_or_fetch_channel(channel_id: int) -> discord.abc.GuildChannel:
"""Attempt to get or fetch a channel and return it."""
log.trace(f"Getting the channel {channel_id}.")
diff --git a/bot/utils/members.py b/bot/utils/members.py
new file mode 100644
index 000000000..302fe6d63
--- /dev/null
+++ b/bot/utils/members.py
@@ -0,0 +1,24 @@
+import logging
+import typing as t
+
+import discord
+
+log = logging.getLogger(__name__)
+
+
+async def get_or_fetch_member(guild: discord.Guild, member_id: int) -> t.Optional[discord.Member]:
+ """
+ Attempt to get a member from cache; on failure fetch from the API.
+
+ Return `None` to indicate the member could not be found.
+ """
+ if member := guild.get_member(member_id):
+ log.trace("%s retrieved from cache.", member)
+ else:
+ try:
+ member = await guild.fetch_member(member_id)
+ except discord.errors.NotFound:
+ log.trace("Failed to fetch %d from API.", member_id)
+ return None
+ log.trace("%s fetched from API.", member)
+ return member
diff --git a/pyproject.toml b/pyproject.toml
index 23cbba19b..4431a41c5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -62,7 +62,8 @@ precommit = "pre-commit install"
build = "docker build -t ghcr.io/python-discord/bot:latest -f Dockerfile ."
push = "docker push ghcr.io/python-discord/bot:latest"
test-nocov = "pytest -n auto"
-test = "pytest -n auto --cov-report= --cov"
+test = "pytest -n auto --cov-report= --cov --ff"
+retest = "pytest -n auto --cov-report= --cov --lf"
html = "coverage html"
report = "coverage report"
diff --git a/tests/bot/exts/backend/sync/test_users.py b/tests/bot/exts/backend/sync/test_users.py
index 27932be95..88f1b2f52 100644
--- a/tests/bot/exts/backend/sync/test_users.py
+++ b/tests/bot/exts/backend/sync/test_users.py
@@ -1,6 +1,8 @@
import unittest
from unittest import mock
+from discord.errors import NotFound
+
from bot.exts.backend.sync._syncers import UserSyncer, _Diff
from tests import helpers
@@ -134,6 +136,7 @@ class UserSyncerDiffTests(unittest.IsolatedAsyncioTestCase):
self.get_mock_member(fake_user()),
None
]
+ guild.fetch_member.side_effect = NotFound(mock.Mock(status=404), "Not found")
actual_diff = await UserSyncer._get_diff(guild)
expected_diff = ([], [{"id": 63, "in_guild": False}], None)
@@ -158,6 +161,7 @@ class UserSyncerDiffTests(unittest.IsolatedAsyncioTestCase):
self.get_mock_member(updated_user),
None
]
+ guild.fetch_member.side_effect = NotFound(mock.Mock(status=404), "Not found")
actual_diff = await UserSyncer._get_diff(guild)
expected_diff = ([new_user], [{"id": 55, "name": "updated"}, {"id": 63, "in_guild": False}], None)
@@ -177,6 +181,7 @@ class UserSyncerDiffTests(unittest.IsolatedAsyncioTestCase):
self.get_mock_member(fake_user()),
None
]
+ guild.fetch_member.side_effect = NotFound(mock.Mock(status=404), "Not found")
actual_diff = await UserSyncer._get_diff(guild)
expected_diff = ([], [], None)
diff --git a/tests/bot/exts/filters/test_token_remover.py b/tests/bot/exts/filters/test_token_remover.py
index 51feae9cb..05e790723 100644
--- a/tests/bot/exts/filters/test_token_remover.py
+++ b/tests/bot/exts/filters/test_token_remover.py
@@ -295,20 +295,21 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):
)
@autospec("bot.exts.filters.token_remover", "UNKNOWN_USER_LOG_MESSAGE")
- def test_format_userid_log_message_unknown(self, unknown_user_log_message):
+ async def test_format_userid_log_message_unknown(self, unknown_user_log_message,):
"""Should correctly format the user ID portion when the actual user it belongs to is unknown."""
token = Token("NDcyMjY1OTQzMDYyNDEzMzMy", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
unknown_user_log_message.format.return_value = " Partner"
msg = MockMessage(id=555, content="hello world")
msg.guild.get_member.return_value = None
+ msg.guild.fetch_member.side_effect = NotFound(mock.Mock(status=404), "Not found")
- return_value = TokenRemover.format_userid_log_message(msg, token)
+ return_value = await TokenRemover.format_userid_log_message(msg, token)
self.assertEqual(return_value, (unknown_user_log_message.format.return_value, False))
unknown_user_log_message.format.assert_called_once_with(user_id=472265943062413332)
@autospec("bot.exts.filters.token_remover", "KNOWN_USER_LOG_MESSAGE")
- def test_format_userid_log_message_bot(self, known_user_log_message):
+ async def test_format_userid_log_message_bot(self, known_user_log_message):
"""Should correctly format the user ID portion when the ID belongs to a known bot."""
token = Token("NDcyMjY1OTQzMDYyNDEzMzMy", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
known_user_log_message.format.return_value = " Partner"
@@ -316,7 +317,7 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):
msg.guild.get_member.return_value.__str__.return_value = "Sam"
msg.guild.get_member.return_value.bot = True
- return_value = TokenRemover.format_userid_log_message(msg, token)
+ return_value = await TokenRemover.format_userid_log_message(msg, token)
self.assertEqual(return_value, (known_user_log_message.format.return_value, True))
@@ -327,12 +328,12 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):
)
@autospec("bot.exts.filters.token_remover", "KNOWN_USER_LOG_MESSAGE")
- def test_format_log_message_user_token_user(self, user_token_message):
+ async def test_format_log_message_user_token_user(self, user_token_message):
"""Should correctly format the user ID portion when the ID belongs to a known user."""
token = Token("NDY3MjIzMjMwNjUwNzc3NjQx", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
user_token_message.format.return_value = "Partner"
- return_value = TokenRemover.format_userid_log_message(self.msg, token)
+ return_value = await TokenRemover.format_userid_log_message(self.msg, token)
self.assertEqual(return_value, (user_token_message.format.return_value, True))
user_token_message.format.assert_called_once_with(
diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py
index f844a9181..aeff734dc 100644
--- a/tests/bot/exts/moderation/infraction/test_infractions.py
+++ b/tests/bot/exts/moderation/infraction/test_infractions.py
@@ -3,6 +3,8 @@ import textwrap
import unittest
from unittest.mock import ANY, AsyncMock, MagicMock, Mock, patch
+from discord.errors import NotFound
+
from bot.constants import Event
from bot.exts.moderation.infraction import _utils
from bot.exts.moderation.infraction.infractions import Infractions
@@ -195,6 +197,7 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
async def test_voice_unban_user_not_found(self):
"""Should include info to return dict when user was not found from guild."""
self.guild.get_member.return_value = None
+ self.guild.fetch_member.side_effect = NotFound(Mock(status=404), "Not found")
result = await self.cog.pardon_voice_ban(self.user.id, self.guild)
self.assertEqual(result, {"Info": "User was not found in the guild."})