Now that we have a general idea of how Discord bots are structured, we can take a look at cogs. But first:
What are cogs?
Cogs are "extensions" for your bot, they behave like Python modules. They can contain commands, and event listeners. Let's take a look at an example.
The anatomy of a Cog.
If you are following along with this tutorial, you will have a file named miscellaneous.py
located in src/cogs
. When we open it, we find a class declaration of a class named Miscellaneous
. Each cog contains 2 parts: the cog class, and the setup
function. Let's take a look at the class first.
class Miscellaneous(commands.Cog):
"""Cog class containing all miscellaneous commands."""
def __init__(self, bot: commands.Bot):
self.bot = bot
Here, we can see Miscellaneous
inherits properties from commands.Cog
, a class which all cogs should inherit from. Further down, we can see a function declaration for cog_load
async def cog_load(self):
"""Method called when the cog has been fully loaded."""
print("The Miscellaneous cog is loaded.")
As it's name suggests, this function is a special function that is called whenever that specific cog has been fully loaded. But the good stuff has yet to come, here, we see our first command. Wondering about slash commands? We'll talk about that later.
@commands.command(
name="ping", description="Get the current latency of the bot."
) # This could be implemented as a slash command.
async def ping(self, ctx: commands.Context):
"""Get the current latency of the bot."""
await ctx.channel.send(
f"The current latency of the bot is {round(self.bot.latency * 1000, 1)}ms."
)
Woah! This code can be confusing at first (Why is there an @
in the code???), but I'll walk you through it, first we see a function decorator, if you don't know what that is, it's fine. We can also see that the name
and description
parameters are being passed to commands.command
. Then we see the actual function declaration of ping()
, which takes ctx
as an argument, as the type hint suggests, this argument is of type commands.Context
. According to the docs:
Represents the context in which a command is being invoked under.
Then, we see a statement which calls the function send()
from ctx.channel
. We are also passing a argument, a an f-string to which we give the value of self.bot.latency
.
That was alot to take in huh? So what does this command actually do? It sends the bot's latency. Yep.
If you didn't quite catch how commands worked (I mean, they are kinda the whole point of Discord bots), don't worry, the next article in the series is going to be entirely about them.
The setup function
At the end of miscellaneous.py
, we can find a function declaration for setup()
async def setup(bot: commands.Bot):
await bot.add_cog(Miscellaneous(bot))
This function is mandatory for any cog to be loaded, if it is missing, you'll be greeted with a nice error message:
discord.ext.commands.errors.NoEntryPointError: Extension 'src.cogs.miscellaneous' has no 'setup' function.
A setup
function has to be an async
function. (Note: this is only as of Discord.py v2.0, which we have installed earlier. If you are using an older version, do not make the setup
function async
). Inside the setup function, we find an async call to commands.Bot.add_cog(cog)
where the cog
parameter is the cog class.
Loading cogs
Cogs on their own aren't really useful if they aren't loaded. We can load them using commands.Bot.load_extension(name)
where name
is the name of the cog we want to load. Since cogs behave the same way as python modules, we need to refer to them as such: When you import a module, you don't do it like this:
import path/to/module
But like this:
import path.to.module
So when you use commands.Bot.load_extension()
, you have to use the same notation (it's called dot notation) as when you're trying to import a module.
Conclusion
In this article we learned about cogs. At this point in the series, you might be wondering: "When the heck are we going to write commands?", well rest assured, it's coming in the next article. Stay tuned!
Top comments (0)