From 510da5190a0f499397c9419fa3b125233bed566c Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 28 Jun 2022 22:36:22 +0100 Subject: Use BotBase from bot core --- bot/bot.py | 166 ++++++------------------------------------------------------- 1 file changed, 14 insertions(+), 152 deletions(-) (limited to 'bot/bot.py') diff --git a/bot/bot.py b/bot/bot.py index c7b87a65..221bfd62 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -1,24 +1,20 @@ -import asyncio import logging -import socket -from contextlib import suppress from typing import Optional import discord -from aiohttp import AsyncResolver, ClientSession, TCPConnector -from async_rediscache import RedisSession -from discord import DiscordException, Embed, Forbidden, Thread +from botcore import BotBase +from botcore.utils import scheduling +from discord import DiscordException, Embed from discord.ext import commands -from discord.ext.commands import Cog, when_mentioned_or -from bot import constants +from bot import constants, exts log = logging.getLogger(__name__) -__all__ = ("Bot", "bot") +__all__ = ("Bot", ) -class Bot(commands.Bot): +class Bot(BotBase): """ Base bot instance. @@ -29,16 +25,6 @@ class Bot(commands.Bot): name = constants.Client.name - def __init__(self, redis_session: RedisSession, **kwargs): - super().__init__(**kwargs) - self.http_session = ClientSession( - connector=TCPConnector(resolver=AsyncResolver(), family=socket.AF_INET) - ) - self._guild_available = asyncio.Event() - self.redis_session = redis_session - self.loop.create_task(self.check_channels()) - self.loop.create_task(self.send_log(self.name, "Connected!")) - @property def member(self) -> Optional[discord.Member]: """Retrieves the guild member object for the bot.""" @@ -47,60 +33,6 @@ class Bot(commands.Bot): return None return guild.me - @Cog.listener() - async def on_thread_join(self, thread: Thread) -> None: - """ - Try to join newly created threads. - - Despite the event name being misleading, this is dispatched when new threads are created. - We want our bots to automatically join threads in order to answer commands using their prefixes. - """ - if thread.me: - # Already in this thread, return early - return - - with suppress(Forbidden): - await thread.join() - - async def close(self) -> None: - """Close Redis session when bot is shutting down.""" - await super().close() - - if self.http_session: - await self.http_session.close() - - if self.redis_session: - await self.redis_session.close() - - def add_cog(self, cog: commands.Cog) -> None: - """ - Delegate to super to register `cog`. - - This only serves to make the info log, so that extensions don't have to. - """ - super().add_cog(cog) - log.info(f"Cog loaded: {cog.qualified_name}") - - def add_command(self, command: commands.Command) -> None: - """Add `command` as normal and then add its root aliases to the bot.""" - super().add_command(command) - self._add_root_aliases(command) - - def remove_command(self, name: str) -> Optional[commands.Command]: - """ - Remove a command/alias as normal and then remove its root aliases from the bot. - - Individual root aliases cannot be removed by this function. - To remove them, either remove the entire command or manually edit `bot.all_commands`. - """ - command = super().remove_command(name) - if command is None: - # Even if it's a root alias, there's no way to get the Bot instance to remove the alias. - return - - self._remove_root_aliases(command) - return command - async def on_command_error(self, context: commands.Context, exception: DiscordException) -> None: """Check command errors for UserInputError and reset the cooldown if thrown.""" if isinstance(exception, commands.UserInputError): @@ -144,84 +76,14 @@ class Bot(commands.Bot): await devlog.send(embed=embed) - async def on_guild_available(self, guild: discord.Guild) -> None: - """ - Set the internal `_guild_available` event when PyDis guild becomes available. + async def setup_hook(self) -> None: + """Default async initialisation method for discord.py.""" + await super().setup_hook() - If the cache appears to still be empty (no members, no channels, or no roles), the event - will not be set. - """ - if guild.id != constants.Client.guild: - return - - if not guild.roles or not guild.members or not guild.channels: - log.warning("Guild available event was dispatched but the cache appears to still be empty!") - return + await self.check_channels() - self._guild_available.set() - - async def on_guild_unavailable(self, guild: discord.Guild) -> None: - """Clear the internal `_guild_available` event when PyDis guild becomes unavailable.""" - if guild.id != constants.Client.guild: - return + # This is not awaited to avoid a deadlock with any cogs that have + # wait_until_guild_available in their cog_load method. + scheduling.create_task(self.load_extensions(exts)) - self._guild_available.clear() - - async def wait_until_guild_available(self) -> None: - """ - Wait until the PyDis guild becomes available (and the cache is ready). - - The on_ready event is inadequate because it only waits 2 seconds for a GUILD_CREATE - gateway event before giving up and thus not populating the cache for unavailable guilds. - """ - await self._guild_available.wait() - - def _add_root_aliases(self, command: commands.Command) -> None: - """Recursively add root aliases for `command` and any of its subcommands.""" - if isinstance(command, commands.Group): - for subcommand in command.commands: - self._add_root_aliases(subcommand) - - for alias in getattr(command, "root_aliases", ()): - if alias in self.all_commands: - raise commands.CommandRegistrationError(alias, alias_conflict=True) - - self.all_commands[alias] = command - - def _remove_root_aliases(self, command: commands.Command) -> None: - """Recursively remove root aliases for `command` and any of its subcommands.""" - if isinstance(command, commands.Group): - for subcommand in command.commands: - self._remove_root_aliases(subcommand) - - for alias in getattr(command, "root_aliases", ()): - self.all_commands.pop(alias, None) - - -_allowed_roles = [discord.Object(id_) for id_ in constants.MODERATION_ROLES] - -_intents = discord.Intents.default() # Default is all intents except for privileged ones (Members, Presences, ...) -_intents.bans = False -_intents.integrations = False -_intents.invites = False -_intents.typing = False -_intents.webhooks = False - -redis_session = RedisSession( - address=(constants.RedisConfig.host, constants.RedisConfig.port), - password=constants.RedisConfig.password, - minsize=1, - maxsize=20, - use_fakeredis=constants.RedisConfig.use_fakeredis, - global_namespace="sir-lancebot" -) -loop = asyncio.get_event_loop() -loop.run_until_complete(redis_session.connect()) - -bot = Bot( - redis_session=redis_session, - command_prefix=when_mentioned_or(constants.Client.prefix), - activity=discord.Game(name=f"Commands: {constants.Client.prefix}help"), - allowed_mentions=discord.AllowedMentions(everyone=False, roles=_allowed_roles), - intents=_intents, -) + await self.send_log(self.name, "Connected!") -- cgit v1.2.3 From e263ac1e7f95cbc4b6b949258d0c09312b550c49 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Thu, 30 Jun 2022 22:29:39 +0100 Subject: Move startup checks and logs to their own cog This is to avoid needed to use wait_until_guild_available during the setup hook. --- bot/bot.py | 31 ++----------------------- bot/exts/events/advent_of_code/_cog.py | 2 +- bot/exts/utilities/logging.py | 42 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 bot/exts/utilities/logging.py (limited to 'bot/bot.py') diff --git a/bot/bot.py b/bot/bot.py index 221bfd62..226f9890 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -40,34 +40,11 @@ class Bot(BotBase): else: await super().on_command_error(context, exception) - async def check_channels(self) -> None: - """Verifies that all channel constants refer to channels which exist.""" - await self.wait_until_guild_available() - - if constants.Client.debug: - log.info("Skipping Channels Check.") - return - - all_channels_ids = [channel.id for channel in self.get_all_channels()] - for name, channel_id in vars(constants.Channels).items(): - if name.startswith("_"): - continue - if channel_id not in all_channels_ids: - log.error(f'Channel "{name}" with ID {channel_id} missing') - - async def send_log(self, title: str, details: str = None, *, icon: str = None) -> None: - """Send an embed message to the devlog channel.""" + async def log_to_dev_log(self, title: str, details: str = None, *, icon: str = None) -> None: + """Send an embed message to the dev-log channel.""" await self.wait_until_guild_available() devlog = self.get_channel(constants.Channels.devlog) - if not devlog: - log.info(f"Fetching devlog channel as it wasn't found in the cache (ID: {constants.Channels.devlog})") - try: - devlog = await self.fetch_channel(constants.Channels.devlog) - except discord.HTTPException as discord_exc: - log.exception("Fetch failed", exc_info=discord_exc) - return - if not icon: icon = self.user.display_avatar.url @@ -80,10 +57,6 @@ class Bot(BotBase): """Default async initialisation method for discord.py.""" await super().setup_hook() - await self.check_channels() - # This is not awaited to avoid a deadlock with any cogs that have # wait_until_guild_available in their cog_load method. scheduling.create_task(self.load_extensions(exts)) - - await self.send_log(self.name, "Connected!") diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 518841d4..1d8b0ca7 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -87,7 +87,7 @@ class AdventOfCode(commands.Cog): try: leaderboard = await _helpers.fetch_leaderboard() except _helpers.FetchingLeaderboardFailedError: - await self.bot.send_log("Unable to fetch AoC leaderboard during role sync.") + await self.bot.log_to_dev_log("Unable to fetch AoC leaderboard during role sync.") return placement_leaderboard = json.loads(leaderboard["placement_leaderboard"]) diff --git a/bot/exts/utilities/logging.py b/bot/exts/utilities/logging.py new file mode 100644 index 00000000..e1d09fdf --- /dev/null +++ b/bot/exts/utilities/logging.py @@ -0,0 +1,42 @@ +from botcore.utils.logging import get_logger +from discord.ext.commands import Cog + +from bot import constants +from bot.bot import Bot + +log = get_logger(__name__) + + +class Logging(Cog): + """Debug logging module.""" + + def __init__(self, bot: Bot): + self.bot = bot + + async def cog_load(self) -> None: + """Announce our presence to the configured dev-log channel after checking channel constants.""" + await self.check_channels() + await self.bot.log_to_dev_log( + title=self.bot.name, + details="Connected!", + ) + + async def check_channels(self) -> None: + """Verifies that all channel constants refer to channels which exist.""" + await self.bot.wait_until_guild_available() + + if constants.Client.debug: + log.info("Skipping Channels Check.") + return + + all_channels_ids = [channel.id for channel in self.bot.get_all_channels()] + for name, channel_id in vars(constants.Channels).items(): + if name.startswith("_"): + continue + if channel_id not in all_channels_ids: + log.error(f'Channel "{name}" with ID {channel_id} missing') + + +async def setup(bot: Bot) -> None: + """Load the Logging cog.""" + await bot.add_cog(Logging(bot)) -- cgit v1.2.3 From cc2dcdcdbf9e6057053bdb72bba848f4c2e19cbd Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Tue, 23 Aug 2022 20:46:14 +0100 Subject: Use extension utils from bot-core --- bot/bot.py | 8 +++++ bot/exts/avatar_modification/avatar_modify.py | 3 +- bot/exts/core/extensions.py | 22 ++++++------- bot/exts/core/internal_eval/_internal_eval.py | 3 +- bot/exts/events/advent_of_code/_cog.py | 3 +- bot/exts/fun/game.py | 3 +- bot/exts/fun/minesweeper.py | 8 ++--- bot/exts/fun/movie.py | 4 +-- bot/exts/fun/snakes/_snakes_cog.py | 3 +- bot/exts/fun/space.py | 4 +-- bot/exts/utilities/colour.py | 3 +- bot/exts/utilities/emoji.py | 8 +++-- bot/exts/utilities/epoch.py | 8 +++-- bot/exts/utilities/githubinfo.py | 3 +- bot/exts/utilities/reddit.py | 3 +- bot/exts/utilities/twemoji.py | 3 +- bot/utils/extensions.py | 45 --------------------------- 17 files changed, 46 insertions(+), 88 deletions(-) delete mode 100644 bot/utils/extensions.py (limited to 'bot/bot.py') diff --git a/bot/bot.py b/bot/bot.py index 226f9890..9309f50c 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -60,3 +60,11 @@ class Bot(BotBase): # This is not awaited to avoid a deadlock with any cogs that have # wait_until_guild_available in their cog_load method. scheduling.create_task(self.load_extensions(exts)) + + async def invoke_help_command(self, ctx: commands.Context) -> None: + """Invoke the help command or default help command if help extensions is not loaded.""" + if "bot.exts.core.help" in ctx.bot.extensions: + help_command = ctx.bot.get_command("help") + await ctx.invoke(help_command, ctx.command.qualified_name) + return + await ctx.send_help(ctx.command) diff --git a/bot/exts/avatar_modification/avatar_modify.py b/bot/exts/avatar_modification/avatar_modify.py index 3ee70cfd..337f510c 100644 --- a/bot/exts/avatar_modification/avatar_modify.py +++ b/bot/exts/avatar_modification/avatar_modify.py @@ -14,7 +14,6 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, Emojis from bot.exts.avatar_modification._effects import PfpEffects -from bot.utils.extensions import invoke_help_command from bot.utils.halloween import spookifications log = logging.getLogger(__name__) @@ -89,7 +88,7 @@ class AvatarModify(commands.Cog): async def avatar_modify(self, ctx: commands.Context) -> None: """Groups all of the pfp modifying commands to allow a single concurrency limit.""" if not ctx.invoked_subcommand: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @avatar_modify.command(name="8bitify", root_aliases=("8bitify",)) async def eightbit_command(self, ctx: commands.Context) -> None: diff --git a/bot/exts/core/extensions.py b/bot/exts/core/extensions.py index d809d2b9..586222c8 100644 --- a/bot/exts/core/extensions.py +++ b/bot/exts/core/extensions.py @@ -4,6 +4,7 @@ from collections.abc import Mapping from enum import Enum from typing import Optional +from botcore.utils._extensions import unqualify from discord import Colour, Embed from discord.ext import commands from discord.ext.commands import Context, group @@ -12,7 +13,6 @@ from bot import exts from bot.bot import Bot from bot.constants import Client, Emojis, MODERATION_ROLES, Roles from bot.utils.checks import with_role_check -from bot.utils.extensions import EXTENSIONS, invoke_help_command, unqualify from bot.utils.pagination import LinePaginator log = logging.getLogger(__name__) @@ -46,13 +46,13 @@ class Extension(commands.Converter): argument = argument.lower() - if argument in EXTENSIONS: + if argument in ctx.bot.all_extensions: return argument - elif (qualified_arg := f"{exts.__name__}.{argument}") in EXTENSIONS: + elif (qualified_arg := f"{exts.__name__}.{argument}") in ctx.bot.all_extensions: return qualified_arg matches = [] - for ext in EXTENSIONS: + for ext in ctx.bot.all_extensions: if argument == unqualify(ext): matches.append(ext) @@ -78,7 +78,7 @@ class Extensions(commands.Cog): @group(name="extensions", aliases=("ext", "exts", "c", "cogs"), invoke_without_command=True) async def extensions_group(self, ctx: Context) -> None: """Load, unload, reload, and list loaded extensions.""" - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @extensions_group.command(name="load", aliases=("l",)) async def load_command(self, ctx: Context, *extensions: Extension) -> None: @@ -88,11 +88,11 @@ class Extensions(commands.Cog): If '\*' or '\*\*' is given as the name, all unloaded extensions will be loaded. """ # noqa: W605 if not extensions: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return if "*" in extensions or "**" in extensions: - extensions = set(EXTENSIONS) - set(self.bot.extensions.keys()) + extensions = set(self.bot.all_extensions) - set(self.bot.extensions.keys()) msg = self.batch_manage(Action.LOAD, *extensions) await ctx.send(msg) @@ -105,7 +105,7 @@ class Extensions(commands.Cog): If '\*' or '\*\*' is given as the name, all loaded extensions will be unloaded. """ # noqa: W605 if not extensions: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return blacklisted = "\n".join(UNLOAD_BLACKLIST & set(extensions)) @@ -131,11 +131,11 @@ class Extensions(commands.Cog): If '\*\*' is given as the name, all extensions, including unloaded ones, will be reloaded. """ # noqa: W605 if not extensions: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return if "**" in extensions: - extensions = EXTENSIONS + extensions = self.bot.all_extensions elif "*" in extensions: extensions = set(self.bot.extensions.keys()) | set(extensions) extensions.remove("*") @@ -175,7 +175,7 @@ class Extensions(commands.Cog): """Return a mapping of extension names and statuses to their categories.""" categories = {} - for ext in EXTENSIONS: + for ext in self.bot.all_extensions: if ext in self.bot.extensions: status = Emojis.status_online else: diff --git a/bot/exts/core/internal_eval/_internal_eval.py b/bot/exts/core/internal_eval/_internal_eval.py index 190a15ec..2daf8ef9 100644 --- a/bot/exts/core/internal_eval/_internal_eval.py +++ b/bot/exts/core/internal_eval/_internal_eval.py @@ -9,7 +9,6 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Client, Roles from bot.utils.decorators import with_role -from bot.utils.extensions import invoke_help_command from ._helpers import EvalContext @@ -154,7 +153,7 @@ class InternalEval(commands.Cog): async def internal_group(self, ctx: commands.Context) -> None: """Internal commands. Top secret!""" if not ctx.invoked_subcommand: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @internal_group.command(name="eval", aliases=("e",)) @with_role(Roles.admins) diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 1d8b0ca7..ab5a7a34 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -18,7 +18,6 @@ from bot.exts.events.advent_of_code.views.dayandstarview import AoCDropdownView from bot.utils import members from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role from bot.utils.exceptions import MovedCommandError -from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) @@ -122,7 +121,7 @@ class AdventOfCode(commands.Cog): async def adventofcode_group(self, ctx: commands.Context) -> None: """All of the Advent of Code commands.""" if not ctx.invoked_subcommand: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @with_role(Roles.admins) @adventofcode_group.command( diff --git a/bot/exts/fun/game.py b/bot/exts/fun/game.py index 5f56bef7..4730d5b3 100644 --- a/bot/exts/fun/game.py +++ b/bot/exts/fun/game.py @@ -15,7 +15,6 @@ from discord.ext.commands import Cog, Context, group from bot.bot import Bot from bot.constants import STAFF_ROLES, Tokens from bot.utils.decorators import with_role -from bot.utils.extensions import invoke_help_command from bot.utils.pagination import ImagePaginator, LinePaginator # Base URL of IGDB API @@ -267,7 +266,7 @@ class Games(Cog): """ # When user didn't specified genre, send help message if genre is None: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return # Capitalize genre for check diff --git a/bot/exts/fun/minesweeper.py b/bot/exts/fun/minesweeper.py index a48b5051..782fb9d8 100644 --- a/bot/exts/fun/minesweeper.py +++ b/bot/exts/fun/minesweeper.py @@ -11,7 +11,6 @@ from bot.bot import Bot from bot.constants import Client from bot.utils.converters import CoordinateConverter from bot.utils.exceptions import UserNotPlayingError -from bot.utils.extensions import invoke_help_command MESSAGE_MAPPING = { 0: ":stop_button:", @@ -51,13 +50,14 @@ class Game: class Minesweeper(commands.Cog): """Play a game of Minesweeper.""" - def __init__(self): + def __init__(self, bot: Bot): + self.bot = bot self.games: dict[int, Game] = {} @commands.group(name="minesweeper", aliases=("ms",), invoke_without_command=True) async def minesweeper_group(self, ctx: commands.Context) -> None: """Commands for Playing Minesweeper.""" - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @staticmethod def get_neighbours(x: int, y: int) -> Iterator[tuple[int, int]]: @@ -267,4 +267,4 @@ class Minesweeper(commands.Cog): def setup(bot: Bot) -> None: """Load the Minesweeper cog.""" - bot.add_cog(Minesweeper()) + bot.add_cog(Minesweeper(bot)) diff --git a/bot/exts/fun/movie.py b/bot/exts/fun/movie.py index a04eeb41..4418b938 100644 --- a/bot/exts/fun/movie.py +++ b/bot/exts/fun/movie.py @@ -9,7 +9,6 @@ from discord.ext.commands import Cog, Context, group from bot.bot import Bot from bot.constants import Tokens -from bot.utils.extensions import invoke_help_command from bot.utils.pagination import ImagePaginator # Define base URL of TMDB @@ -50,6 +49,7 @@ class Movie(Cog): """Movie Cog contains movies command that grab random movies from TMDB.""" def __init__(self, bot: Bot): + self.bot = bot self.http_session: ClientSession = bot.http_session @group(name="movies", aliases=("movie",), invoke_without_command=True) @@ -73,7 +73,7 @@ class Movie(Cog): try: result = await self.get_movies_data(self.http_session, MovieGenres[genre].value, 1) except KeyError: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return # Check if "results" is in result. If not, throw error. diff --git a/bot/exts/fun/snakes/_snakes_cog.py b/bot/exts/fun/snakes/_snakes_cog.py index 59e57199..96718200 100644 --- a/bot/exts/fun/snakes/_snakes_cog.py +++ b/bot/exts/fun/snakes/_snakes_cog.py @@ -22,7 +22,6 @@ from bot.constants import ERROR_REPLIES, Tokens from bot.exts.fun.snakes import _utils as utils from bot.exts.fun.snakes._converter import Snake from bot.utils.decorators import locked -from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) @@ -440,7 +439,7 @@ class Snakes(Cog): @group(name="snakes", aliases=("snake",), invoke_without_command=True) async def snakes_group(self, ctx: Context) -> None: """Commands from our first code jam.""" - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @bot_has_permissions(manage_messages=True) @snakes_group.command(name="antidote") diff --git a/bot/exts/fun/space.py b/bot/exts/fun/space.py index 48ad0f96..0bbe0b33 100644 --- a/bot/exts/fun/space.py +++ b/bot/exts/fun/space.py @@ -11,7 +11,6 @@ from discord.ext.commands import Cog, Context, group from bot.bot import Bot from bot.constants import Tokens from bot.utils.converters import DateConverter -from bot.utils.extensions import invoke_help_command logger = logging.getLogger(__name__) @@ -27,6 +26,7 @@ class Space(Cog): def __init__(self, bot: Bot): self.http_session = bot.http_session + self.bot = bot self.rovers = {} self.get_rovers.start() @@ -50,7 +50,7 @@ class Space(Cog): @group(name="space", invoke_without_command=True) async def space(self, ctx: Context) -> None: """Head command that contains commands about space.""" - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @space.command(name="apod") async def apod(self, ctx: Context, date: Optional[str]) -> None: diff --git a/bot/exts/utilities/colour.py b/bot/exts/utilities/colour.py index ee6bad93..5282bc6d 100644 --- a/bot/exts/utilities/colour.py +++ b/bot/exts/utilities/colour.py @@ -13,7 +13,6 @@ from discord.ext import commands from bot import constants from bot.bot import Bot -from bot.exts.core.extensions import invoke_help_command from bot.utils.decorators import whitelist_override THUMBNAIL_SIZE = (80, 80) @@ -99,7 +98,7 @@ class Colour(commands.Cog): extra_colour = ImageColor.getrgb(colour_input) await self.send_colour_response(ctx, extra_colour) except ValueError: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @colour.command() async def rgb(self, ctx: commands.Context, red: int, green: int, blue: int) -> None: diff --git a/bot/exts/utilities/emoji.py b/bot/exts/utilities/emoji.py index fa438d7f..2b2fab8a 100644 --- a/bot/exts/utilities/emoji.py +++ b/bot/exts/utilities/emoji.py @@ -10,7 +10,6 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, ERROR_REPLIES -from bot.utils.extensions import invoke_help_command from bot.utils.pagination import LinePaginator from bot.utils.time import time_since @@ -20,6 +19,9 @@ log = logging.getLogger(__name__) class Emojis(commands.Cog): """A collection of commands related to emojis in the server.""" + def __init__(self, bot: Bot) -> None: + self.bot = bot + @staticmethod def embed_builder(emoji: dict) -> tuple[Embed, list[str]]: """Generates an embed with the emoji names and count.""" @@ -74,7 +76,7 @@ class Emojis(commands.Cog): if emoji is not None: await ctx.invoke(self.info_command, emoji) else: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @emoji_group.command(name="count", aliases=("c",)) async def count_command(self, ctx: commands.Context, *, category_query: str = None) -> None: @@ -120,4 +122,4 @@ class Emojis(commands.Cog): def setup(bot: Bot) -> None: """Load the Emojis cog.""" - bot.add_cog(Emojis()) + bot.add_cog(Emojis(bot)) diff --git a/bot/exts/utilities/epoch.py b/bot/exts/utilities/epoch.py index 42312dd1..2a21688e 100644 --- a/bot/exts/utilities/epoch.py +++ b/bot/exts/utilities/epoch.py @@ -6,7 +6,6 @@ from dateutil import parser from discord.ext import commands from bot.bot import Bot -from bot.utils.extensions import invoke_help_command # https://discord.com/developers/docs/reference#message-formatting-timestamp-styles STYLES = { @@ -48,6 +47,9 @@ class DateString(commands.Converter): class Epoch(commands.Cog): """Convert an entered time and date to a unix timestamp.""" + def __init__(self, bot: Bot) -> None: + self.bot = bot + @commands.command(name="epoch") async def epoch(self, ctx: commands.Context, *, date_time: DateString = None) -> None: """ @@ -71,7 +73,7 @@ class Epoch(commands.Cog): Times in the dropdown are shown in UTC """ if not date_time: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return if isinstance(date_time, tuple): @@ -135,4 +137,4 @@ class TimestampMenuView(discord.ui.View): def setup(bot: Bot) -> None: """Load the Epoch cog.""" - bot.add_cog(Epoch()) + bot.add_cog(Epoch(bot)) diff --git a/bot/exts/utilities/githubinfo.py b/bot/exts/utilities/githubinfo.py index 046f67df..ed176290 100644 --- a/bot/exts/utilities/githubinfo.py +++ b/bot/exts/utilities/githubinfo.py @@ -12,7 +12,6 @@ from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, ERROR_REPLIES, Emojis, NEGATIVE_REPLIES, Tokens -from bot.exts.core.extensions import invoke_help_command log = logging.getLogger(__name__) @@ -168,7 +167,7 @@ class GithubInfo(commands.Cog): async def github_group(self, ctx: commands.Context) -> None: """Commands for finding information related to GitHub.""" if ctx.invoked_subcommand is None: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @commands.Cog.listener() async def on_message(self, message: discord.Message) -> None: diff --git a/bot/exts/utilities/reddit.py b/bot/exts/utilities/reddit.py index 782583d2..fa50eb36 100644 --- a/bot/exts/utilities/reddit.py +++ b/bot/exts/utilities/reddit.py @@ -15,7 +15,6 @@ from discord.utils import escape_markdown, sleep_until from bot.bot import Bot from bot.constants import Channels, ERROR_REPLIES, Emojis, Reddit as RedditConfig, STAFF_ROLES from bot.utils.converters import Subreddit -from bot.utils.extensions import invoke_help_command from bot.utils.messages import sub_clyde from bot.utils.pagination import ImagePaginator, LinePaginator @@ -302,7 +301,7 @@ class Reddit(Cog): @group(name="reddit", invoke_without_command=True) async def reddit_group(self, ctx: Context) -> None: """View the top posts from various subreddits.""" - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) @reddit_group.command(name="top") async def top_command(self, ctx: Context, subreddit: Subreddit = "r/Python") -> None: diff --git a/bot/exts/utilities/twemoji.py b/bot/exts/utilities/twemoji.py index c915f05b..a4477bc1 100644 --- a/bot/exts/utilities/twemoji.py +++ b/bot/exts/utilities/twemoji.py @@ -9,7 +9,6 @@ from emoji import UNICODE_EMOJI_ENGLISH, is_emoji from bot.bot import Bot from bot.constants import Colours, Roles from bot.utils.decorators import whitelist_override -from bot.utils.extensions import invoke_help_command log = logging.getLogger(__name__) BASE_URLS = { @@ -133,7 +132,7 @@ class Twemoji(commands.Cog): async def twemoji(self, ctx: commands.Context, *raw_emoji: str) -> None: """Sends a preview of a given Twemoji, specified by codepoint or emoji.""" if len(raw_emoji) == 0: - await invoke_help_command(ctx) + await self.bot.invoke_help_command(ctx) return try: codepoint = self.codepoint_from_input(raw_emoji) diff --git a/bot/utils/extensions.py b/bot/utils/extensions.py deleted file mode 100644 index 09192ae2..00000000 --- a/bot/utils/extensions.py +++ /dev/null @@ -1,45 +0,0 @@ -import importlib -import inspect -import pkgutil -from collections.abc import Iterator -from typing import NoReturn - -from discord.ext.commands import Context - -from bot import exts - - -def unqualify(name: str) -> str: - """Return an unqualified name given a qualified module/package `name`.""" - return name.rsplit(".", maxsplit=1)[-1] - - -def walk_extensions() -> Iterator[str]: - """Yield extension names from the bot.exts subpackage.""" - - def on_error(name: str) -> NoReturn: - raise ImportError(name=name) # pragma: no cover - - for module in pkgutil.walk_packages(exts.__path__, f"{exts.__name__}.", onerror=on_error): - if unqualify(module.name).startswith("_"): - # Ignore module/package names starting with an underscore. - continue - - if module.ispkg: - imported = importlib.import_module(module.name) - if not inspect.isfunction(getattr(imported, "setup", None)): - # If it lacks a setup function, it's not an extension. - continue - - yield module.name - - -async def invoke_help_command(ctx: Context) -> None: - """Invoke the help command or default help command if help extensions is not loaded.""" - if "bot.exts.core.help" in ctx.bot.extensions: - help_command = ctx.bot.get_command("help") - await ctx.invoke(help_command, ctx.command.qualified_name) - return - await ctx.send_help(ctx.command) - -EXTENSIONS = frozenset(walk_extensions()) -- cgit v1.2.3 From 952a3a7849d4694cc3e4aa89021d3c976cdc537b Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 23 Sep 2022 22:12:26 +0100 Subject: Remove all wait_until_guil_available as this is now done in bot-core --- bot/bot.py | 1 - bot/exts/events/advent_of_code/_cog.py | 1 - bot/exts/events/advent_of_code/_helpers.py | 10 ---------- bot/exts/holidays/easter/egg_facts.py | 2 -- bot/exts/holidays/halloween/spookynamerate.py | 1 - bot/exts/holidays/pride/pride_facts.py | 2 -- bot/exts/utilities/logging.py | 2 -- bot/exts/utilities/reddit.py | 5 +---- 8 files changed, 1 insertion(+), 23 deletions(-) (limited to 'bot/bot.py') diff --git a/bot/bot.py b/bot/bot.py index 9309f50c..636946f1 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -42,7 +42,6 @@ class Bot(BotBase): async def log_to_dev_log(self, title: str, details: str = None, *, icon: str = None) -> None: """Send an embed message to the dev-log channel.""" - await self.wait_until_guild_available() devlog = self.get_channel(constants.Channels.devlog) if not icon: diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index ab5a7a34..49140a3f 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -70,7 +70,6 @@ class AdventOfCode(commands.Cog): Runs on a schedule, as defined in the task.loop decorator. """ - await self.bot.wait_until_guild_available() guild = self.bot.get_guild(Client.guild) completionist_role = guild.get_role(Roles.aoc_completionist) if completionist_role is None: diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index 6c004901..abd80b77 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -523,13 +523,6 @@ async def countdown_status(bot: Bot) -> None: # Log that we're going to start with the countdown status. log.info("The Advent of Code has started or will start soon, starting countdown status.") - # Trying to change status too early in the bot's startup sequence will fail - # the task because the websocket instance has not yet been created. Waiting - # for this event means that both the websocket instance has been initialized - # and that the connection to Discord is mature enough to change the presence - # of the bot. - await bot.wait_until_guild_available() - # Calculate when the task needs to stop running. To prevent the task from # sleeping for the entire year, it will only wait in the currently # configured year. This means that the task will only start hibernating once @@ -578,9 +571,6 @@ async def new_puzzle_notification(bot: Bot) -> None: log.info("The Advent of Code has started or will start soon, waking up notification task.") - # Ensure that the guild cache is loaded so we can get the Advent of Code - # channel and role. - await bot.wait_until_guild_available() aoc_channel = bot.get_channel(Channels.advent_of_code) aoc_role = aoc_channel.guild.get_role(AdventOfCode.role_id) diff --git a/bot/exts/holidays/easter/egg_facts.py b/bot/exts/holidays/easter/egg_facts.py index 2fb2041e..43b31c7b 100644 --- a/bot/exts/holidays/easter/egg_facts.py +++ b/bot/exts/holidays/easter/egg_facts.py @@ -29,8 +29,6 @@ class EasterFacts(commands.Cog): @seasonal_task(Month.APRIL) async def send_egg_fact_daily(self) -> None: """A background task that sends an easter egg fact in the event channel everyday.""" - await self.bot.wait_until_guild_available() - channel = self.bot.get_channel(Channels.sir_lancebot_playground) await channel.send(embed=self.make_embed()) diff --git a/bot/exts/holidays/halloween/spookynamerate.py b/bot/exts/holidays/halloween/spookynamerate.py index 5d41ce6d..a76e5e12 100644 --- a/bot/exts/holidays/halloween/spookynamerate.py +++ b/bot/exts/holidays/halloween/spookynamerate.py @@ -355,7 +355,6 @@ class SpookyNameRate(Cog): async def get_channel(self) -> Optional[TextChannel]: """Gets the sir-lancebot-channel after waiting until ready.""" - await self.bot.wait_until_ready() channel = self.bot.get_channel( Channels.sir_lancebot_playground ) or await self.bot.fetch_channel(Channels.sir_lancebot_playground) diff --git a/bot/exts/holidays/pride/pride_facts.py b/bot/exts/holidays/pride/pride_facts.py index ae025ae7..36a9415e 100644 --- a/bot/exts/holidays/pride/pride_facts.py +++ b/bot/exts/holidays/pride/pride_facts.py @@ -28,8 +28,6 @@ class PrideFacts(commands.Cog): @seasonal_task(Month.JUNE) async def send_pride_fact_daily(self) -> None: """Background task to post the daily pride fact every day.""" - await self.bot.wait_until_guild_available() - channel = self.bot.get_channel(Channels.sir_lancebot_playground) await self.send_select_fact(channel, datetime.utcnow()) diff --git a/bot/exts/utilities/logging.py b/bot/exts/utilities/logging.py index e1d09fdf..83b7025f 100644 --- a/bot/exts/utilities/logging.py +++ b/bot/exts/utilities/logging.py @@ -23,8 +23,6 @@ class Logging(Cog): async def check_channels(self) -> None: """Verifies that all channel constants refer to channels which exist.""" - await self.bot.wait_until_guild_available() - if constants.Client.debug: log.info("Skipping Channels Check.") return diff --git a/bot/exts/utilities/reddit.py b/bot/exts/utilities/reddit.py index 07222d79..028c16bc 100644 --- a/bot/exts/utilities/reddit.py +++ b/bot/exts/utilities/reddit.py @@ -48,9 +48,7 @@ class Reddit(Cog): async def cog_load(self) -> None: """Sets the reddit webhook when the cog is loaded.""" - await self.bot.wait_until_guild_available() - if not self.webhook: - self.webhook = await self.bot.fetch_webhook(RedditConfig.webhook) + self.webhook = await self.bot.fetch_webhook(RedditConfig.webhook) @property def channel(self) -> TextChannel: @@ -256,7 +254,6 @@ class Reddit(Cog): await sleep_until(midnight_tomorrow) - await self.bot.wait_until_guild_available() if not self.webhook: await self.bot.fetch_webhook(RedditConfig.webhook) -- cgit v1.2.3