Chapter 3. Cogs
Tags: python, discord, beginners, tutorial
Published: 2022-04-25 15:13:16

[Now that we have a general idea of how Discord bots are structured](https://dev.to/biasedkiwi/part-2-a-closer-look-at-the-code-4ifg), 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.

```python
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`

```python
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.

```python
@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](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=context#discord.ext.commands.Context):

> 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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0262mypox7qki4gcd7e0.png)

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()`

```python
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:

```python
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:

```python
import path/to/module
```

But like this:

```python
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!

## Further Reading

* [`commands.Cog`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=commands%20cog#discord.ext.commands.Cog)
* [`commands.Bot.load_extension`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=load_extension#discord.ext.commands.Bot.load_extension)
* [Function Decorators](https://docs.python.org/3/glossary.html#term-decorator)
* [`commands.command()`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=commands%20command#discord.ext.commands.Bot.command)