Learn to Code via Tutorials on Repl.it

← Back to all posts
10
Making a discord bot with disco-py (not discord.py!)
h
21natzil (680)

Creating a discord bot with disco-py

This is not a discord.py tutorial! This is a tutorial for a discord bot library that I prefer, and made by one of discord's own developers! disco-py.

Getting Started

First, let's create a python3 repl. We're going to create a requirements.txt file, can put the following text inside it.

disco-py
flask

Repl.it will look to this file for external dependencies, disco-py for bot obviously, and flask, if you want to use uptimerobot. Then we're also going to create a folder for the plugins called plugins. Plugins are exactly like discord.py's cogs, it's just a set of commands grouped together, that can be loaded / unloaded. By now you should have created a bot application here, and you can now copy the bot's token. Now create a .env file, and write

token=<token here>

.env files are special on repl.it, as other people can't see them. Repl.it will load these files on startup and create environment variables. Alright, now time to write some code!

Creating a plugin!

Let's create a file in the plugin folder called hello.py (plugins/hello.py) and create the class that will hold all the commands / listeners.

from disco.bot import Plugin


class HelloPlug(Plugin):
  ...

We'll get into loading the plugins later (For those of you that've used discord.py, you'll notice there's no function like setup to add the plugin. That's because disco-py doesn't need one.) Let's create a command that says hello to us.

from disco.bot import Plugin


class HelloPlug(Plugin):

  @Plugin.command("hello", "<name:str...>")
  def hello(self, event, name: str):
    event.msg.reply(f"Hello {name}!")

Ok, let's break down all this code. First we use @Plugin.command to tell disco that this function is a command. The first argument we pass into that in the name of the command that people will use to invoke the command. The second argument specifies what information the command requires. The syntax is pretty simple, however it requires an explanation.

  • The < > characters specify that this argument is required. If I had used [``], it would have been optional.
  • name:str tells disco-py to pass the value provide into the function's name argument. the str tells disco-py to cast the value to a string, if it's not already.
  • The ... tells disco-py to match the whole input. Without this, if someone did !hello Johny Jenkins, name would only be Johny.
  • command("add", "<num1:int> <num2:int>") will match !add 5 4
  • command("kick", "<user:str> <reason:str...>") will match !kick Johny Called me ugly
  • Pro Tip: You cannot use ... if it's not the last argument.

As you can see, an event variable is provided, this will contain information on the event, and exposes things such as

  • event.msg
  • event.channel
  • event.author
  • event.guild

In this case, we want to send a message back in the same channel, so we can do event.msg.reply for that. If you've used discord.py, you'll notice we're not using async / await. That's because disco-py uses the (arguably better) gevent lib. This means you can use packages such as requests, almost any database driver, and still be asynchronous!

Running the bot

Disco-py has a very different way of running bots, for better or worse. We're going to create a config.json file. Here we're going to put information like the prefix and plugin locations. The config.json actually stores a lot more information, but for right now that's all we'll need.

{
    "bot": {
        "plugins": [
            "plugins.hello"
        ],
        "commands_prefix": "!"
    }
}

You can copy paste this, it's pretty self-explanatory. Don't use / or \\ paths to provide the location of the bot, instead use . like you're importing it.

Now, disco bots must be run by the command line, but doing something like:

python3 -m disco.cli --token <token here>

Pro Tip: Make sure you run this command in the same directory as the config file

However that's quite inconvenient on repl.it. Instead, we're going that some command in the main.py file, like so:

from os import environ, system

token = environ['token']


system("python3 -m disco.cli --token {token}".format(token=token))

And at this point, we have everything we need! You can start the repl and everything should be ready to go! This is just a small part of disco-py. Sadly, the docs right now are quite lacking. That's why I'm going to continue to work on this tutorial, and expose all of disco's hidden treasures!

You can view the complete bot here: https://repl.it/@21natzil/ExampleBot

Using it with uptimerobot (Optional)

If you'd like to run your bot on repl.it, it's actually even easier with disco-py than discord.py. disco-py has flask integration built right in, making it super easy to combine a website and discord bot. Let's return to the hello.py file, and add the following route to the Plugin class:

  @Plugin.route("/")
  def index(self):
	return "Hello World"

If you've used flask before, this should look very familiar. All this code does is return the text Hello World when someone visits the website. Now we just have to edit the config, and add 2 pits of information flask requires.

{
	"bot": {
		"plugins": [
			"plugins.hello"
		],
		"commands_prefix": "!",
		"http_enabled": true
	}
}

All we added was "http_enabled": true to tell disco-py that we're using flask. And just like that if you visit the repl's website it should say Hello World! See the link to the example bot above to see it in action.

Thanks for reading! Hopefully you'll give disco-py a try. At first glace it's not much, but I promise you, it's much more complicated then that! Any feedback or questions are greatly appreciated!