Chapter 2. A closer look at the code.
Tags: python, discord, beginners, tutorial
Published: 2022-04-25 10:03:45

[Now that we have prepared our **virtual environment**](https://dev.to/biasedkiwi/part-1-initial-setup-51ha), we are ready to start developing our Discord bot.

First, clone a template I have made with [git](https://git-scm.com/downloads). In the same directory as our virtual environment, run the following commands:

```shell
git init .
git remote add origin https://github.com/BiasedKiwi/discordpy-template.git
git pull origin main
```
Let's take a look at what these commands are doing.
* `git init .` creates a Git repository in the current directory.
* `git remote add origin` sets `https://github.com/BiasedKiwi/discordpy-template.git` as the remote server.
* `git pull origin main` fetches all the commits on the `main` branch

Now, these command don't show any output to the console, to check that the remote has been properly registered, let's execute `git remote -v`. You should see this output:

```shell
origin  https://github.com/BiasedKiwi/discordpy-template.git (fetch)
origin  https://github.com/BiasedKiwi/discordpy-template.git (push)
```

After you've executed all of these command, your directory structure should look like this:

```shell
├── LICENSE
├── README.md
├── launcher.py
├── requirements.txt
└── src
    ├── __init__.py
    ├── bot.py
    └── cogs
        └── miscellaneous.py
```

## A look at the code.

Let's take a look at `src/bot.py`. First, we can see a class declaration:

```python
class MinimalBot(commands.Bot):
    """Constructor class for the bot."""

    def __init__(self, *args, **kwargs):
        self.prefix = kwargs["command_prefix"]
        super().__init__(
            *args, **kwargs
        )  # Initialise a `Bot` instance with the parameters passed in the constructor.
```
This code declares a class named `MinimalBot` which **inherits** properties from `discord.ext.commands.Bot`. In `MinimalBot`'s `__init__` function, it creates an instance of it's parent class, a.k.a. `commands.Bot`, with the parameters suupplied (`*args, **kwargs`).

If we continue reading, we can see a function definition:

```python
async def setup_hook(self):
        await self.load_cogs(client=self, directory="./src/cogs")
```

`setup_hook()` is a special function called when the bot is being set up. It can be used to perform async operations when the bot first starts, without having to mess with `__init__()`.Inside we can see a call to another function: `self.load_cogs()`

```python
async def load_cogs(self, client, directory: str, subdir: str = "") -> None:
        """Load all cogs in a given directory in a recursive fashion."""
        os.chdir(directory)
        base = os.getcwd()
        for file in os.listdir():  # Iterate through all the files in a directory
            if file.endswith(".py"):
                if subdir != "":
                    await client.load_extension(
                        f"src.cogs.{subdir}.{file[:-3]}"
                    )  # As of Discord.py 2.0, `load_extension` is a coroutine.
                else:
                    await client.load_extension(
                        f"src.cogs.{file[:-3]}"
                    )  # Refer to comment on line 61.
            elif os.path.isdir(os.path.join(base, file)):
                os.chdir(os.path.join(base, file))
                await self.load_cogs(client, os.getcwd(), subdir=file)  # Recursive call
                os.chdir(base)
```
Unlike `setup_hook()`, `self.load_cogs()` isn't a special function of `commands.Bot`, it has been defined by us. This function loads all the **cogs** in a directory. For now, just know that cogs are "extensions" of the bot that can contain commands and other interesting things.

Further down, we can see another function definition: `on_ready()`. `on_ready()` is an **event** that is called when the bot has connected to Discord servers and is done preparing the data sent by Discord.

Events are special functions called when a specific event has been dispatched from Discord (duh!), in this example, `on_ready` is called when the bot is ready to send and receive data to Discord. Other events also exist like `on_message()` which is an event that is called whenever a message has been sent in a guild in which the bot is in. For a list of all events, take a look at the link to the Discord.py event reference in the *Further Reading* section at the end of this article.

Now, let's take a look at another file: `launcher.py`. This file is very simple, it contains a single `main` function.

```python
def main():
    intents = discord.Intents.default()
    intents.message_content = True
    bot = MinimalBot(
        intents=intents,
        command_prefix=os.environ.get("BOT_CMD_PREFIX"),
    )
    bot.run(os.environ.get("BOT_DISCORD_TOKEN"))
```
The first thing that this command does is set the **intents**, these are very important in Discord bot development, and we will talk about them in the next section of this article. Then, it creates an instance of `MinimalBot` inside a variable named `bot`. Finally, it runs the bot using an environment variable to get the **token** of the bot. (More on that later.)

## Intents

Intents were implemented by Discord to regulate the amount of data your bot has access to, for example, we've mentionned the `on_message` event before. To get this event working, we have to set the `message_content` intent to `True`. This will allow your bot to read the contents of all messages the bot can read. But there's a catch, the `message_content` intent is what Discord calls a **privileged intent.** This means that once your bot reaches 75 guilds, Discord will have to verify your bot for you to continue using the intent.

## Tokens

Tokens are a string of characters that authentify you with the Discord API (Kind of like a password). They carry your autorisations, like *privileged intents*. Tokens are **highly sensitive pieces of info**, if it falls in the wrong hands, it could have desastrous consequences for your bot, so make sure to keep it somewhere safe, and only share it with people you truly trust.

## Conclusion

Alright! I think this article has come to an end, in the next one, we will look at **cogs**: how to use them, load them and their gotchas. See you on the next one!

## Further Reading
* [`commands.Bot`](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=commands%20bot#discord.ext.commands.Bot)
* [`commands.Bot.setup_hook()`](https://discordpy.readthedocs.io/en/latest/ext/commands/api.html?highlight=setup_hook#discord.ext.commands.Bot.setup_hook)
* [Discord.py event reference.](https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_ready#event-reference)
* [Python's `super()` function.](https://docs.python.org/3/library/functions.html#super)
* [Discord bot verification.](https://support.discord.com/hc/en-us/articles/360040720412)
* [Class Inheritance in Python](https://docs.python.org/3/tutorial/classes.html#inheritance)