Recursively load all cogs in a Discord.py bot
I’ve been in the process of moving my discord bot from @dodo to @dogdog to make it easier on myself to improve on what I originally made. I want to take up programming as a hobby again and why not go back to where it all started. Anyway, here’s a neat trick i’ve been using for a while.
As a disclaimer, all of this can be mostly replaced with something like the below example, but where is the fun in that?
for key, value in bot.cogs.items():
bot.load_extension(key)
In main.py
:
def load_extensions():
"""Load all modules/extensions/cogs from specificed directories"""
dir_list = ['listeners', 'modules', 'slashes']
exclusion_list = ['help']
for dir_ in dir_list:
print(f'=== Attempting to load all extensions in {dir_} directory ...')
for filename in os.listdir(f'./{dir_}'):
module = filename[:-3]
if filename.endswith('.py') and module not in exclusion_list:
try:
bot.load_extension(f'{dir_}.{module}')
print(f'\tSuccessfully loaded extension: {module}')
except Exception as err:
exc = f'{type(err).__name__}: {err}'
print(f'\tFailed to load extension: {module}\n\t\t{exc}')
for excl_module in exclusion_list:
print(f'=== Excluding the extension: {excl_module}')
dir_list
are all subdirectories of the parent directory. For organizational purposes I split them in to modules
(commands such as .weather), listeners (on_message and guild/member status changes), and discord’s built in slash
commands.
exclusion_list
is for specific files to exclude from loading. This is because within each subdirectory I have
most major commands split in to different folders to make it easier to find what I’m looking for. The customized
help
is currently disabled until I complete it.
These can (and should) be moved to a configuration file elsewhere. I only have them here for demonstration.
In main.py
:
def log_in():
"""Login function"""
print('=== Initializing startup sequence ...')
load_extensions()
print('=== Attempting to log in to bot ...')
try:
bot.run(DISCORD_TOKEN)
except discord.errors.HTTPException or discord.errors.LoginFailure as error:
print('\nDiscord: Unsuccessful login:', error)
else:
sys.exit("Login Unsuccessful")
if __name__ == '__main__':
log_in()
Now load_extensions()
is ran in the discord bot’s startup script.
=== Initializing startup sequence ...
=== Attempting to load all extensions in listeners directory ...
Successfully loaded extension: guild_events
Successfully loaded extension: member_events
Successfully loaded extension: on_message
=== Attempting to load all extensions in modules directory ...
Successfully loaded extension: admin
Successfully loaded extension: custom_command
Successfully loaded extension: misc
Successfully loaded extension: people
Successfully loaded extension: xkcd
=== Attempting to load all extensions in slashes directory ...
Successfully loaded extension: memes
=== Excluding the extension: help
=== Attempting to log in to bot ...
==================================
Logged in as: testdogtestdog
Client ID: {Bot's UID}
Local time: 2022-04-30 10:06:48
==================================
… and the output is kinda clean too!