Build a Dicord bot with ease and flexibility
Project description
Build-A-Bot
Build a Dicord bot with ease and flexibility
For editing module repo: Before replacing anything with modules from elsewhere, and I can't stress this enough, you MUST read the new and old files carefully to verify that you indeed have the latest version of the module. Check every file, every method, every line that you are not overriding things so that they are lost forever and you have to spend another 8 hours recreating it.
Some nitpicky things
- All files are lowercase and snake case
- module names start with an uppercase letter (except for cases like jQuery) and are CamelCase
- With acronyms, only capitilize the first letter if longer than 2 characters (ie. Url, DB, Http, AV)
- Descriptions are required, but don't need to be detailed
- All modules must have a README
- For modules in a folder, or foldered modules, name it
README.md
and put it alongside themodule.json
- For single file modules, put the readme in
__READMES__
with the same name as the module file (ie../my_module.py
=>./__READMES__/my_module.md
)
- For modules in a folder, or foldered modules, name it
- For single file modules make sure your meta is in the following format
meta = { ... } ## BuildABot -- end
this is so the automated bot maker can properly identify the module depencencies, but is not nessesary for non-public modules - Verify all dependencies, soft dependencies, and requirements are there, none are missing, and there are none extra
- If nessesary have
defaultConfig
is in the module meta - Change nothing without doing what it says at the top
- modules should be independent and should not throw errors on_load, on_enable, and on_disable
- The more config options, the better
Creating a module
Setting up
To start, you have two options; create a single file module or a folder. You should use a folder if you plan to have, commands, locale, many classes, or complex logic.
Single File
- Create your file in
src/modules
(echo "" > src/modules/my_module.py
) - import buildabot module (
from buildabot import module
) - create a var called
meta
and assign a dict, more info about module metas below (meta = {}
)- End the dict with
} ## BuildABot -- end
if it is a public module
- End the dict with
- create a class that extends
module
(class Mymodule(module):
)
Folder
- Create a folder, choose a folder name close to your modules' (
mkdir src/modules/my_module
) - Change to that folder (
cd src/modules/my_module
) - Create
module.json
and create an object inside, more info about module metas below (echo "{}" > module.json
) - Create a python file with whatever name, I'd reccomend the same as your folder (
echo "" > my_module.py
) - import buildabot module (
from buildabot import module
) - create a class that extends
module
(class Mymodule(module):
)
Now that you have the basic setup done, it's time to setup your module meta
Meta
module Meta is something that tells BuildABot what your module does and how to get things rolling. The meta is an object (or dict), here is a list of all properties you can use, some are required
Key | Type | Default | Info |
---|---|---|---|
class | string | n/a | Starting class of the module, more info below |
name | string | n/a | Name of the module |
description | string | n/a | What the module does, be as short or complex as you need |
?depends | string[] | [] | module dependencies |
?softDepends | string[] | [] | Optional module dependencies |
?defaultConfig | object | {} | Default config for the module |
?requirements | string[] | [] | Pypi requirements for the module |
?threaded | boolean | false | module uses threading. modules that have this true can not be disabled |
?disable | boolean | false | modules that have this true will not be enabled |
?experimental | boolean | false | Experimental modules should be used causiously as they might not behave as expected. |
Example Meta:
{
"class": "my_module.Mymodule",
"name": "Mymodule",
"description": "My module is an awesome module that enables the bot to do some really awesome stuff!",
"depends": [],
"softDepends": [
"Commands"
],
"defaultConfig": {
"awesomeFactor": 1.42
},
"requirements": ["pytz"],
"threaded": false,
"disable": false,
"experimental": false
}
If for some reason your module needs to access your or another feautres meta you can do module#meta
Class
- For single file modules, set
class
as the name of the class that extendsmodule
- For folder modules, class should be set to the import of the class that extends
module
from the module folder (ie.settings.SnowflakeSettings
, in the filesettings.py
with the class namedSnowflakeSettings
)
module methods
def on_load(self)
- called when module is loaded, don't attempt to access other modules as they may not be loaded yetasync def on_enable(self)
- called when the module is enabled, now is when you can garentee you dependencies will be loadedasync def on_disable(self)
- called when module is disabled, more offten than not this won't be called when the bot stops
Events
Events are listened using module#on_event(event_name, listener_func, [namespace="discord"], [priority=0], [ignore_canceled=False])
, event names can be found on the discord.py documentation, in addition here are the built-in events, the namespace is buildabot
:
on_ready
- Called when the module manager is setupon_done
- Called after enable process is finished (afteron_all_enabled
)on_all_load
- Called after all modules are loaded, useful to add or modify functions in each moduleon_load
- Called once a module has been loaded, useful to add or modify a dependant moduleon_all_enabled
- Called when all modules have been enabledon_enabled
- Called once a module has been enabledon_all_disabled
- Called when all modules have been disabledon_disable
- Called once a module has been disabled
Important: All listener functions must be a coroutine. In order to turn a function into a coroutine they must be async def
functions
Each module may have their own events, you can read about them in the modules' README
To create an event, it's pretty simple, in your on_load
define the module with self.module_manager.define_event(event_name)
then to call the event run either await self.module_manager.emit_event(namespace, event_name, *args, **kwargs)
or self.module_manager.emit_event_sync(namespace, event_name, *args, **kwargs)
Using other modules
Using other modules is pretty easy, it's as simple as doing self.module_manager.get_module("SomeOthermodule")
. But before you use any module you should put the module in your dependiencies, this prevents any errors and garentees the module is there when your module is enabled. If you were to soft depend a module then you should always check if the module is enabled before using it, self.module_manager.is_enabled("SomeOthermodule")
Creating commands
Because commands are so common, I thought it'd be a good idea to tell you how to use the Commands module, but more detailed info will be in the Commands README. First of all, Commands requires EmbedUI and works best with SnowflakeSettings installed, and second your module should be in a folder to be the cleanest, the tutorial will be for foldered modules only.
- To get setup you first want to create a new directory in your module directory called anything you want, but it's common to call it
cmds
- Now, hooking into Commands is easy, as ushal you want to put Commands into your soft dependencies.
- Next copy this code snippit into your on_enable
if self.module_manager.is_enabled("Commands"):
from modules.commands.command_manager import CommandManager # import CommandManager for type hinting
cmd: CommandManager = self.module_manager.get_module("Commands") # Get the command manager
cmd.add_command_dir('my_module/cmds', ftr_dir=True) # Tell the command manager where your commands are
cmd.add_type("my", "My module", after='info') # More info in Commands README
This snippit will get the Commands command manager and tell it where to look for your commands, this isnt the only way to add commands, but it is the cleanest.
- Now in your modules' commands directory, create a new python file, the name of the file will be the name of the command (ie
my_command.py
) - Inside the file put the following code (remove comments if you want)
from modules.commands.command import Command
from modules.commands.command_context import CommandContext
meta = {
'class': 'MyCommand',
'description': "A command that does cool stuff",
'usage': '',
'pack': 'my_module',
'type': "my",
'permissions': []
} # More info in Commands README
class MyCommand(Command):
async def on_command(self, context: CommandContext): # Called when the user runs the command, more info in Commands README
await context.ok("{}, my command is the coolest command!".format(context.author.mention)) # Replys to the channel using EmbedUI
Example module
This is a foldered module
src/modules/my_module/module.json
{
"class": "my_module.Mymodule",
"name": "Mymodule",
"description": "My module is an awesome module that enables the bot to do some really awesome stuff!",
"depends": [
"MongoDB"
],
"softDepends": [
"Commands"
],
"defaultConfig": {
"awesomeFactor": 1.42
},
}
src/modules/my_module/my_module.py
from buildabot import module
class Mymodule(module):
def __init__(self, fm, m):
super().__init__(fm, m)
self.collection = None
async def on_enable(self):
self.collection = self.module_manager.get_module("MongoDB").collection("my_module")
if self.module_manager.is_enabled("Commands"):
from modules.commands.command_manager import CommandManager
cmd: CommandManager = self.module_manager.get_module("Commands")
cmd.add_command_dir('my_module/cmds', ftr_dir=True)
cmd.add_type("my", "My module", after='info')
cmd.add_alias("add", "my")
cmd.add_alias("count", "my")
src/modules/my_module/cmds/my.py
import discord
from modules.commands.command import Command
from modules.commands.command_context import CommandContext
meta = {
'class': 'My', # Class of the command
'description': "A command that does cool stuff", # What the command does
'usage': '<number>', # Tells the user the command usage in the help command
'pack': 'my_module', # Used to disable specific module commands in the Commands config
'type': "my", # In the "My module" category in the help command
'permissions': ['administrator'] # WIll require the user to have the `administrator` permission
# Alias support in command meta not avaliable, for now add aliases in your `on_enable`
}
class My(Command):
async def on_command(self, context: CommandContext):
# Verify the correct amount of arguments
if len(context.args) < 1:
raise context.MissingArgsException(context)
# Test first argument for number
try:
add = int(context.args[0])
except:
# Make sure to tell users why a command failed
await context.error("That's not a number")
return
# Add to users counter, if not exist insert it with `upsert`
result = self.command_manager.get_module("Mymodule").collection.update_one(
{"user": context.author.id}, {"$add": {"count": add}}, {"upsert": True})
# Get count from document
count = result.raw_result["count"]
# Tell the user thier updated counter
await context.ok(f"Your counter is now at {count}")
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file BuildABot-2.0.4.tar.gz
.
File metadata
- Download URL: BuildABot-2.0.4.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 09911f60a6b743ae3a12561def05fafd069e641059eedfe590fbe119ce4f6e2e |
|
MD5 | de887f893af3bafeffb7d1de9f687292 |
|
BLAKE2b-256 | b0d3bde55cb9f3943721d5ee5a025234c92ddc7b9d7fcd220eadfd2ccc2d8056 |
File details
Details for the file BuildABot-2.0.4-py3-none-any.whl
.
File metadata
- Download URL: BuildABot-2.0.4-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1a62d25ce6004d8fb7695b4fa37aa828fdb33eded0beccdc5903f029b234025b |
|
MD5 | 5bc3e5a23ec9ea2a86ed66f3ab786617 |
|
BLAKE2b-256 | d6e040013bb0cf21f4fd937ef9ce5dfafef893aa8da56150ee75297c5fd45664 |