A modular way to create a Discord bot.
This repository has been archived on 2021-03-28. You can view files and clone it, but cannot push or open issues/pull-requests.
Go to file
Jef Roosens d1080d0fcb Added bug & features request issue templates 2020-08-29 10:01:01 +02:00
.gitlab/issue_templates Added bug & features request issue templates 2020-08-29 10:01:01 +02:00
frank Excluded tests from package build 2020-08-26 14:54:55 +02:00
tests Added commands order test 2020-08-26 14:12:58 +02:00
.dockerignore Added basic framework 2020-08-08 09:19:09 +02:00
.gitignore Added dummy test 2020-08-25 19:04:24 +02:00
CHANGELOG.md Final prep for 0.1 release 2020-08-26 15:08:41 +02:00
LICENSE Added GPL V3 license 2020-08-25 17:14:17 +02:00
Makefile Fixed publish recipe 2020-08-26 15:17:37 +02:00
README.md Added to README 2020-08-26 18:13:54 +02:00
pytest.ini Moved source file from other repo 2020-08-25 17:08:53 +02:00
requirements-dev.txt Added Twine to dev requirements 2020-08-26 14:13:18 +02:00
requirements.txt Added publish recipe 2020-08-25 18:56:19 +02:00
setup.py Changed name (frank is taken) 2020-08-26 15:20:00 +02:00




Playing around with creating a Discord bot is a fun pass-time, and a good way to learn a programming language. Sadly, however, discord.py can be a little hard to work with at times. That's when I got the idea to create Frank. The goal of Frank is to make creating Discord bots easier. It handles all the bot-related stuff in the background, so you can focus on writing the functionality of the bot itself, not how the bot works/interacts with Discord.

Frank works by dividing the bot into modules. Each module has its own prefix, commands, and daemons. Frank handles routing the Discord commands to their respective functions.

Example Module

In this section, I've written an example module for you, to understand the basic mechanics behind Frank.

import frank

class ExampleMod(frank.Module):
    PREFIX = 'examp'
    NAME = 'example'
    HELP = 'an example module'

This first part shows the three important variables in any module.

  • PREFIX defines the string used to use the commands defined in this module. This means you can use the module as such inside your Discord server:
    fr examp [NAME_OF_COMMAND] [ARGS]
    With fr being the default prefix for Frank (can be overwritten). As you define more modules, they should all have a unique prefix. This is how Frank's modular system works, and any modules added to the list will automatically be picked up by Frank. The PREFIX value can also be list, allowing for multiple prefixes: for example a long, description one, and a short, easy to type one (e.g. minecraft and mc).
    def pre_start(self):
        self.some_var = 'a value needed for working'

The pre_start function is where you define any variables which should be created before any daemons are started or commands are run. I don't recommend overwriting __init__, as this might break compatibility with future versions of Frank.

    @frank.command('command', help_str='a small description of the command')
    async def some_command(self, cmd, author, channel, mid):
        # do some stuff

    async def some_daemon(self):
        while True:
            # do some stuff

    async def default_cmd(self):
        # do some default action

These three decorators are the bread and butter of Frank. Let's break them down:

  • frank.command defines a command. The first argument is its keyword, which will be used to execute the command. The help_str value is used in the help command, to show some information about the module. The syntax is the same as before:
    fr examp command [ARGS]
    This is how you can define as many Discord commands as you want, without needing to know how to parse the messages etc. Each command gets the author, channel, and id of the message. The cmd variable contains all the arguments passed to the command.
  • frank.daemon defines a daemon, a process that should run in the background for as long as the bot is active. It should contain a while loop and preferably a sleep function using asyncio.sleep() (there are plans to improve this behavior). Because a daemon is just a method of the module class, it has access to all class variables, including those defined in pre_start.
  • frank.default defines the command that should be run if the module is called without explicitely giving a command. For example, if you call fr examp without specifying a command, it will run the default command. This is useful for making a command that's used very often easier to execute.

In the end, all you need to do is the following in your main script:

from frank import Frank
# Or whatever your package containing your modules is called
from modules import ExampleMod

if __name__ == '__main__':
    client = Frank([ExampleMod])

You can obtain this token from the Discord developer page.