Low boilerplate command framework for Discord's REST API with Database, external Cache, Localization, Event Logging support and more. Bleeding-edge low boilerplate command framework for Discord's REST API extending mDiscord wrapper. Batteries Included.
- Command's metadata inferred from Python syntax itself
- Dual availability of commands - define once and use as either message or interaction based
- Implicit modals inferred from argument typehints available as modal or message-based argument polling depending on invocation
- Hierarchy-based internal permission system
- Reaction-based commands
- Basic extendable runtime-defined message custom command parser
- Webhook-based logging of Discord events
- Leaderboard builder
- Built-in Database support (SQLAlchemy)
- Built-in remote cache support (Redis)
- Built-in localization support (i18n)
- Run as module
- Easly extendable
- Volatile
- Repository was used as a monorepo and a "testbed" for unrelated features, certain parts were moved to separate repositories however there are still remnants of them here
- Barely any documentation
- Horror in internal files
System package requirements for Postgres support:
sudo apt install libpq5
Required packages:
python3 -m pip install -r requirements.txt
More examples can be found directly in my M_Bot repo.
Unlike other libraries, there is no bot
or cog
- everything is registered globally and a lot of information is taken from docstrings and function signatures, mainly for ease of extending.
Command example
from MFramework import register, Groups, Context
@register(group=Groups.GLOBAL)
async def say(ctx: Context, text: str, i: int=1) -> str:
'''
Sends a specifed message x times and finishes with replying with Done
Params
------
text:
Message to send
i:
Amount of times
'''
for x in range(i):
await ctx.send(f"{text} x {x}")
return "Done"
Button example
from MFramework import Context, Button, Select
class CoolButton(Button):
@classmethod
async def execute(self, ctx: Context, data: str):
# Any kind of logic that happens upon pressing a button
pass
Select Button example
from typing import List
from MFramework import Context, Select, Select_Option
class NiceSelection(Select):
@classmethod
async def execute(self, ctx: Context, data: str, values: List[str], not_selected: List[Select_Option]):
# Any kind of logic that happens upon selecting options from Menu
pass
Using components example
from MFramework import Row
@register(group=Groups.GLOBAL)
async def new_cool_button(ctx: Context, cool_argument: str = "It's cool! Trust!") -> CoolButton:
'''
Sends new message with cool button
Params
------
cool_argument:
Label's text of this button
'''
return CoolButton(label=cool_argument)
@register(group=Groups.GLOBAL)
async def new_cool_button(ctx: Context, name: str = "Cool Option") -> List[Row]:
'''
Sends new message with 2 rows, first with Selection with two options and second with two buttons
Params
------
name:
name of first option
'''
rows = [
Row(
NiceSelection(
Option(
label=name, value=123
),
Option(
label="Second option", value=256
),
placeholder= "Options"
)
),
Row(
CoolButton(label="Cool Button!", style=Button_Styles.SECONDARY),
Button(label="Not cool button", style=Button_Styles.DANGER)
)
]
return rows
Modal example
from MFramework import register, Groups, Context, Embed
from MFramework.commands.components import TextInput
@register(group=Groups.GLOBAL)
async def suggestion(ctx: Context, title: TextInput[1, 100], your_suggestion: TextInput[1, 2000]) -> Embed:
'''
Make a Suggestion!
Params
------
title:
Title of suggestion
your_suggestion:
Your suggestion
'''
return Embed(title=title).set_description(your_suggestion)
Autocomplete example
from MFramework import register, Groups, Context, Interaction
async def animals(interaction: Interaction, current: str) -> list[str]:
"""Current represents what user typed so far"""
return ["Sheep", "Dog", "Cat"]
@register(group=Groups.GLOBAL)
async def choose(ctx: Context, animal: animals) -> str:
"""
Choose an animal
Params
------
animal:
Autocomplete that suggests animal names
"""
return f"Selected animal: {animal}"
locale/en-US/bot.json
{
"hi": {
"hello": "Hello!"
}
}
locale/pl/bot.json
{
"hi": {
"hello": "Cześć!"
}
}
bot.py
@register(group=Groups.GLOBAL)
async def hi(ctx: Context) -> str:
'''Replies in your language'''
return ctx.t("hello")
via docker compose
docker-compose up
Manually
docker run -it \
-v data:/app/data \
-v bot:/app/bot \
Mmesek/mframework
Build docker image
docker build --target base -t mframework:latest .
Run built image with autoremoving
docker run -it \
-v "PATH_TO_DATA_FOLDER:/app/data" \
-v "PATH_TO_BOT_CODE:/app/bot" \
--rm mframework
python -m MFramework bot --cfg=tokens.ini --log=INFO
Any sort of contribution, be it a Documentation, feature implementation, feature suggestion, bug fix, bug report or even a typo fix is welcome. For bigger changes open an issue first.