DEV Community

BiasedKiwi
BiasedKiwi

Posted on

Chapter 3. Cogs

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
Enter fullscreen mode Exit fullscreen mode

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.")
Enter fullscreen mode Exit fullscreen mode

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."
        )
Enter fullscreen mode Exit fullscreen mode

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.

What the command does.

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))
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

But like this:

import path.to.module
Enter fullscreen mode Exit fullscreen mode

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!

Further Reading

Top comments (0)