From ad502cf1ea684912de57c1ab11aef5c7577e414e Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 20:58:00 -0700 Subject: [PATCH 01/10] Categorize Extensions --- bot.py | 66 ++++----- commands/__init__.py | 9 -- ircrelay/relay.py | 4 +- modules/__init__.py | 7 + .../administration}/backup.py | 0 .../administration}/botinfo.py | 0 .../administration}/commandcontrol.py | 0 .../administration}/config.py | 0 {commands => modules/administration}/debug.py | 0 {commands => modules/administration}/echo.py | 2 +- {commands => modules/administration}/embed.py | 0 .../administration}/extension.py | 0 .../administration}/github.py | 0 {commands => modules/administration}/leave.py | 0 .../administration}/listen.py | 0 .../administration}/restart.py | 0 {commands => modules/administration}/set.py | 0 {commands => modules/administration}/sync.py | 0 {commands => modules/fun}/animal.py | 0 {functions => modules/fun}/autoreact.py | 0 modules/fun/botinfo.py | 125 ++++++++++++++++++ {commands => modules/fun}/burn.py | 0 {commands => modules/fun}/conch.py | 0 {commands => modules/fun}/correct.py | 0 {commands => modules/fun}/duck.py | 0 {commands => modules/fun}/emoji.py | 0 {commands => modules/fun}/giphy.py | 0 {commands => modules/fun}/grab.py | 0 {commands => modules/fun}/hangman.py | 0 {commands => modules/fun}/hello.py | 0 {commands => modules/fun}/hug.py | 0 {commands => modules/fun}/joke.py | 0 {commands => modules/fun}/kanye.py | 0 {commands => modules/fun}/lenny.py | 0 {commands => modules/fun}/mock.py | 0 {commands => modules/fun}/roll.py | 0 {commands => modules/fun}/wyr.py | 0 {commands => modules/fun}/xkcd.py | 0 modules/moderation/__init__.py | 8 ++ {functions => modules/moderation}/automod.py | 2 +- {functions => modules/moderation}/events.py | 0 {commands => modules/moderation}/gate.py | 0 {functions => modules/moderation}/honeypot.py | 0 {functions => modules/moderation}/logger.py | 0 {commands => modules/moderation}/members.py | 0 {commands => modules/moderation}/moderator.py | 2 +- {commands => modules/moderation}/modlog.py | 0 {commands => modules/moderation}/modmail.py | 2 +- {functions => modules/moderation}/nickname.py | 0 .../moderation}/nicknamefix.py | 2 +- {commands => modules/moderation}/notes.py | 0 {commands => modules/moderation}/purge.py | 0 {commands => modules/moderation}/report.py | 0 {commands => modules/moderation}/role.py | 0 {commands => modules/moderation}/rules.py | 0 {commands => modules/moderation}/slowmode.py | 0 {commands => modules/moderation}/whois.py | 3 +- modules/operation/__init__.py | 5 + .../operation}/application.py | 0 {commands => modules/operation}/factoids.py | 2 +- {commands => modules/operation}/forum.py | 0 {functions => modules/operation}/paste.py | 2 +- {commands => modules/operation}/relay.py | 4 +- {commands => modules/operation}/voting.py | 0 {commands => modules/operation}/xp.py | 0 {commands => modules/utility}/chatgpt.py | 0 {commands => modules/utility}/dictionary.py | 0 {commands => modules/utility}/dumpdbg.py | 0 {commands => modules/utility}/help.py | 0 {commands => modules/utility}/htd.py | 0 {commands => modules/utility}/ipinfo.py | 0 {commands => modules/utility}/iss.py | 0 {commands => modules/utility}/linter.py | 0 {commands => modules/utility}/news.py | 0 {commands => modules/utility}/poll.py | 0 {commands => modules/utility}/search.py | 0 {commands => modules/utility}/spotify.py | 0 {commands => modules/utility}/translate.py | 0 {commands => modules/utility}/urban.py | 0 {commands => modules/utility}/weather.py | 0 {commands => modules/utility}/winerror.py | 0 {commands => modules/utility}/wolfram.py | 0 {commands => modules/utility}/youtube.py | 0 83 files changed, 182 insertions(+), 63 deletions(-) create mode 100644 modules/__init__.py rename {commands => modules/administration}/backup.py (100%) rename {commands => modules/administration}/botinfo.py (100%) rename {commands => modules/administration}/commandcontrol.py (100%) rename {commands => modules/administration}/config.py (100%) rename {commands => modules/administration}/debug.py (100%) rename {commands => modules/administration}/echo.py (98%) rename {commands => modules/administration}/embed.py (100%) rename {commands => modules/administration}/extension.py (100%) rename {commands => modules/administration}/github.py (100%) rename {commands => modules/administration}/leave.py (100%) rename {commands => modules/administration}/listen.py (100%) rename {commands => modules/administration}/restart.py (100%) rename {commands => modules/administration}/set.py (100%) rename {commands => modules/administration}/sync.py (100%) rename {commands => modules/fun}/animal.py (100%) rename {functions => modules/fun}/autoreact.py (100%) create mode 100644 modules/fun/botinfo.py rename {commands => modules/fun}/burn.py (100%) rename {commands => modules/fun}/conch.py (100%) rename {commands => modules/fun}/correct.py (100%) rename {commands => modules/fun}/duck.py (100%) rename {commands => modules/fun}/emoji.py (100%) rename {commands => modules/fun}/giphy.py (100%) rename {commands => modules/fun}/grab.py (100%) rename {commands => modules/fun}/hangman.py (100%) rename {commands => modules/fun}/hello.py (100%) rename {commands => modules/fun}/hug.py (100%) rename {commands => modules/fun}/joke.py (100%) rename {commands => modules/fun}/kanye.py (100%) rename {commands => modules/fun}/lenny.py (100%) rename {commands => modules/fun}/mock.py (100%) rename {commands => modules/fun}/roll.py (100%) rename {commands => modules/fun}/wyr.py (100%) rename {commands => modules/fun}/xkcd.py (100%) create mode 100644 modules/moderation/__init__.py rename {functions => modules/moderation}/automod.py (99%) rename {functions => modules/moderation}/events.py (100%) rename {commands => modules/moderation}/gate.py (100%) rename {functions => modules/moderation}/honeypot.py (100%) rename {functions => modules/moderation}/logger.py (100%) rename {commands => modules/moderation}/members.py (100%) rename {commands => modules/moderation}/moderator.py (99%) rename {commands => modules/moderation}/modlog.py (100%) rename {commands => modules/moderation}/modmail.py (99%) rename {functions => modules/moderation}/nickname.py (100%) rename {commands => modules/moderation}/nicknamefix.py (98%) rename {commands => modules/moderation}/notes.py (100%) rename {commands => modules/moderation}/purge.py (100%) rename {commands => modules/moderation}/report.py (100%) rename {commands => modules/moderation}/role.py (100%) rename {commands => modules/moderation}/rules.py (100%) rename {commands => modules/moderation}/slowmode.py (100%) rename {commands => modules/moderation}/whois.py (98%) create mode 100644 modules/operation/__init__.py rename {commands => modules/operation}/application.py (100%) rename {commands => modules/operation}/factoids.py (99%) rename {commands => modules/operation}/forum.py (100%) rename {functions => modules/operation}/paste.py (99%) rename {commands => modules/operation}/relay.py (99%) rename {commands => modules/operation}/voting.py (100%) rename {commands => modules/operation}/xp.py (100%) rename {commands => modules/utility}/chatgpt.py (100%) rename {commands => modules/utility}/dictionary.py (100%) rename {commands => modules/utility}/dumpdbg.py (100%) rename {commands => modules/utility}/help.py (100%) rename {commands => modules/utility}/htd.py (100%) rename {commands => modules/utility}/ipinfo.py (100%) rename {commands => modules/utility}/iss.py (100%) rename {commands => modules/utility}/linter.py (100%) rename {commands => modules/utility}/news.py (100%) rename {commands => modules/utility}/poll.py (100%) rename {commands => modules/utility}/search.py (100%) rename {commands => modules/utility}/spotify.py (100%) rename {commands => modules/utility}/translate.py (100%) rename {commands => modules/utility}/urban.py (100%) rename {commands => modules/utility}/weather.py (100%) rename {commands => modules/utility}/winerror.py (100%) rename {commands => modules/utility}/wolfram.py (100%) rename {commands => modules/utility}/youtube.py (100%) diff --git a/bot.py b/bot.py index df4343d21..3c64b8af9 100644 --- a/bot.py +++ b/bot.py @@ -49,7 +49,7 @@ class TechSupportBot(commands.Bot): """ CONFIG_PATH: str = os.environ.get("CONFIG_YML", "./config.yml") - EXTENSIONS_DIR_NAME: str = "commands" + EXTENSIONS_DIR_NAME: str = "modules" EXTENSIONS_DIR: str = ( f"{os.path.join(os.path.dirname(__file__))}/{EXTENSIONS_DIR_NAME}" ) @@ -482,7 +482,6 @@ async def get_postgres_ref(self: Self) -> gino.GinoEngine: async def get_potential_extensions(self: Self) -> list[str]: """Gets the current list of extensions in the defined directory. - This ONLY gets commands, not functions Returns: list[str]: Gets a list of the string names of every python file @@ -490,27 +489,29 @@ async def get_potential_extensions(self: Self) -> list[str]: """ self.logger.console.info(f"Searching {self.EXTENSIONS_DIR} for extensions") - extensions_list = [ - os.path.basename(f)[:-3] - for f in glob.glob(f"{self.EXTENSIONS_DIR}/*.py") - if os.path.isfile(f) and not f.endswith("__init__.py") - ] - return extensions_list + pattern = os.path.join(self.EXTENSIONS_DIR, "**", "*.py") - async def get_potential_function_extensions(self: Self) -> list[str]: - """Gets the current list of extensions in the defined directory. - This ONLY gets functions, not commands + extensions_list = [] - Returns: - list[str]: Gets a list of the string names of every python file - in the functions folder - """ - self.logger.console.info(f"Searching {self.FUNCTIONS_DIR} for extensions") - extensions_list = [ - os.path.basename(f)[:-3] - for f in glob.glob(f"{self.FUNCTIONS_DIR}/*.py") - if os.path.isfile(f) and not f.endswith("__init__.py") - ] + for file_path in glob.glob(pattern, recursive=True): + if not os.path.isfile(file_path): + continue + + if file_path.endswith("__init__.py"): + continue + + # strip root dir + rel_path = os.path.relpath(file_path, self.EXTENSIONS_DIR) + + # remove .py + rel_path = rel_path[:-3] + + # convert folder separators into dots + dotted = rel_path.replace(os.sep, ".") + + extensions_list.append(dotted) + + print(extensions_list) return extensions_list async def load_extensions(self: Self, graceful: bool = True) -> None: @@ -545,27 +546,8 @@ async def load_extensions(self: Self, graceful: bool = True) -> None: if not graceful: raise exception - self.logger.console.debug("Retrieving functions") - for extension_name in await self.get_potential_function_extensions(): - if extension_name in self.file_config.bot_config.disabled_extensions: - self.logger.console.debug( - f"{extension_name} is disabled on startup - ignoring load" - ) - continue - - try: - await self.load_extension(f"{self.FUNCTIONS_DIR_NAME}.{extension_name}") - self.extension_name_list.append(extension_name) - except Exception as exception: - self.logger.console.error( - f"Failed to load extension {extension_name}: {exception}" - ) - if not graceful: - raise exception - def get_command_extension_name(self: Self, command: commands.Command) -> str: - """Gets the subname of an extension from a command. - Used only for commands, should never be run for a function + """Gets the subname of an module from a command. Args: command (commands.Command): the command to reference @@ -575,7 +557,7 @@ def get_command_extension_name(self: Self, command: commands.Command) -> str: """ if not command.module.startswith(f"{self.EXTENSIONS_DIR_NAME}."): return None - extension_name = command.module.split(".")[1] + extension_name = ".".join(command.module.split(".")[1:]).replace(".py", "") return extension_name async def register_file_extension( diff --git a/commands/__init__.py b/commands/__init__.py index 23b499ed4..c7f399496 100644 --- a/commands/__init__.py +++ b/commands/__init__.py @@ -3,10 +3,8 @@ Both app and prefix commands are in this module """ -from .application import * from .burn import * from .conch import * -from .config import * from .correct import * from .emoji import * from .hello import * @@ -15,13 +13,6 @@ from .hug import * from .lenny import * from .linter import * -from .listen import * from .mock import * -from .moderator import * -from .modlog import * -from .notes import * -from .relay import * from .roll import * -from .rules import * from .wyr import * -from .xp import * diff --git a/ircrelay/relay.py b/ircrelay/relay.py index a23617f5f..e3bde6242 100644 --- a/ircrelay/relay.py +++ b/ircrelay/relay.py @@ -16,7 +16,7 @@ import irc.client import irc.connection -import commands +import modules.operation from ircrelay import formatting @@ -43,7 +43,7 @@ class IRCBot(irc.bot.SingleServerIRCBot): password (str): The password of the IRC bot account """ - irc_cog: commands.relay.DiscordToIRC = None + irc_cog: modules.operation.relay.DiscordToIRC = None loop: asyncio.AbstractEventLoop = None console: logging.Logger = logging.getLogger("root") IRC_BOLD: str = "" diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 000000000..d995bff49 --- /dev/null +++ b/modules/__init__.py @@ -0,0 +1,7 @@ +"""All the customizable modules for the bot""" + +from .administration import * +from .moderation import * +from .operation import * +from .fun import * +from .utility import * diff --git a/commands/backup.py b/modules/administration/backup.py similarity index 100% rename from commands/backup.py rename to modules/administration/backup.py diff --git a/commands/botinfo.py b/modules/administration/botinfo.py similarity index 100% rename from commands/botinfo.py rename to modules/administration/botinfo.py diff --git a/commands/commandcontrol.py b/modules/administration/commandcontrol.py similarity index 100% rename from commands/commandcontrol.py rename to modules/administration/commandcontrol.py diff --git a/commands/config.py b/modules/administration/config.py similarity index 100% rename from commands/config.py rename to modules/administration/config.py diff --git a/commands/debug.py b/modules/administration/debug.py similarity index 100% rename from commands/debug.py rename to modules/administration/debug.py diff --git a/commands/echo.py b/modules/administration/echo.py similarity index 98% rename from commands/echo.py rename to modules/administration/echo.py index 7264e66d8..59442a1eb 100644 --- a/commands/echo.py +++ b/modules/administration/echo.py @@ -16,7 +16,7 @@ import configuration from core import auxiliary, cogs -from functions import logger as function_logger +from modules.moderation import logger as function_logger if TYPE_CHECKING: import bot diff --git a/commands/embed.py b/modules/administration/embed.py similarity index 100% rename from commands/embed.py rename to modules/administration/embed.py diff --git a/commands/extension.py b/modules/administration/extension.py similarity index 100% rename from commands/extension.py rename to modules/administration/extension.py diff --git a/commands/github.py b/modules/administration/github.py similarity index 100% rename from commands/github.py rename to modules/administration/github.py diff --git a/commands/leave.py b/modules/administration/leave.py similarity index 100% rename from commands/leave.py rename to modules/administration/leave.py diff --git a/commands/listen.py b/modules/administration/listen.py similarity index 100% rename from commands/listen.py rename to modules/administration/listen.py diff --git a/commands/restart.py b/modules/administration/restart.py similarity index 100% rename from commands/restart.py rename to modules/administration/restart.py diff --git a/commands/set.py b/modules/administration/set.py similarity index 100% rename from commands/set.py rename to modules/administration/set.py diff --git a/commands/sync.py b/modules/administration/sync.py similarity index 100% rename from commands/sync.py rename to modules/administration/sync.py diff --git a/commands/animal.py b/modules/fun/animal.py similarity index 100% rename from commands/animal.py rename to modules/fun/animal.py diff --git a/functions/autoreact.py b/modules/fun/autoreact.py similarity index 100% rename from functions/autoreact.py rename to modules/fun/autoreact.py diff --git a/modules/fun/botinfo.py b/modules/fun/botinfo.py new file mode 100644 index 000000000..0e485b6a7 --- /dev/null +++ b/modules/fun/botinfo.py @@ -0,0 +1,125 @@ +""" +Commands which allow information about the bot to be shown +The cog in the file is named: + BotInfo + +This file contains 1 command: + .bot +""" + +from __future__ import annotations + +import re +from typing import TYPE_CHECKING, Self + +import discord +import git +from discord.ext import commands + +from core import auxiliary, cogs + +if TYPE_CHECKING: + import bot + + +async def setup(bot: bot.TechSupportBot) -> None: + """Loading the BotInfo plugin into the bot + + Args: + bot (bot.TechSupportBot): The bot object to register the cogs to + """ + await bot.add_cog(BotInfo(bot=bot)) + + +class BotInfo(cogs.BaseCog): + """ + The class that holds the bot command + """ + + @commands.check(auxiliary.bot_admin_check_context) + @commands.command(name="bot", description="Provides bot info") + async def get_bot_data(self: Self, ctx: commands.Context) -> None: + """Gets various data about the bot. + + This is a command and should be accessed via Discord. + + Args: + ctx (commands.Context): the context object for the calling message + """ + embed = discord.Embed(title=self.bot.user.name, color=discord.Color.blurple()) + + embed.add_field( + name="Started", + value=( + f"" + if self.bot.startup_time + else "Unknown" + ), + inline=True, + ) + embed.add_field( + name="Latency", + value=f"{self.bot.latency*1000} ms" if self.bot.latency else "None", + inline=True, + ) + embed.add_field( + name="Description", value=self.bot.description or "None", inline=True + ) + embed.add_field( + name="Servers", + value=", ".join(f"{guild.name} ({guild.id})" for guild in self.bot.guilds), + inline=True, + ) + irc_config = self.bot.file_config.api.irc + if not irc_config.enable_irc: + embed.add_field( + name="IRC", + value="IRC is not enabled", + inline=True, + ) + else: + irc_status = self.bot.irc.get_irc_status() + embed.add_field( + name="IRC", + value=f"IRC Status: `{irc_status['status']}`\n" + + f"IRC Bot Name: `{irc_status['name']}`\n" + + f"Channels: `{irc_status['channels']}`", + inline=True, + ) + try: + repo = git.Repo(search_parent_directories=True) + commit = repo.head.commit + commit_hash = commit.hexsha[:7] + commit_message = commit.message.splitlines()[0].strip() + branch_name = repo.active_branch.name + match = re.search( + r"github.com[:/](.*?)/(.*?)(?:.git)?$", repo.remotes.origin.url + ) + if match: + repo_owner = match.group(1) + repo_name = match.group(2) + else: + repo_owner = "" + repo_name = "" + + has_differences = repo.is_dirty() + + embed.add_field( + name="Version Info", + value=( + f"Upstream: `{repo_owner}/{repo_name}/{branch_name}`\n" + f"Commit: `{commit_hash} - {commit_message}`\n" + f"Local changes made: `{has_differences}`" + ), + inline=False, + ) + except Exception as exc: + embed.add_field( + name="Version Info", + value=f"There was an error getting version info: {exc}", + inline=False, + ) + + embed.set_thumbnail(url=self.bot.user.display_avatar.url) + + await ctx.send(embed=embed) diff --git a/commands/burn.py b/modules/fun/burn.py similarity index 100% rename from commands/burn.py rename to modules/fun/burn.py diff --git a/commands/conch.py b/modules/fun/conch.py similarity index 100% rename from commands/conch.py rename to modules/fun/conch.py diff --git a/commands/correct.py b/modules/fun/correct.py similarity index 100% rename from commands/correct.py rename to modules/fun/correct.py diff --git a/commands/duck.py b/modules/fun/duck.py similarity index 100% rename from commands/duck.py rename to modules/fun/duck.py diff --git a/commands/emoji.py b/modules/fun/emoji.py similarity index 100% rename from commands/emoji.py rename to modules/fun/emoji.py diff --git a/commands/giphy.py b/modules/fun/giphy.py similarity index 100% rename from commands/giphy.py rename to modules/fun/giphy.py diff --git a/commands/grab.py b/modules/fun/grab.py similarity index 100% rename from commands/grab.py rename to modules/fun/grab.py diff --git a/commands/hangman.py b/modules/fun/hangman.py similarity index 100% rename from commands/hangman.py rename to modules/fun/hangman.py diff --git a/commands/hello.py b/modules/fun/hello.py similarity index 100% rename from commands/hello.py rename to modules/fun/hello.py diff --git a/commands/hug.py b/modules/fun/hug.py similarity index 100% rename from commands/hug.py rename to modules/fun/hug.py diff --git a/commands/joke.py b/modules/fun/joke.py similarity index 100% rename from commands/joke.py rename to modules/fun/joke.py diff --git a/commands/kanye.py b/modules/fun/kanye.py similarity index 100% rename from commands/kanye.py rename to modules/fun/kanye.py diff --git a/commands/lenny.py b/modules/fun/lenny.py similarity index 100% rename from commands/lenny.py rename to modules/fun/lenny.py diff --git a/commands/mock.py b/modules/fun/mock.py similarity index 100% rename from commands/mock.py rename to modules/fun/mock.py diff --git a/commands/roll.py b/modules/fun/roll.py similarity index 100% rename from commands/roll.py rename to modules/fun/roll.py diff --git a/commands/wyr.py b/modules/fun/wyr.py similarity index 100% rename from commands/wyr.py rename to modules/fun/wyr.py diff --git a/commands/xkcd.py b/modules/fun/xkcd.py similarity index 100% rename from commands/xkcd.py rename to modules/fun/xkcd.py diff --git a/modules/moderation/__init__.py b/modules/moderation/__init__.py new file mode 100644 index 000000000..dbdb18522 --- /dev/null +++ b/modules/moderation/__init__.py @@ -0,0 +1,8 @@ +"""Modules designed for server moderation""" + +from .automod import * +from .logger import * +from .moderator import * +from .modlog import * +from .nickname import * +from .notes import * diff --git a/functions/automod.py b/modules/moderation/automod.py similarity index 99% rename from functions/automod.py rename to modules/moderation/automod.py index 470353e8c..aec28b7b1 100644 --- a/functions/automod.py +++ b/modules/moderation/automod.py @@ -12,8 +12,8 @@ import configuration from botlogging import LogContext, LogLevel -from commands import moderator, modlog from core import auxiliary, cogs, moderation +from modules.moderation import moderator, modlog if TYPE_CHECKING: import bot diff --git a/functions/events.py b/modules/moderation/events.py similarity index 100% rename from functions/events.py rename to modules/moderation/events.py diff --git a/commands/gate.py b/modules/moderation/gate.py similarity index 100% rename from commands/gate.py rename to modules/moderation/gate.py diff --git a/functions/honeypot.py b/modules/moderation/honeypot.py similarity index 100% rename from functions/honeypot.py rename to modules/moderation/honeypot.py diff --git a/functions/logger.py b/modules/moderation/logger.py similarity index 100% rename from functions/logger.py rename to modules/moderation/logger.py diff --git a/commands/members.py b/modules/moderation/members.py similarity index 100% rename from commands/members.py rename to modules/moderation/members.py diff --git a/commands/moderator.py b/modules/moderation/moderator.py similarity index 99% rename from commands/moderator.py rename to modules/moderation/moderator.py index 90de49d6d..1da3d07a9 100644 --- a/commands/moderator.py +++ b/modules/moderation/moderator.py @@ -12,8 +12,8 @@ import configuration import ui from botlogging import LogContext, LogLevel -from commands import modlog from core import auxiliary, cogs, moderation +from modules.moderation import modlog if TYPE_CHECKING: import bot diff --git a/commands/modlog.py b/modules/moderation/modlog.py similarity index 100% rename from commands/modlog.py rename to modules/moderation/modlog.py diff --git a/commands/modmail.py b/modules/moderation/modmail.py similarity index 99% rename from commands/modmail.py rename to modules/moderation/modmail.py index 0dcc5b8cc..526252828 100644 --- a/commands/modmail.py +++ b/modules/moderation/modmail.py @@ -24,8 +24,8 @@ import configuration import ui -from commands import rules from core import auxiliary, cogs +from modules.moderation import rules if TYPE_CHECKING: import bot diff --git a/functions/nickname.py b/modules/moderation/nickname.py similarity index 100% rename from functions/nickname.py rename to modules/moderation/nickname.py diff --git a/commands/nicknamefix.py b/modules/moderation/nicknamefix.py similarity index 98% rename from commands/nicknamefix.py rename to modules/moderation/nicknamefix.py index 53df55b10..a723e174a 100644 --- a/commands/nicknamefix.py +++ b/modules/moderation/nicknamefix.py @@ -9,7 +9,7 @@ from discord import app_commands from core import auxiliary, cogs -from functions import nickname +from modules.moderation import nickname if TYPE_CHECKING: import bot diff --git a/commands/notes.py b/modules/moderation/notes.py similarity index 100% rename from commands/notes.py rename to modules/moderation/notes.py diff --git a/commands/purge.py b/modules/moderation/purge.py similarity index 100% rename from commands/purge.py rename to modules/moderation/purge.py diff --git a/commands/report.py b/modules/moderation/report.py similarity index 100% rename from commands/report.py rename to modules/moderation/report.py diff --git a/commands/role.py b/modules/moderation/role.py similarity index 100% rename from commands/role.py rename to modules/moderation/role.py diff --git a/commands/rules.py b/modules/moderation/rules.py similarity index 100% rename from commands/rules.py rename to modules/moderation/rules.py diff --git a/commands/slowmode.py b/modules/moderation/slowmode.py similarity index 100% rename from commands/slowmode.py rename to modules/moderation/slowmode.py diff --git a/commands/whois.py b/modules/moderation/whois.py similarity index 98% rename from commands/whois.py rename to modules/moderation/whois.py index 5237b6ed9..cc403ae3f 100644 --- a/commands/whois.py +++ b/modules/moderation/whois.py @@ -10,8 +10,9 @@ import configuration import ui -from commands import application, moderator, notes, xp from core import auxiliary, cogs, moderation +from modules.moderation import moderator, notes +from modules.operation import application, xp if TYPE_CHECKING: import bot diff --git a/modules/operation/__init__.py b/modules/operation/__init__.py new file mode 100644 index 000000000..0daeb9f9e --- /dev/null +++ b/modules/operation/__init__.py @@ -0,0 +1,5 @@ +"""Modules designed for operations of the server""" + +from .application import * +from .relay import * +from .xp import * diff --git a/commands/application.py b/modules/operation/application.py similarity index 100% rename from commands/application.py rename to modules/operation/application.py diff --git a/commands/factoids.py b/modules/operation/factoids.py similarity index 99% rename from commands/factoids.py rename to modules/operation/factoids.py index 3ffa2bfb5..666130c85 100644 --- a/commands/factoids.py +++ b/modules/operation/factoids.py @@ -36,7 +36,7 @@ import ui from botlogging import LogContext, LogLevel from core import auxiliary, cogs, custom_errors -from functions import logger as function_logger +from modules.moderation import logger as function_logger if TYPE_CHECKING: import bot diff --git a/commands/forum.py b/modules/operation/forum.py similarity index 100% rename from commands/forum.py rename to modules/operation/forum.py diff --git a/functions/paste.py b/modules/operation/paste.py similarity index 99% rename from functions/paste.py rename to modules/operation/paste.py index 96583741b..80630102e 100644 --- a/functions/paste.py +++ b/modules/operation/paste.py @@ -11,7 +11,7 @@ import configuration from botlogging import LogContext, LogLevel from core import cogs -from functions import automod +from modules.moderation import automod if TYPE_CHECKING: import bot diff --git a/commands/relay.py b/modules/operation/relay.py similarity index 99% rename from commands/relay.py rename to modules/operation/relay.py index e211ab495..5639ca26f 100644 --- a/commands/relay.py +++ b/modules/operation/relay.py @@ -12,8 +12,8 @@ import configuration import ui from core import auxiliary, cogs -from functions import automod -from functions import logger as function_logger +from modules.moderation import automod +from modules.moderation import logger as function_logger if TYPE_CHECKING: import bot diff --git a/commands/voting.py b/modules/operation/voting.py similarity index 100% rename from commands/voting.py rename to modules/operation/voting.py diff --git a/commands/xp.py b/modules/operation/xp.py similarity index 100% rename from commands/xp.py rename to modules/operation/xp.py diff --git a/commands/chatgpt.py b/modules/utility/chatgpt.py similarity index 100% rename from commands/chatgpt.py rename to modules/utility/chatgpt.py diff --git a/commands/dictionary.py b/modules/utility/dictionary.py similarity index 100% rename from commands/dictionary.py rename to modules/utility/dictionary.py diff --git a/commands/dumpdbg.py b/modules/utility/dumpdbg.py similarity index 100% rename from commands/dumpdbg.py rename to modules/utility/dumpdbg.py diff --git a/commands/help.py b/modules/utility/help.py similarity index 100% rename from commands/help.py rename to modules/utility/help.py diff --git a/commands/htd.py b/modules/utility/htd.py similarity index 100% rename from commands/htd.py rename to modules/utility/htd.py diff --git a/commands/ipinfo.py b/modules/utility/ipinfo.py similarity index 100% rename from commands/ipinfo.py rename to modules/utility/ipinfo.py diff --git a/commands/iss.py b/modules/utility/iss.py similarity index 100% rename from commands/iss.py rename to modules/utility/iss.py diff --git a/commands/linter.py b/modules/utility/linter.py similarity index 100% rename from commands/linter.py rename to modules/utility/linter.py diff --git a/commands/news.py b/modules/utility/news.py similarity index 100% rename from commands/news.py rename to modules/utility/news.py diff --git a/commands/poll.py b/modules/utility/poll.py similarity index 100% rename from commands/poll.py rename to modules/utility/poll.py diff --git a/commands/search.py b/modules/utility/search.py similarity index 100% rename from commands/search.py rename to modules/utility/search.py diff --git a/commands/spotify.py b/modules/utility/spotify.py similarity index 100% rename from commands/spotify.py rename to modules/utility/spotify.py diff --git a/commands/translate.py b/modules/utility/translate.py similarity index 100% rename from commands/translate.py rename to modules/utility/translate.py diff --git a/commands/urban.py b/modules/utility/urban.py similarity index 100% rename from commands/urban.py rename to modules/utility/urban.py diff --git a/commands/weather.py b/modules/utility/weather.py similarity index 100% rename from commands/weather.py rename to modules/utility/weather.py diff --git a/commands/winerror.py b/modules/utility/winerror.py similarity index 100% rename from commands/winerror.py rename to modules/utility/winerror.py diff --git a/commands/wolfram.py b/modules/utility/wolfram.py similarity index 100% rename from commands/wolfram.py rename to modules/utility/wolfram.py diff --git a/commands/youtube.py b/modules/utility/youtube.py similarity index 100% rename from commands/youtube.py rename to modules/utility/youtube.py From 6ad34474544a1f666802d3c98e7a4e2d9496eca3 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 21:46:31 -0700 Subject: [PATCH 02/10] A proper solution for module identification on app commands --- README.md | 1 - bot.py | 24 ++---- modules/__init__.py | 2 +- modules/administration/backup.py | 3 - modules/administration/config.py | 13 +-- modules/administration/debug.py | 11 +-- modules/administration/extension.py | 12 +-- modules/fun/botinfo.py | 125 ---------------------------- modules/fun/hangman.py | 2 +- modules/fun/hello.py | 1 - modules/fun/xkcd.py | 8 +- modules/moderation/moderator.py | 17 ++-- modules/moderation/modlog.py | 5 +- modules/moderation/nicknamefix.py | 1 - modules/moderation/notes.py | 3 - modules/moderation/purge.py | 1 - modules/moderation/report.py | 2 +- modules/moderation/role.py | 3 - modules/moderation/slowmode.py | 1 - modules/moderation/whois.py | 1 - modules/operation/application.py | 11 +-- modules/operation/factoids.py | 2 - modules/operation/forum.py | 5 +- modules/operation/voting.py | 3 - modules/operation/xp.py | 1 - modules/utility/dictionary.py | 1 - modules/utility/help.py | 2 +- modules/utility/news.py | 1 - modules/utility/search.py | 2 - modules/utility/winerror.py | 1 - modules/utility/youtube.py | 1 - 31 files changed, 35 insertions(+), 231 deletions(-) delete mode 100644 modules/fun/botinfo.py diff --git a/README.md b/README.md index e1cb2321b..552d9fca2 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ class Greeter(cogs.BaseCog): @app_commands.command( name="hello", description="Says hello to the bot (because they are doing such a great job!)", - extras={"module": "hello"}, ) async def hello_app_command(self: Self, interaction: discord.Interaction) -> None: await interaction.response.send_message("🇭 🇪 🇾") diff --git a/bot.py b/bot.py index 3c64b8af9..bedc0bd0f 100644 --- a/bot.py +++ b/bot.py @@ -511,7 +511,6 @@ async def get_potential_extensions(self: Self) -> list[str]: extensions_list.append(dotted) - print(extensions_list) return extensions_list async def load_extensions(self: Self, graceful: bool = True) -> None: @@ -768,21 +767,14 @@ async def interaction_check(self: Self, interaction: discord.Interaction) -> boo console_only=True, ) # Check 1 - Ensure extension is enabled - try: - extension_name = interaction.command.extras["module"] - except KeyError: - # Skip extension enabled check if no extras module has been defined - self.logger.console.warning( - "No module has been defined, skipping extension enabled check" - ) - extension_name = None - - if extension_name: - # If the extension is disabled, raise an error to show it and block execution - if not self.command_run_extension_disabled_check( - interaction.guild, extension_name - ): - raise custom_errors.AppCommandExtensionDisabled + # removes "modules." + extension_name = interaction.command.callback.__module__[8:] + print(extension_name) + # If the extension is disabled, raise an error to show it and block execution + if not self.command_run_extension_disabled_check( + interaction.guild, extension_name + ): + raise custom_errors.AppCommandExtensionDisabled # Check 2 - Approve if invoker is bot admin result = await self.command_run_admin_check(interaction.user) diff --git a/modules/__init__.py b/modules/__init__.py index d995bff49..9797f2c6c 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -1,7 +1,7 @@ """All the customizable modules for the bot""" from .administration import * +from .fun import * from .moderation import * from .operation import * -from .fun import * from .utility import * diff --git a/modules/administration/backup.py b/modules/administration/backup.py index 7951b00f1..3e40d36be 100644 --- a/modules/administration/backup.py +++ b/modules/administration/backup.py @@ -33,9 +33,6 @@ class BackupCommand(cogs.BaseCog): @app_commands.command( name="backup", description="Backs up data into a zip file", - extras={ - "module": "backup", - }, ) async def backup( self: Self, interaction: discord.Interaction, config_file: bool = False diff --git a/modules/administration/config.py b/modules/administration/config.py index bdc3a2f93..9961410b4 100644 --- a/modules/administration/config.py +++ b/modules/administration/config.py @@ -38,13 +38,12 @@ class ConfigControl(cogs.BaseCog): """ config_commands: app_commands.Group = app_commands.Group( - name="config", description="...", extras={"module": "config"} + name="config", description="..." ) config_extension_commands: app_commands.Group = app_commands.Group( name="extension", description="...", - extras={"module": "config"}, parent=config_commands, ) @@ -53,7 +52,7 @@ class ConfigControl(cogs.BaseCog): @config_extension_commands.command( name="enable", description="Enables an extension for the guild by name", - extras={"module": "config", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def enable_extension( self: Self, interaction: discord.Interaction, extension_name: str @@ -100,7 +99,7 @@ async def enable_extension( @config_extension_commands.command( name="disable", description="Disables an extension for the guild by name", - extras={"module": "config", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def disable_extension( self: Self, interaction: discord.Interaction, extension_name: str @@ -146,7 +145,6 @@ async def disable_extension( @config_extension_commands.command( name="list-disabled", description="Lists all disabled extensions in the current server", - extras={"module": "config"}, ) async def list_disabled(self: Self, interaction: discord.Interaction) -> None: """This will read the current guild config and list all the @@ -176,7 +174,6 @@ async def list_disabled(self: Self, interaction: discord.Interaction) -> None: @config_extension_commands.command( name="enable-all", description="Enables all loaded but disabled extensions in the guild", - extras={"module": "config"}, ) async def enable_everything(self: Self, interaction: discord.Interaction) -> None: """This will get all the disabled extensions and enable them for the current @@ -214,7 +211,6 @@ async def enable_everything(self: Self, interaction: discord.Interaction) -> Non @config_commands.command( name="json", description="This gets the guild config json file and sends it as a response", - extras={"module": "config"}, ) async def config_json(self: Self, interaction: discord.Interaction) -> None: """This pulls the guild json config and send it to the caller @@ -240,7 +236,7 @@ async def config_json(self: Self, interaction: discord.Interaction) -> None: @config_commands.command( name="patch", description="Edits guild config by uploading JSON", - extras={"module": "config", "usage": "[uploaded-json]"}, + extras={"usage": "[uploaded-json]"}, ) async def patch_config( self: Self, interaction: discord.Interaction, config_json: discord.Attachment @@ -272,7 +268,6 @@ async def patch_config( @config_commands.command( name="reset", description="Resets config to default for the current guild", - extras={"module": "config"}, ) async def reset_config(self: Self, interaction: discord.Interaction) -> None: """A function to reset the current guild config to stock diff --git a/modules/administration/debug.py b/modules/administration/debug.py index 184666919..b0134681e 100644 --- a/modules/administration/debug.py +++ b/modules/administration/debug.py @@ -35,16 +35,13 @@ class Debugger(cogs.BaseCog): """ debug_group: app_commands.Group = app_commands.Group( - name="debug", description="...", extras={"module": "debug"} + name="debug", description="..." ) @app_commands.check(auxiliary.bot_admin_check_interaction) @debug_group.command( name="message", description="Searches and displays all the message properties", - extras={ - "module": "debug", - }, ) async def debug_message( self: Self, @@ -70,9 +67,6 @@ async def debug_message( @debug_group.command( name="member", description="Searches and displays all the member properties", - extras={ - "module": "debug", - }, ) async def debug_member( self: Self, interaction: discord.Interaction, member: discord.Member @@ -92,9 +86,6 @@ async def debug_member( @debug_group.command( name="channel", description="Searches and displays all the channel properties", - extras={ - "module": "debug", - }, ) async def debug_channel( self: Self, interaction: discord.Interaction, channel: discord.abc.GuildChannel diff --git a/modules/administration/extension.py b/modules/administration/extension.py index ac621ac76..10d6f4042 100644 --- a/modules/administration/extension.py +++ b/modules/administration/extension.py @@ -43,14 +43,15 @@ class ExtensionControl(cogs.BaseCog): """ extension_commands: app_commands.Group = app_commands.Group( - name="extension", description="...", extras={"module": "extension"} + name="extension", + description="...", ) @app_commands.check(auxiliary.bot_admin_check_interaction) @extension_commands.command( name="status", description="Gets the status of an extension by name", - extras={"module": "extension", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def extension_status( self: Self, interaction: discord.Interaction, extension_name: str @@ -94,7 +95,7 @@ async def extension_status( @extension_commands.command( name="load", description="Loads an extension by name", - extras={"module": "extension", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def load_extension( self: Self, interaction: discord.Interaction, extension_name: str @@ -126,7 +127,7 @@ async def load_extension( @extension_commands.command( name="unload", description="Unloads an extension by name", - extras={"module": "extension", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def unload_extension( self: Self, interaction: discord.Interaction, extension_name: str @@ -157,7 +158,7 @@ async def unload_extension( @extension_commands.command( name="reload", description="Reloads an extension by name", - extras={"module": "extension", "usage": "[extension-name]"}, + extras={"usage": "[extension-name]"}, ) async def reload_extension( self: Self, interaction: discord.Interaction, extension_name: str @@ -195,7 +196,6 @@ async def reload_extension( name="register", description="Uploads an extension from Discord to be saved on the bot", extras={ - "module": "extension", "usage": "[extension-name] [python-file-upload]", }, ) diff --git a/modules/fun/botinfo.py b/modules/fun/botinfo.py deleted file mode 100644 index 0e485b6a7..000000000 --- a/modules/fun/botinfo.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Commands which allow information about the bot to be shown -The cog in the file is named: - BotInfo - -This file contains 1 command: - .bot -""" - -from __future__ import annotations - -import re -from typing import TYPE_CHECKING, Self - -import discord -import git -from discord.ext import commands - -from core import auxiliary, cogs - -if TYPE_CHECKING: - import bot - - -async def setup(bot: bot.TechSupportBot) -> None: - """Loading the BotInfo plugin into the bot - - Args: - bot (bot.TechSupportBot): The bot object to register the cogs to - """ - await bot.add_cog(BotInfo(bot=bot)) - - -class BotInfo(cogs.BaseCog): - """ - The class that holds the bot command - """ - - @commands.check(auxiliary.bot_admin_check_context) - @commands.command(name="bot", description="Provides bot info") - async def get_bot_data(self: Self, ctx: commands.Context) -> None: - """Gets various data about the bot. - - This is a command and should be accessed via Discord. - - Args: - ctx (commands.Context): the context object for the calling message - """ - embed = discord.Embed(title=self.bot.user.name, color=discord.Color.blurple()) - - embed.add_field( - name="Started", - value=( - f"" - if self.bot.startup_time - else "Unknown" - ), - inline=True, - ) - embed.add_field( - name="Latency", - value=f"{self.bot.latency*1000} ms" if self.bot.latency else "None", - inline=True, - ) - embed.add_field( - name="Description", value=self.bot.description or "None", inline=True - ) - embed.add_field( - name="Servers", - value=", ".join(f"{guild.name} ({guild.id})" for guild in self.bot.guilds), - inline=True, - ) - irc_config = self.bot.file_config.api.irc - if not irc_config.enable_irc: - embed.add_field( - name="IRC", - value="IRC is not enabled", - inline=True, - ) - else: - irc_status = self.bot.irc.get_irc_status() - embed.add_field( - name="IRC", - value=f"IRC Status: `{irc_status['status']}`\n" - + f"IRC Bot Name: `{irc_status['name']}`\n" - + f"Channels: `{irc_status['channels']}`", - inline=True, - ) - try: - repo = git.Repo(search_parent_directories=True) - commit = repo.head.commit - commit_hash = commit.hexsha[:7] - commit_message = commit.message.splitlines()[0].strip() - branch_name = repo.active_branch.name - match = re.search( - r"github.com[:/](.*?)/(.*?)(?:.git)?$", repo.remotes.origin.url - ) - if match: - repo_owner = match.group(1) - repo_name = match.group(2) - else: - repo_owner = "" - repo_name = "" - - has_differences = repo.is_dirty() - - embed.add_field( - name="Version Info", - value=( - f"Upstream: `{repo_owner}/{repo_name}/{branch_name}`\n" - f"Commit: `{commit_hash} - {commit_message}`\n" - f"Local changes made: `{has_differences}`" - ), - inline=False, - ) - except Exception as exc: - embed.add_field( - name="Version Info", - value=f"There was an error getting version info: {exc}", - inline=False, - ) - - embed.set_thumbnail(url=self.bot.user.display_avatar.url) - - await ctx.send(embed=embed) diff --git a/modules/fun/hangman.py b/modules/fun/hangman.py index 3b03b83e2..3e5c5d2c0 100644 --- a/modules/fun/hangman.py +++ b/modules/fun/hangman.py @@ -334,7 +334,7 @@ async def hangman(self: Self, ctx: commands.Context) -> None: @hangman_app_group.command( name="start", description="Start a Hangman game in the current channel.", - extras={"module": "hangman", "suppress_logs": True}, + extras={"suppress_logs": True}, ) async def start_game( self: Self, interaction: discord.Interaction, word: str diff --git a/modules/fun/hello.py b/modules/fun/hello.py index 788ddd2df..cea88eb47 100644 --- a/modules/fun/hello.py +++ b/modules/fun/hello.py @@ -33,7 +33,6 @@ class Greeter(cogs.BaseCog): @app_commands.command( name="hello", description="Says hello to the bot (because they are doing such a great job!)", - extras={"module": "hello"}, ) async def hello_app_command(self: Self, interaction: discord.Interaction) -> None: """A simple command to have the bot say HEY to the invoker diff --git a/modules/fun/xkcd.py b/modules/fun/xkcd.py index 0ef1e2d2e..6a1570170 100644 --- a/modules/fun/xkcd.py +++ b/modules/fun/xkcd.py @@ -44,9 +44,6 @@ class XKCD(cogs.BaseCog): @xkcd.command( name="latest", description="Gets the latest XKCD comic.", - extras={ - "module": "xkcd", - }, ) async def xkcd_latest(self: Self, interaction: discord.Interaction) -> None: """This calls the XKCD API and gets the latest comic @@ -74,9 +71,6 @@ async def xkcd_latest(self: Self, interaction: discord.Interaction) -> None: @xkcd.command( name="random", description="Gets a random XKCD comic.", - extras={ - "module": "xkcd", - }, ) async def xkcd_random(self: Self, interaction: discord.Interaction) -> None: """This calls the XKCD API and gets a random comic @@ -122,7 +116,7 @@ async def xkcd_random(self: Self, interaction: discord.Interaction) -> None: @xkcd.command( name="specific", description="Gets an XKCD comic by number.", - extras={"module": "xkcd", "usage": "[comic_number]"}, + extras={"usage": "[comic_number]"}, ) async def xkcd_specific( self: Self, interaction: discord.Interaction, comic_number: int diff --git a/modules/moderation/moderator.py b/modules/moderation/moderator.py index 1da3d07a9..d70c62425 100644 --- a/modules/moderation/moderator.py +++ b/modules/moderation/moderator.py @@ -37,7 +37,7 @@ class ProtectCommands(cogs.BaseCog): """ warnings_group: app_commands.Group = app_commands.Group( - name="warning", description="...", extras={"module": "moderator"} + name="warning", description="..." ) # Commands @@ -47,7 +47,6 @@ class ProtectCommands(cogs.BaseCog): @app_commands.command( name="ban", description="Bans a user from the guild", - extras={"module": "moderator"}, ) async def handle_ban_user( self: Self, @@ -129,7 +128,6 @@ async def handle_ban_user( @app_commands.command( name="unban", description="Unbans a user from the guild", - extras={"module": "moderator"}, ) async def handle_unban_user( self: Self, interaction: discord.Interaction, target: discord.User, reason: str @@ -194,7 +192,6 @@ async def handle_unban_user( @app_commands.command( name="kick", description="Kicks a user from the guild", - extras={"module": "moderator"}, ) async def handle_kick_user( self: Self, @@ -249,7 +246,8 @@ async def handle_kick_user( @app_commands.checks.has_permissions(moderate_members=True) @app_commands.checks.bot_has_permissions(moderate_members=True) @app_commands.command( - name="mute", description="Times out a user", extras={"module": "moderator"} + name="mute", + description="Times out a user", ) async def handle_mute_user( self: Self, @@ -363,7 +361,6 @@ async def handle_mute_user( @app_commands.command( name="unmute", description="Removes timeout from a user", - extras={"module": "moderator"}, ) async def handle_unmute_user( self: Self, @@ -424,7 +421,8 @@ async def handle_unmute_user( @app_commands.checks.has_permissions(kick_members=True) @app_commands.checks.bot_has_permissions(kick_members=True) @app_commands.command( - name="warn", description="Warns a user", extras={"module": "moderator"} + name="warn", + description="Warns a user", ) async def handle_warn_user( self: Self, @@ -564,7 +562,8 @@ async def handle_warn_user( @app_commands.checks.has_permissions(kick_members=True) @app_commands.checks.bot_has_permissions(kick_members=True) @app_commands.command( - name="unwarn", description="Unwarns a user", extras={"module": "moderator"} + name="unwarn", + description="Unwarns a user", ) async def handle_unwarn_user( self: Self, @@ -667,7 +666,6 @@ async def unwarn_warning_autocomplete( @warnings_group.command( name="clear", description="clears all warnings from a user", - extras={"module": "moderator"}, ) async def handle_warning_clear( self: Self, @@ -727,7 +725,6 @@ async def handle_warning_clear( @warnings_group.command( name="all", description="Shows all warnings to the invoker", - extras={"module": "moderator"}, ) async def handle_warning_all( self: Self, diff --git a/modules/moderation/modlog.py b/modules/moderation/modlog.py index 8e71f5d02..38dff34fd 100644 --- a/modules/moderation/modlog.py +++ b/modules/moderation/modlog.py @@ -36,13 +36,12 @@ class BanLogger(cogs.BaseCog): """ modlog_group: app_commands.Group = app_commands.Group( - name="modlog", description="...", extras={"module": "modlog"} + name="modlog", description="..." ) @modlog_group.command( name="highscores", description="Shows the top 10 moderators based on ban count", - extras={"module": "modlog"}, ) async def high_score_command(self: Self, interaction: discord.Interaction) -> None: """Gets the top 10 moderators based on banned user count @@ -82,7 +81,6 @@ async def high_score_command(self: Self, interaction: discord.Interaction) -> No @modlog_group.command( name="lookup-user", description="Looks up the 10 most recent bans for a given user", - extras={"module": "modlog"}, ) async def lookup_user_command( self: Self, interaction: discord.Interaction, user: discord.User @@ -126,7 +124,6 @@ async def lookup_user_command( @modlog_group.command( name="lookup-moderator", description="Looks up the 10 most recent bans by a given moderator", - extras={"module": "modlog"}, ) async def lookup_moderator_command( self: Self, interaction: discord.Interaction, moderator: discord.Member diff --git a/modules/moderation/nicknamefix.py b/modules/moderation/nicknamefix.py index a723e174a..f75cdebca 100644 --- a/modules/moderation/nicknamefix.py +++ b/modules/moderation/nicknamefix.py @@ -33,7 +33,6 @@ class NicknameFixer(cogs.BaseCog): description="Auto adjusts a nickname of the given member", extras={ "usage": "member", - "module": "nicknamefix", }, ) async def fixnickname( diff --git a/modules/moderation/notes.py b/modules/moderation/notes.py index 2457c35fb..012cc39a2 100644 --- a/modules/moderation/notes.py +++ b/modules/moderation/notes.py @@ -113,7 +113,6 @@ class Notes(cogs.BaseCog): extras={ "brief": "Sets a note for a user", "usage": "@user [note]", - "module": "notes", }, ) async def set_note( @@ -186,7 +185,6 @@ async def set_note( extras={ "brief": "Clears all notes for a user", "usage": "@user", - "module": "notes", }, ) async def clear_notes( @@ -253,7 +251,6 @@ async def clear_notes( extras={ "brief": "Gets all notes for a user", "usage": "@user", - "module": "notes", }, ) async def all_notes( diff --git a/modules/moderation/purge.py b/modules/moderation/purge.py index d51eedb01..bcb7aa9ac 100644 --- a/modules/moderation/purge.py +++ b/modules/moderation/purge.py @@ -32,7 +32,6 @@ class Purger(cogs.BaseCog): @app_commands.command( name="purge", description="Purge by pure duration of messages", - extras={"module": "purge"}, ) async def purge_command( self: Self, diff --git a/modules/moderation/report.py b/modules/moderation/report.py index 8e4b16487..02485bab0 100644 --- a/modules/moderation/report.py +++ b/modules/moderation/report.py @@ -31,7 +31,7 @@ class Report(cogs.BaseCog): @app_commands.command( name="report", description="Reports something to the moderators", - extras={"module": "report", "suppress_logs": True}, + extras={"suppress_logs": True}, ) async def report_command( self: Self, interaction: discord.Interaction, reason: str diff --git a/modules/moderation/role.py b/modules/moderation/role.py index de91f98e3..a97606b93 100644 --- a/modules/moderation/role.py +++ b/modules/moderation/role.py @@ -40,7 +40,6 @@ def __init__(self: Self, bot: bot.TechSupportBot) -> None: self.ctx_menu = app_commands.ContextMenu( name="Manage roles", callback=self.assign_role_command, - extras={"module": "role"}, ) self.bot.tree.add_command(self.ctx_menu) @@ -53,7 +52,6 @@ async def preconfig(self: Self) -> None: @role_group.command( name="self", description="Assign or remove roles from yourself", - extras={"module": "role"}, ) async def self_role(self: Self, interaction: discord.Interaction) -> None: """The base of the self role command @@ -101,7 +99,6 @@ async def self_role(self: Self, interaction: discord.Interaction) -> None: @role_group.command( name="manage", description="Modify roles on a given user", - extras={"module": "role"}, ) async def assign_role( self: Self, interaction: discord.Interaction, member: discord.Member diff --git a/modules/moderation/slowmode.py b/modules/moderation/slowmode.py index 90294a1b6..97590f2e5 100644 --- a/modules/moderation/slowmode.py +++ b/modules/moderation/slowmode.py @@ -33,7 +33,6 @@ class SlowmodeManager(cogs.BaseCog): extras={ "brief": "Changes time for slowmode", "usage": "seconds, [optional] channel", - "module": "slowmode", }, ) async def slowmode( diff --git a/modules/moderation/whois.py b/modules/moderation/whois.py index cc403ae3f..147cd829d 100644 --- a/modules/moderation/whois.py +++ b/modules/moderation/whois.py @@ -35,7 +35,6 @@ class Whois(cogs.BaseCog): description="Gets Discord user information", extras={ "usage": "@user", - "module": "whois", "ephemeral_error": True, }, ) diff --git a/modules/operation/application.py b/modules/operation/application.py index 04b8935d6..749532075 100644 --- a/modules/operation/application.py +++ b/modules/operation/application.py @@ -131,7 +131,8 @@ class ApplicationManager(cogs.LoopCog): """ application_group: app_commands.Group = app_commands.Group( - name="application", description="...", extras={"module": "application"} + name="application", + description="...", ) # Slash Commands @@ -139,7 +140,6 @@ class ApplicationManager(cogs.LoopCog): @app_commands.command( name="apply", description="Use this to show you are interested in being staff on this server", - extras={"module": "application"}, ) async def apply(self: Self, interaction: discord.Interaction) -> None: """The slash command entrance for /apply @@ -154,7 +154,6 @@ async def apply(self: Self, interaction: discord.Interaction) -> None: @application_group.command( name="ban", description="Ban someone from making new applications", - extras={"module": "application"}, ) async def ban_user( self: Self, interaction: discord.Interaction, member: discord.Member @@ -186,7 +185,6 @@ async def ban_user( @application_group.command( name="unban", description="Unban someone and allow them to apply", - extras={"module": "application"}, ) async def unban_user( self: Self, interaction: discord.Interaction, member: discord.Member @@ -216,7 +214,6 @@ async def unban_user( @application_group.command( name="get", description="Gets the application of the given user", - extras={"module": "application"}, ) async def get_application( self: Self, @@ -241,7 +238,6 @@ async def get_application( @application_group.command( name="approve", description="Approves the application of the given user", - extras={"module": "application"}, ) async def approve_application( self: Self, @@ -290,7 +286,6 @@ async def approve_application( @application_group.command( name="deny", description="Denies the application of the given user", - extras={"module": "application"}, ) async def deny_application( self: Self, @@ -326,7 +321,6 @@ async def deny_application( @application_group.command( name="delete", description="Deletes all applications from a user", - extras={"module": "application"}, ) async def delete_applications( self: Self, @@ -357,7 +351,6 @@ async def delete_applications( @application_group.command( name="list", description="Lists all applications by a given status", - extras={"module": "application"}, ) async def list_applications( self: Self, diff --git a/modules/operation/factoids.py b/modules/operation/factoids.py index 666130c85..430303824 100644 --- a/modules/operation/factoids.py +++ b/modules/operation/factoids.py @@ -944,7 +944,6 @@ async def send_to_logger( description="Calls a factoid from the database and sends it publicy in the channel.", extras={ "usage": "[factoid_name]", - "module": "factoids", }, ) async def factoid_call_command( @@ -1737,7 +1736,6 @@ async def info( extras={ "brief": "Sets a note for a user", "usage": "[file] [property] [true_all] [ignore_hidden]", - "module": "factoids", }, ) async def app_command_all( diff --git a/modules/operation/forum.py b/modules/operation/forum.py index 773ce3196..4f6da7fba 100644 --- a/modules/operation/forum.py +++ b/modules/operation/forum.py @@ -83,7 +83,7 @@ class ForumChannel(cogs.LoopCog): """ forum_group: app_commands.Group = app_commands.Group( - name="forum", description="...", extras={"module": "forum"} + name="forum", description="..." ) async def preconfig(self: Self) -> None: @@ -93,7 +93,6 @@ async def preconfig(self: Self) -> None: @forum_group.command( name="mark", description="Mark a support forum thread", - extras={"module": "forum"}, ) async def mark_thread_command( self: Self, interaction: discord.Interaction, status: str, reason: str = "" @@ -224,7 +223,6 @@ async def status_autocomplete( @forum_group.command( name="unsolved", description="Gets a collection of unsolved issues", - extras={"module": "forum"}, ) async def showUnsolved(self: Self, interaction: discord.Interaction) -> None: """A command to mark the thread as abandoned @@ -276,7 +274,6 @@ async def showUnsolved(self: Self, interaction: discord.Interaction) -> None: @forum_group.command( name="reopen", description="Reopens a support thread", - extras={"module": "forum"}, ) async def reopen_thread(self: Self, interaction: discord.Interaction) -> None: """This command reopens a closed and locked thread diff --git a/modules/operation/voting.py b/modules/operation/voting.py index d43e92b4b..af106e5f3 100644 --- a/modules/operation/voting.py +++ b/modules/operation/voting.py @@ -67,9 +67,6 @@ class Voting(cogs.LoopCog): @app_commands.command( name="vote", description="Starts a yes/no vote that runs for 72 hours", - extras={ - "module": "voting", - }, ) async def votingbutton( self: Self, diff --git a/modules/operation/xp.py b/modules/operation/xp.py index 0f8e2ee0a..4ebcaa462 100644 --- a/modules/operation/xp.py +++ b/modules/operation/xp.py @@ -50,7 +50,6 @@ async def preconfig(self: Self) -> None: description="Shows the top 10 XP users in the server", extras={ "usage": "", - "module": "xp", }, ) async def top_xp_command(self: Self, interaction: discord.Interaction) -> None: diff --git a/modules/utility/dictionary.py b/modules/utility/dictionary.py index f583c8fc4..5f85f1c4d 100644 --- a/modules/utility/dictionary.py +++ b/modules/utility/dictionary.py @@ -49,7 +49,6 @@ class Dictionary(cogs.BaseCog): @app_commands.command( name="dictionary", description="Looks up a word in the dictionary", - extras={"module": "dictionary"}, ) async def dictionary_lookup( self: Self, interaction: discord.Interaction, word: str diff --git a/modules/utility/help.py b/modules/utility/help.py index 9e209d7e1..e48a964aa 100644 --- a/modules/utility/help.py +++ b/modules/utility/help.py @@ -124,7 +124,7 @@ async def help_command( continue # Check if extension is enabled - extension_name = command.extras["module"] + extension_name = command.callback.__module__[8:] if extension_name not in configuration.get_config_entry( ctx.guild.id, "core_enabled_extensions" ): diff --git a/modules/utility/news.py b/modules/utility/news.py index cb6804f3d..30ee5b968 100644 --- a/modules/utility/news.py +++ b/modules/utility/news.py @@ -193,7 +193,6 @@ async def wait(self: Self, guild: discord.Guild) -> None: @app_commands.command( name="news", description="Gets a random news headline", - extras={"module": "news"}, ) async def news_command( self: Self, interaction: discord.Interaction, category: str = "" diff --git a/modules/utility/search.py b/modules/utility/search.py index bb9033abf..74fe23669 100644 --- a/modules/utility/search.py +++ b/modules/utility/search.py @@ -82,7 +82,6 @@ async def make_request(self: Self, query: str) -> munch.Munch: description="Returns the top Web search result", extras={ "usage": "[query]", - "module": "search", }, ) async def websearch_text( @@ -122,7 +121,6 @@ async def websearch_text( description="Returns the top Web search image result", extras={ "usage": "[query]", - "module": "search", }, ) async def websearch_image( diff --git a/modules/utility/winerror.py b/modules/utility/winerror.py index 6dd8354e0..01fecea28 100644 --- a/modules/utility/winerror.py +++ b/modules/utility/winerror.py @@ -69,7 +69,6 @@ async def preconfig(self: Self) -> None: @app_commands.command( name="winerror", description="Searches the windows error database based on input", - extras={"module": "winerror"}, ) async def winerror( self: Self, interaction: discord.Interaction, search_term: str diff --git a/modules/utility/youtube.py b/modules/utility/youtube.py index eb2d977d7..c4c7b61f2 100644 --- a/modules/utility/youtube.py +++ b/modules/utility/youtube.py @@ -71,7 +71,6 @@ async def get_items( description="Returns the top YouTube search result", extras={ "usage": "[query]", - "module": "youtube", }, ) async def youtube(self: Self, interaction: discord.Interaction, query: str) -> None: From 743ced6c56d7fcc73fe59635239282efad8733c2 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 21:47:35 -0700 Subject: [PATCH 03/10] Remove old folders --- commands/__init__.py | 18 ------------------ functions/__init__.py | 5 ----- 2 files changed, 23 deletions(-) delete mode 100644 commands/__init__.py delete mode 100644 functions/__init__.py diff --git a/commands/__init__.py b/commands/__init__.py deleted file mode 100644 index c7f399496..000000000 --- a/commands/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -This is the folder for all cogs that contain commands -Both app and prefix commands are in this module -""" - -from .burn import * -from .conch import * -from .correct import * -from .emoji import * -from .hello import * -from .help import * -from .htd import * -from .hug import * -from .lenny import * -from .linter import * -from .mock import * -from .roll import * -from .wyr import * diff --git a/functions/__init__.py b/functions/__init__.py deleted file mode 100644 index 081de5b74..000000000 --- a/functions/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Functions are commandless cogs""" - -from .automod import * -from .logger import * -from .nickname import * From 4d9da218f0439041ad5aa11767005132fde288f6 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:35:24 -0700 Subject: [PATCH 04/10] Change how cogs get extension_name, clear FUNCTIONS_DIR --- bot.py | 7 ------ core/cogs.py | 22 ++++++++++++++----- modules/administration/extension.py | 11 ++-------- modules/fun/autoreact.py | 2 +- modules/fun/duck.py | 2 +- modules/fun/kanye.py | 2 +- modules/moderation/automod.py | 2 +- modules/moderation/gate.py | 2 +- modules/moderation/honeypot.py | 2 +- modules/moderation/logger.py | 2 +- modules/moderation/moderator.py | 2 +- modules/moderation/modlog.py | 2 +- modules/moderation/nickname.py | 2 +- modules/moderation/notes.py | 2 +- modules/moderation/purge.py | 2 +- modules/moderation/report.py | 2 +- modules/moderation/whois.py | 2 +- modules/operation/application.py | 4 ++-- modules/operation/factoids.py | 1 - modules/operation/forum.py | 2 +- modules/operation/paste.py | 2 +- modules/operation/relay.py | 2 +- modules/operation/voting.py | 2 +- modules/operation/xp.py | 2 +- modules/utility/news.py | 7 +----- modules/utility/winerror.py | 2 +- tests/commands_tests/test_extensions_htd.py | 1 - tests/commands_tests/test_extensions_hug.py | 2 +- tests/commands_tests/test_extensions_lenny.py | 2 +- .../commands_tests/test_extensions_linter.py | 2 +- tests/commands_tests/test_extensions_mock.py | 2 +- tests/commands_tests/test_extensions_roll.py | 2 +- tests/commands_tests/test_extensions_wyr.py | 2 +- tests/config_for_tests.py | 3 +-- 34 files changed, 49 insertions(+), 59 deletions(-) diff --git a/bot.py b/bot.py index bedc0bd0f..d86aa18aa 100644 --- a/bot.py +++ b/bot.py @@ -44,8 +44,6 @@ class TechSupportBot(commands.Bot): CONFIG_PATH (str): The hard coded path to the yaml config file EXTENSIONS_DIR_NAME (str): The hardcoded folder for commands EXTENSIONS_DIR (str): The list of all files in the EXTENSIONS_DIR_NAME folder - FUNCTIONS_DIR_NAME (str):The hardcoded folder for functions - FUNCTIONS_DIR (str):The list of all files in the FUNCTIONS_DIR_NAME folder """ CONFIG_PATH: str = os.environ.get("CONFIG_YML", "./config.yml") @@ -53,10 +51,6 @@ class TechSupportBot(commands.Bot): EXTENSIONS_DIR: str = ( f"{os.path.join(os.path.dirname(__file__))}/{EXTENSIONS_DIR_NAME}" ) - FUNCTIONS_DIR_NAME: str = "functions" - FUNCTIONS_DIR: str = ( - f"{os.path.join(os.path.dirname(__file__))}/{FUNCTIONS_DIR_NAME}" - ) def __init__( self: Self, intents: discord.Intents, allowed_mentions: discord.AllowedMentions @@ -769,7 +763,6 @@ async def interaction_check(self: Self, interaction: discord.Interaction) -> boo # Check 1 - Ensure extension is enabled # removes "modules." extension_name = interaction.command.callback.__module__[8:] - print(extension_name) # If the extension is disabled, raise an error to show it and block execution if not self.command_run_extension_disabled_check( interaction.guild, extension_name diff --git a/core/cogs.py b/core/cogs.py index b27b0a366..b3d62b0bf 100644 --- a/core/cogs.py +++ b/core/cogs.py @@ -26,8 +26,6 @@ class BaseCog(commands.Cog): Args: bot (bot.TechSupportBot): the bot object no_guild (bool): True if the extension should run globally - extension_name(str): The name of the extension - if it needs to be different than the file name """ COG_TYPE: str = "Base" @@ -37,11 +35,10 @@ def __init__( self: Self, bot: bot.TechSupportBot, no_guild: bool = False, - extension_name: str = None, ) -> None: self.bot = bot self.no_guild = no_guild - self.extension_name = extension_name + self.extension_name = self.get_extension_name() asyncio.create_task(self._preconfig()) @@ -91,6 +88,21 @@ def extension_enabled(self: Self, guild: discord.Guild) -> bool: return True return False + def get_extension_name(self: Self) -> str | None: + """Gets the full extension name for this cog. + + Returns: + str | None: The dotted extension name without the root + extensions directory, or None if the cog is not + contained within the extensions directory. + """ + module = self.__class__.__module__ + + if not module.startswith(f"{self.bot.EXTENSIONS_DIR_NAME}."): + return None + + return ".".join(module.split(".")[1:]).replace(".py", "") + class MatchCog(BaseCog): """ @@ -338,7 +350,7 @@ async def _loop_execute( if not self.ON_START: await self.wait(guild) - for folder_dir in [self.bot.EXTENSIONS_DIR_NAME, self.bot.FUNCTIONS_DIR_NAME]: + for folder_dir in [self.bot.EXTENSIONS_DIR_NAME]: while self.bot.extensions.get(f"{folder_dir}.{self.extension_name}"): if guild and guild not in self.bot.guilds: break diff --git a/modules/administration/extension.py b/modules/administration/extension.py index 10d6f4042..2752488cc 100644 --- a/modules/administration/extension.py +++ b/modules/administration/extension.py @@ -71,20 +71,13 @@ async def extension_status( ) else "unloaded" ) - functions_status = ( - "loaded" - if self.bot.extensions.get( - f"{self.bot.FUNCTIONS_DIR_NAME}.{extension_name}" - ) - else "unloaded" - ) embed = discord.Embed( title=f"Extension status for `{extension_name}`", - description=f"Extension: {extensions_status}\nFunction: {functions_status}", + description=f"{extensions_status}", ) - if functions_status == "loaded" or extensions_status == "loaded": + if extensions_status == "loaded": embed.color = discord.Color.green() else: embed.color = discord.Color.gold() diff --git a/modules/fun/autoreact.py b/modules/fun/autoreact.py index 31847f007..11048e5d8 100644 --- a/modules/fun/autoreact.py +++ b/modules/fun/autoreact.py @@ -19,7 +19,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(AutoReact(bot=bot, extension_name="autoreact")) + await bot.add_cog(AutoReact(bot=bot)) class AutoReact(cogs.MatchCog): diff --git a/modules/fun/duck.py b/modules/fun/duck.py index 31be40fdc..765a11ee2 100644 --- a/modules/fun/duck.py +++ b/modules/fun/duck.py @@ -28,7 +28,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(DuckHunt(bot=bot, extension_name="duck")) + await bot.add_cog(DuckHunt(bot=bot)) class DuckHunt(cogs.LoopCog): diff --git a/modules/fun/kanye.py b/modules/fun/kanye.py index 61753fb86..e4fd41830 100644 --- a/modules/fun/kanye.py +++ b/modules/fun/kanye.py @@ -23,7 +23,7 @@ async def setup(bot: bot.TechSupportBot) -> None: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(KanyeQuotes(bot=bot, extension_name="kanye")) + await bot.add_cog(KanyeQuotes(bot=bot)) class KanyeQuotes(cogs.LoopCog): diff --git a/modules/moderation/automod.py b/modules/moderation/automod.py index aec28b7b1..8875bf7e4 100644 --- a/modules/moderation/automod.py +++ b/modules/moderation/automod.py @@ -25,7 +25,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(AutoMod(bot=bot, extension_name="automod")) + await bot.add_cog(AutoMod(bot=bot)) @dataclass diff --git a/modules/moderation/gate.py b/modules/moderation/gate.py index fc2abc94d..fa5ce4eac 100644 --- a/modules/moderation/gate.py +++ b/modules/moderation/gate.py @@ -21,7 +21,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(ServerGate(bot=bot, extension_name="gate")) + await bot.add_cog(ServerGate(bot=bot)) class ServerGate(cogs.MatchCog): diff --git a/modules/moderation/honeypot.py b/modules/moderation/honeypot.py index 88d88faa0..01cd2bd9f 100644 --- a/modules/moderation/honeypot.py +++ b/modules/moderation/honeypot.py @@ -21,7 +21,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(HoneyPot(bot=bot, extension_name="honeypot")) + await bot.add_cog(HoneyPot(bot=bot)) class HoneyPot(cogs.MatchCog): diff --git a/modules/moderation/logger.py b/modules/moderation/logger.py index 0253d5374..f1f861ad8 100644 --- a/modules/moderation/logger.py +++ b/modules/moderation/logger.py @@ -22,7 +22,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(Logger(bot=bot, extension_name="logger")) + await bot.add_cog(Logger(bot=bot)) def get_channel_id(channel: discord.abc.GuildChannel | discord.Thread) -> int: diff --git a/modules/moderation/moderator.py b/modules/moderation/moderator.py index d70c62425..52ee30e2a 100644 --- a/modules/moderation/moderator.py +++ b/modules/moderation/moderator.py @@ -25,7 +25,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(ProtectCommands(bot=bot, extension_name="moderator")) + await bot.add_cog(ProtectCommands(bot=bot)) class ProtectCommands(cogs.BaseCog): diff --git a/modules/moderation/modlog.py b/modules/moderation/modlog.py index 38dff34fd..7da6fcc5c 100644 --- a/modules/moderation/modlog.py +++ b/modules/moderation/modlog.py @@ -25,7 +25,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(BanLogger(bot=bot, extension_name="modlog")) + await bot.add_cog(BanLogger(bot=bot)) class BanLogger(cogs.BaseCog): diff --git a/modules/moderation/nickname.py b/modules/moderation/nickname.py index d63e736c0..8ebd5059f 100644 --- a/modules/moderation/nickname.py +++ b/modules/moderation/nickname.py @@ -31,7 +31,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(AutoNickName(bot=bot, extension_name="nickname")) + await bot.add_cog(AutoNickName(bot=bot)) def format_username(username: str) -> str: diff --git a/modules/moderation/notes.py b/modules/moderation/notes.py index 012cc39a2..3dc08d4ab 100644 --- a/modules/moderation/notes.py +++ b/modules/moderation/notes.py @@ -23,7 +23,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(Notes(bot=bot, extension_name="notes")) + await bot.add_cog(Notes(bot=bot)) async def is_reader(interaction: discord.Interaction) -> bool: diff --git a/modules/moderation/purge.py b/modules/moderation/purge.py index bcb7aa9ac..910060ab5 100644 --- a/modules/moderation/purge.py +++ b/modules/moderation/purge.py @@ -21,7 +21,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(Purger(bot=bot, extension_name="purge")) + await bot.add_cog(Purger(bot=bot)) class Purger(cogs.BaseCog): diff --git a/modules/moderation/report.py b/modules/moderation/report.py index 02485bab0..703dc17fd 100644 --- a/modules/moderation/report.py +++ b/modules/moderation/report.py @@ -22,7 +22,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(Report(bot=bot, extension_name="report")) + await bot.add_cog(Report(bot=bot)) class Report(cogs.BaseCog): diff --git a/modules/moderation/whois.py b/modules/moderation/whois.py index 147cd829d..b1a9ec65e 100644 --- a/modules/moderation/whois.py +++ b/modules/moderation/whois.py @@ -24,7 +24,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(Whois(bot=bot, extension_name="whois")) + await bot.add_cog(Whois(bot=bot)) class Whois(cogs.BaseCog): diff --git a/modules/operation/application.py b/modules/operation/application.py index 749532075..c5939c997 100644 --- a/modules/operation/application.py +++ b/modules/operation/application.py @@ -41,8 +41,8 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(ApplicationManager(bot=bot, extension_name="application")) - await bot.add_cog(ApplicationNotifier(bot=bot, extension_name="application")) + await bot.add_cog(ApplicationManager(bot=bot)) + await bot.add_cog(ApplicationNotifier(bot=bot)) async def command_permission_check(interaction: discord.Interaction) -> bool: diff --git a/modules/operation/factoids.py b/modules/operation/factoids.py index 430303824..692afafa5 100644 --- a/modules/operation/factoids.py +++ b/modules/operation/factoids.py @@ -51,7 +51,6 @@ async def setup(bot: bot.TechSupportBot) -> None: await bot.add_cog( FactoidManager( bot=bot, - extension_name="factoids", ) ) diff --git a/modules/operation/forum.py b/modules/operation/forum.py index 4f6da7fba..08f99ef75 100644 --- a/modules/operation/forum.py +++ b/modules/operation/forum.py @@ -26,7 +26,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot to register the cog to """ - await bot.add_cog(ForumChannel(bot=bot, extension_name="forum")) + await bot.add_cog(ForumChannel(bot=bot)) STATUS_CONFIG = { diff --git a/modules/operation/paste.py b/modules/operation/paste.py index 80630102e..e603c745a 100644 --- a/modules/operation/paste.py +++ b/modules/operation/paste.py @@ -23,7 +23,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cog with """ - await bot.add_cog(Paster(bot=bot, extension_name="paste")) + await bot.add_cog(Paster(bot=bot)) class Paster(cogs.MatchCog): diff --git a/modules/operation/relay.py b/modules/operation/relay.py index 5639ca26f..e811ee827 100644 --- a/modules/operation/relay.py +++ b/modules/operation/relay.py @@ -36,7 +36,7 @@ async def setup(bot: bot.TechSupportBot) -> None: if not irc_config.enable_irc: raise AttributeError("Relay was not loaded due to IRC being disabled") - irc_cog = DiscordToIRC(bot=bot, extension_name="relay") + irc_cog = DiscordToIRC(bot=bot) await bot.add_cog(irc_cog) bot.irc.irc_cog = irc_cog diff --git a/modules/operation/voting.py b/modules/operation/voting.py index af106e5f3..cd780eb17 100644 --- a/modules/operation/voting.py +++ b/modules/operation/voting.py @@ -32,7 +32,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot to register the cog to """ - await bot.add_cog(Voting(bot=bot, extension_name="voting")) + await bot.add_cog(Voting(bot=bot)) class Voting(cogs.LoopCog): diff --git a/modules/operation/xp.py b/modules/operation/xp.py index 4ebcaa462..fb19bd202 100644 --- a/modules/operation/xp.py +++ b/modules/operation/xp.py @@ -23,7 +23,7 @@ async def setup(bot: bot.TechSupportBot) -> None: Args: bot (bot.TechSupportBot): The bot object to register the cogs to """ - await bot.add_cog(LevelXP(bot=bot, extension_name="xp")) + await bot.add_cog(LevelXP(bot=bot)) class LevelXP(cogs.MatchCog): diff --git a/modules/utility/news.py b/modules/utility/news.py index 30ee5b968..49789bda9 100644 --- a/modules/utility/news.py +++ b/modules/utility/news.py @@ -36,7 +36,7 @@ async def setup(bot: bot.TechSupportBot) -> None: except AttributeError as exc: raise AttributeError("News was not loaded due to missing API key") from exc - await bot.add_cog(News(bot=bot, extension_name="news")) + await bot.add_cog(News(bot=bot)) class Category(enum.Enum): @@ -203,9 +203,6 @@ async def news_command( interaction (discord.Interaction): The interaction in which the command was run category (str, optional): The category to get news headlines from. Defaults to None. """ - - # Debug statement - print("Executing news command") if category is None or category.lower() not in self.valid_category: category = random.choice(list(Category)).value else: @@ -258,8 +255,6 @@ async def news_autocompletion( Returns: list: The list of autocomplete for the news command. """ - # Debug statement - print("Autocomplete interaction") news_category = [] for category in Category: if current.lower() in category.value.lower(): diff --git a/modules/utility/winerror.py b/modules/utility/winerror.py index 01fecea28..a60037c52 100644 --- a/modules/utility/winerror.py +++ b/modules/utility/winerror.py @@ -24,7 +24,7 @@ async def setup(bot: bot.TechSupportBot) -> None: bot (bot.TechSupportBot): The bot to register the extensions """ - await bot.add_cog(WindowsError(bot=bot, extension_name="winerror")) + await bot.add_cog(WindowsError(bot=bot)) @dataclass diff --git a/tests/commands_tests/test_extensions_htd.py b/tests/commands_tests/test_extensions_htd.py index 9e2c51295..7c907cc68 100644 --- a/tests/commands_tests/test_extensions_htd.py +++ b/tests/commands_tests/test_extensions_htd.py @@ -8,7 +8,6 @@ from typing import Self import pytest - from commands import htd diff --git a/tests/commands_tests/test_extensions_hug.py b/tests/commands_tests/test_extensions_hug.py index c5ca7f2bd..d2d38b03b 100644 --- a/tests/commands_tests/test_extensions_hug.py +++ b/tests/commands_tests/test_extensions_hug.py @@ -10,8 +10,8 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest - from commands import hug + from core import auxiliary from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_lenny.py b/tests/commands_tests/test_extensions_lenny.py index f9e641ffb..187196aa4 100644 --- a/tests/commands_tests/test_extensions_lenny.py +++ b/tests/commands_tests/test_extensions_lenny.py @@ -9,8 +9,8 @@ from unittest.mock import AsyncMock, patch import pytest - from commands import lenny + from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_linter.py b/tests/commands_tests/test_extensions_linter.py index 5097a5c87..72ddd9602 100644 --- a/tests/commands_tests/test_extensions_linter.py +++ b/tests/commands_tests/test_extensions_linter.py @@ -11,8 +11,8 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest - from commands import linter + from core import auxiliary from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_mock.py b/tests/commands_tests/test_extensions_mock.py index 7238df54d..178a889e2 100644 --- a/tests/commands_tests/test_extensions_mock.py +++ b/tests/commands_tests/test_extensions_mock.py @@ -10,10 +10,10 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest +from commands import mock from hypothesis import given from hypothesis.strategies import text -from commands import mock from core import auxiliary from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_roll.py b/tests/commands_tests/test_extensions_roll.py index c243bf88d..a2dd8c7f5 100644 --- a/tests/commands_tests/test_extensions_roll.py +++ b/tests/commands_tests/test_extensions_roll.py @@ -11,10 +11,10 @@ import discord import pytest +from commands import roll from hypothesis import given from hypothesis.strategies import integers -from commands import roll from core import auxiliary from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_wyr.py b/tests/commands_tests/test_extensions_wyr.py index 57cc663c9..f20079b32 100644 --- a/tests/commands_tests/test_extensions_wyr.py +++ b/tests/commands_tests/test_extensions_wyr.py @@ -12,8 +12,8 @@ import discord import pytest - from commands import wyr + from core import auxiliary from tests import config_for_tests, helpers diff --git a/tests/config_for_tests.py b/tests/config_for_tests.py index f4f9b94be..c4f7ed48b 100644 --- a/tests/config_for_tests.py +++ b/tests/config_for_tests.py @@ -14,6 +14,7 @@ from typing import Self from unittest.mock import patch +from commands import Burn, Corrector, Emojis, Greeter, MagicConch from hypothesis.strategies import ( # pylint: disable=W0611 SearchStrategy, composite, @@ -21,8 +22,6 @@ text, ) -from commands import Burn, Corrector, Emojis, Greeter, MagicConch - from .helpers import ( MockAsset, MockAttachment, From 3b5dc95b636bd08be169c852259853f3586e3e10 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:42:44 -0700 Subject: [PATCH 05/10] Reformat load/unload/reload command --- modules/administration/extension.py | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/modules/administration/extension.py b/modules/administration/extension.py index 2752488cc..c94c0536a 100644 --- a/modules/administration/extension.py +++ b/modules/administration/extension.py @@ -106,10 +106,9 @@ async def load_extension( await interaction.response.send_message(embed=embed) return - try: - await self.bot.load_extension(f"functions.{extension_name}") - except (ModuleNotFoundError, commands.errors.ExtensionNotFound): - await self.bot.load_extension(f"commands.{extension_name}") + await self.bot.load_extension( + f"{self.bot.EXTENSIONS_DIR_NAME}.{extension_name}" + ) embed = auxiliary.prepare_confirm_embed( message=f"I've loaded the {extension_name} extension" @@ -137,10 +136,10 @@ async def unload_extension( embed = auxiliary.prepare_deny_embed(f"I could not find {extension_name}") await interaction.response.send_message(embed=embed) return - try: - await self.bot.unload_extension(f"functions.{extension_name}") - except commands.errors.ExtensionNotLoaded: - await self.bot.unload_extension(f"commands.{extension_name}") + + await self.bot.unload_extension( + f"{self.bot.EXTENSIONS_DIR_NAME}.{extension_name}" + ) embed = auxiliary.prepare_confirm_embed( message=f"I've unloaded the {extension_name} extension" @@ -168,16 +167,13 @@ async def reload_extension( embed = auxiliary.prepare_deny_embed(f"I could not find {extension_name}") await interaction.response.send_message(embed=embed) return - try: - await self.bot.unload_extension(f"functions.{extension_name}") - await self.bot.load_extension(f"functions.{extension_name}") - except ( - ModuleNotFoundError, - commands.errors.ExtensionNotFound, - commands.errors.ExtensionNotLoaded, - ): - await self.bot.unload_extension(f"commands.{extension_name}") - await self.bot.load_extension(f"commands.{extension_name}") + + await self.bot.unload_extension( + f"{self.bot.EXTENSIONS_DIR_NAME}.{extension_name}" + ) + await self.bot.load_extension( + f"{self.bot.EXTENSIONS_DIR_NAME}.{extension_name}" + ) embed = auxiliary.prepare_confirm_embed( message=f"I've reloaded the {extension_name} extension" From 86be19387f06bfdf692bbe77062861193fc3dc87 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:45:52 -0700 Subject: [PATCH 06/10] pylint formatting --- modules/administration/extension.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/administration/extension.py b/modules/administration/extension.py index c94c0536a..17c51ca21 100644 --- a/modules/administration/extension.py +++ b/modules/administration/extension.py @@ -16,7 +16,6 @@ import discord from discord import app_commands -from discord.ext import commands import ui from core import auxiliary, cogs From 2e00793a321631db8b8907bee1fe7c6d553f8516 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:47:32 -0700 Subject: [PATCH 07/10] flake8 formatting --- ircrelay/relay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ircrelay/relay.py b/ircrelay/relay.py index e3bde6242..2490e7d23 100644 --- a/ircrelay/relay.py +++ b/ircrelay/relay.py @@ -25,7 +25,7 @@ class IRCBot(irc.bot.SingleServerIRCBot): The class to start the entire IRC bot Attributes: - irc_cog (commands.relay.DiscordToIRC): The discord cog for the relay, + irc_cog (modules.operation.relay.DiscordToIRC): The discord cog for the relay, to allow communication between loop (asyncio.AbstractEventLoop): The discord bots event loop console (logging.Logger): The console to print errors to From ff6298a3dff070bfa8e2401baa69445f4accb52a Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:54:03 -0700 Subject: [PATCH 08/10] Fix imports on unit test --- modules/fun/__init__.py | 12 ++++++++++++ modules/utility/__init__.py | 4 ++++ tests/commands_tests/test_extensions_htd.py | 3 ++- tests/commands_tests/test_extensions_hug.py | 2 +- tests/commands_tests/test_extensions_lenny.py | 2 +- tests/commands_tests/test_extensions_linter.py | 2 +- tests/commands_tests/test_extensions_mock.py | 2 +- tests/commands_tests/test_extensions_roll.py | 2 +- tests/commands_tests/test_extensions_wyr.py | 2 +- tests/config_for_tests.py | 3 ++- 10 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 modules/fun/__init__.py create mode 100644 modules/utility/__init__.py diff --git a/modules/fun/__init__.py b/modules/fun/__init__.py new file mode 100644 index 000000000..72947f87b --- /dev/null +++ b/modules/fun/__init__.py @@ -0,0 +1,12 @@ +"""Modules designed for fun social interactions""" + +from .burn import * +from .conch import * +from .correct import * +from .emoji import * +from .hello import * +from .hug import * +from .lenny import * +from .mock import * +from .roll import * +from .wyr import * diff --git a/modules/utility/__init__.py b/modules/utility/__init__.py new file mode 100644 index 000000000..80675e940 --- /dev/null +++ b/modules/utility/__init__.py @@ -0,0 +1,4 @@ +"""Modules that provide some utility with external resources""" + +from .htd import * +from .linter import * diff --git a/tests/commands_tests/test_extensions_htd.py b/tests/commands_tests/test_extensions_htd.py index 7c907cc68..4f7b1a6e5 100644 --- a/tests/commands_tests/test_extensions_htd.py +++ b/tests/commands_tests/test_extensions_htd.py @@ -8,7 +8,8 @@ from typing import Self import pytest -from commands import htd + +from modules.utility import htd class Test_SplitNicely: diff --git a/tests/commands_tests/test_extensions_hug.py b/tests/commands_tests/test_extensions_hug.py index d2d38b03b..5b38249f3 100644 --- a/tests/commands_tests/test_extensions_hug.py +++ b/tests/commands_tests/test_extensions_hug.py @@ -10,9 +10,9 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from commands import hug from core import auxiliary +from modules.fun import hug from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_lenny.py b/tests/commands_tests/test_extensions_lenny.py index 187196aa4..611695278 100644 --- a/tests/commands_tests/test_extensions_lenny.py +++ b/tests/commands_tests/test_extensions_lenny.py @@ -9,8 +9,8 @@ from unittest.mock import AsyncMock, patch import pytest -from commands import lenny +from modules.fun import lenny from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_linter.py b/tests/commands_tests/test_extensions_linter.py index 72ddd9602..b589ad974 100644 --- a/tests/commands_tests/test_extensions_linter.py +++ b/tests/commands_tests/test_extensions_linter.py @@ -11,9 +11,9 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from commands import linter from core import auxiliary +from modules.utility import linter from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_mock.py b/tests/commands_tests/test_extensions_mock.py index 178a889e2..14469d356 100644 --- a/tests/commands_tests/test_extensions_mock.py +++ b/tests/commands_tests/test_extensions_mock.py @@ -10,11 +10,11 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from commands import mock from hypothesis import given from hypothesis.strategies import text from core import auxiliary +from modules.fun import mock from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_roll.py b/tests/commands_tests/test_extensions_roll.py index a2dd8c7f5..2a388a11b 100644 --- a/tests/commands_tests/test_extensions_roll.py +++ b/tests/commands_tests/test_extensions_roll.py @@ -11,11 +11,11 @@ import discord import pytest -from commands import roll from hypothesis import given from hypothesis.strategies import integers from core import auxiliary +from modules.fun import roll from tests import config_for_tests, helpers diff --git a/tests/commands_tests/test_extensions_wyr.py b/tests/commands_tests/test_extensions_wyr.py index f20079b32..4487f6515 100644 --- a/tests/commands_tests/test_extensions_wyr.py +++ b/tests/commands_tests/test_extensions_wyr.py @@ -12,9 +12,9 @@ import discord import pytest -from commands import wyr from core import auxiliary +from modules.fun import wyr from tests import config_for_tests, helpers diff --git a/tests/config_for_tests.py b/tests/config_for_tests.py index c4f7ed48b..c159e983c 100644 --- a/tests/config_for_tests.py +++ b/tests/config_for_tests.py @@ -14,7 +14,6 @@ from typing import Self from unittest.mock import patch -from commands import Burn, Corrector, Emojis, Greeter, MagicConch from hypothesis.strategies import ( # pylint: disable=W0611 SearchStrategy, composite, @@ -22,6 +21,8 @@ text, ) +from modules.fun import Burn, Corrector, Emojis, Greeter, MagicConch + from .helpers import ( MockAsset, MockAttachment, From 288b09bdbce2b2c52ae60c479b4bf0abe6aa78dd Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 8 Jun 2026 00:01:09 -0700 Subject: [PATCH 09/10] Fix some broken unit tests --- tests/commands_tests/test_extensions_lenny.py | 3 ++- tests/commands_tests/test_extensions_mock.py | 6 ++++-- tests/commands_tests/test_extensions_roll.py | 3 ++- tests/commands_tests/test_extensions_wyr.py | 18 ++++++++++++------ tests/helpers/bot.py | 1 + 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/commands_tests/test_extensions_lenny.py b/tests/commands_tests/test_extensions_lenny.py index 611695278..872a8df21 100644 --- a/tests/commands_tests/test_extensions_lenny.py +++ b/tests/commands_tests/test_extensions_lenny.py @@ -34,7 +34,8 @@ class Test_Lenny: def test_line_length(self: Self) -> None: """A test to ensure we never exceed the 2000 allowed characters""" # Step 1 - Setup env - lenny_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + lenny_test = setup_local_extension(discord_env.bot) # Step 2 - Call the function faces = lenny_test.LENNYS_SELECTION diff --git a/tests/commands_tests/test_extensions_mock.py b/tests/commands_tests/test_extensions_mock.py index 14469d356..5de7d3254 100644 --- a/tests/commands_tests/test_extensions_mock.py +++ b/tests/commands_tests/test_extensions_mock.py @@ -172,7 +172,8 @@ class Test_PrepareMockMessage: def test_with_set_string(self: Self) -> None: """A test to ensure that upper/lower works""" # Step 1 - Setup env - mocker = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + mocker = setup_local_extension(discord_env.bot) # Step 2 - Call the function result = mocker.prepare_mock_message(message="abcd") @@ -188,7 +189,8 @@ def test_with_random_string(self: Self, input_message: str) -> None: input_message (str): A random message to to prepare_mock_message with """ # Step 1 - Setup env - mocker = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + mocker = setup_local_extension(discord_env.bot) # Step 2 - Call the function result = mocker.prepare_mock_message(message=input_message) diff --git a/tests/commands_tests/test_extensions_roll.py b/tests/commands_tests/test_extensions_roll.py index 2a388a11b..2a4dc1a19 100644 --- a/tests/commands_tests/test_extensions_roll.py +++ b/tests/commands_tests/test_extensions_roll.py @@ -92,7 +92,8 @@ def test_random_numbers(self: Self, min_value: int, max_value: int) -> None: max_value (int): Another random int to test roll bounds with """ # Step 1 - Setup env - roller = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + roller = setup_local_extension(discord_env.bot) if min_value > max_value: temp = min_value max_value = min_value diff --git a/tests/commands_tests/test_extensions_wyr.py b/tests/commands_tests/test_extensions_wyr.py index 4487f6515..df37de8c8 100644 --- a/tests/commands_tests/test_extensions_wyr.py +++ b/tests/commands_tests/test_extensions_wyr.py @@ -39,7 +39,8 @@ class Test_Preconfig: async def test_preconfig(self: Self) -> None: """A test to ensure that preconfig sets the last variable correctly""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) # Step 2 - Call the function await wyr_test.preconfig() @@ -106,7 +107,8 @@ class Test_Get_Question: def test_any_question(self: Self) -> None: """Ensure that get_question gets any question""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) wyr_test.last = None # Step 2 - Call the function @@ -120,7 +122,8 @@ def test_any_question(self: Self) -> None: def test_resource_read(self: Self) -> None: """A test to ensure that the resource file is parsed correctly""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) wyr_test.last = None # Step 2 - Call the function @@ -136,7 +139,8 @@ def test_resource_read(self: Self) -> None: def test_non_repeat_question(self: Self) -> None: """A test to ensure that a random question can never occur twice""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) wyr_test.last = '"q1o1" || "q1o2"' # Step 2 - Call the function @@ -152,7 +156,8 @@ def test_non_repeat_question(self: Self) -> None: def test_last_set(self: Self) -> None: """Ensure that the last variable is properly set""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) wyr_test.last = None # Step 2 - Call the function @@ -166,7 +171,8 @@ def test_create_question_string(self: Self) -> None: """Ensure that the string is properly turned into a question""" # Step 1 - Setup env - wyr_test = setup_local_extension() + discord_env = config_for_tests.FakeDiscordEnv() + wyr_test = setup_local_extension(discord_env.bot) # Step 2 - Call the function resource_string = wyr_test.create_question_string('"q1o1" || "q1o2"') diff --git a/tests/helpers/bot.py b/tests/helpers/bot.py index e8c179be3..13f4d417a 100644 --- a/tests/helpers/bot.py +++ b/tests/helpers/bot.py @@ -23,6 +23,7 @@ class MockBot: """ def __init__(self: Self, input_id: int = None) -> None: + self.EXTENSIONS_DIR_NAME = "modules" self.id = input_id async def get_prefix(self: Self, message: helpers.MockMessage = None) -> str: From 6fa4e8af951a851e66648dde646b70c324bfd558 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 8 Jun 2026 00:09:58 -0700 Subject: [PATCH 10/10] Cleaup loop execute function --- core/cogs.py | 81 +++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/core/cogs.py b/core/cogs.py index b3d62b0bf..5d9778c30 100644 --- a/core/cogs.py +++ b/core/cogs.py @@ -350,51 +350,35 @@ async def _loop_execute( if not self.ON_START: await self.wait(guild) - for folder_dir in [self.bot.EXTENSIONS_DIR_NAME]: - while self.bot.extensions.get(f"{folder_dir}.{self.extension_name}"): - if guild and guild not in self.bot.guilds: - break + while self.bot.extensions.get( + f"{self.bot.EXTENSIONS_DIR_NAME}.{self.extension_name}" + ): + if guild and guild not in self.bot.guilds: + break - try: - channels_list = configuration.get_config_entry( - guild.id, self.CHANNELS_KEY - ) - except AttributeError: - channels_list = [] - - if target_channel and str(target_channel.id) not in channels_list: - # exit task if the channel is no longer configured - break - - if ( - guild is None - or self.extension_name - in configuration.get_config_entry( - guild.id, "core_enabled_extensions" - ) - ): - try: - if target_channel: - await self.execute(guild, target_channel) - else: - await self.execute(guild) - except Exception as exception: - # always try to wait even when execute fails - await self.bot.logger.send_log( - message=f"Loop cog execute error: {self.__class__.__name__}!", - level=LogLevel.ERROR, - channel=configuration.get_config_entry( - guild.id, "core_logging_channel" - ), - context=LogContext(guild=guild), - exception=exception, - ) + try: + channels_list = configuration.get_config_entry( + guild.id, self.CHANNELS_KEY + ) + except AttributeError: + channels_list = [] + + if target_channel and str(target_channel.id) not in channels_list: + # exit task if the channel is no longer configured + break + if guild is None or self.extension_name in configuration.get_config_entry( + guild.id, "core_enabled_extensions" + ): try: - await self.wait(guild) + if target_channel: + await self.execute(guild, target_channel) + else: + await self.execute(guild) except Exception as exception: + # always try to wait even when execute fails await self.bot.logger.send_log( - message=f"Loop wait cog error: {self.__class__.__name__}!", + message=f"Loop cog execute error: {self.__class__.__name__}!", level=LogLevel.ERROR, channel=configuration.get_config_entry( guild.id, "core_logging_channel" @@ -402,8 +386,21 @@ async def _loop_execute( context=LogContext(guild=guild), exception=exception, ) - # avoid spamming - await self._default_wait() + + try: + await self.wait(guild) + except Exception as exception: + await self.bot.logger.send_log( + message=f"Loop wait cog error: {self.__class__.__name__}!", + level=LogLevel.ERROR, + channel=configuration.get_config_entry( + guild.id, "core_logging_channel" + ), + context=LogContext(guild=guild), + exception=exception, + ) + # avoid spamming + await self._default_wait() async def execute( self: Self,