An opinionated extension for discord.py, inspired by JellyCommands. Amethyst adds a handful of features that I found myself re-implementing or wanting for many of my Discord bots such as automatic app command synchronisation and job scheduling.
The amethyst command
and context_menu
decorators are just a wrappers around discord.py's decorators. Please refer to the discord.py documentation for usage.
Amethyst's event decorator is a type hinted wrapper around discord.py's normal event decorator. The primary difference is that you must specify which event you wish to subscribe to. The amethyst module exports all of the default discord.py events with the prefix on_
.
import amethyst
@amethyst.event(amethyst.on_ready)
async def on_ready():
print("Bot is ready!")
Amethyst implements a cron-like asynchronous scheduler for calling functions on a set schedule, powered by croniter.
The following is an example of a schedule that will run every day at 8 am.
import amethyst
@amethyst.schedule("0 8 * * *")
async def every_morning():
print("Good morning!")
Amethyst can dynamically load python modules, powered by dynamicpy. When run, the client will automatically import and register any widgets found in the .command
, .commands
, .plugin
and .plugins
submodules. The submodules which are searched can be configured in the amethyst.Client
constructor.
Lets say you have the following project structure:
my-bot/
├── __init__.py
├── main.py
└── commands/
├── __init__.py
├── foo.py
└── bar.py
If your instance of amethyst.Client
is instantiated in main.py
then the commands/
package will be recursively searched for widgets to register.
The searched modules can also be top-level, the only requirement is that they are at the same level as the module inside which the client was instantiated.
my-bot.py
plugins.py
commands/
├── __init__.py
├── foo.py
└── bar.py
In this example, the commands.py
module and the commands/
package will be searched.
Amethyst has a plugin system, powered by dynamicpy and inspired by discord.py Cogs. You can create a plugin by simply defining a class that extends amethyst.Plugin
. If this is found by the Dynamic Module Importer then it will be automatically registered to the client, otherwise you will have to use the Client.register_plugin
method.
An example plugin may look like the following:
import amethyst
class ExamplePlugin(amethyst.Plugin):
@amethyst.event(amethyst.on_ready)
async def on_ready(self):
channel = self.client.get_channel(000000000000000000)
await channel.send("Bot is ready!")
Amethyst plugins support dynamicpy dependency injection for their constructors. You can add dependencies to the client using the Client.add_dependency
method, which will then be injected into constructor parameters when the plugin is registered.
import mysql.connector
import amethyst
client = amethyst.Client(...)
database: mysql.connector.MySQLConnection = mysql.connector.connect(...)
client.add_dependency(database)
class ExamplePlugin(amethyst.Plugin):
def __init__(self, database: mysql.connector.MySQLConnection) -> None:
self.database = database
Amethyst uses python-dotenv to load .env
files found at the project root. This can be used to configure certain aspects of the library.
Name | Default | Description |
---|---|---|
AMETHYST_TOKEN | None | If present, token can be omitted from the Client.run and this will be used instead. |
AMETHYST_AUTO_SYNC | true | If present, the client will synchronise app_commands if they are out of date with Discord. |
AMETHYST_GUILD | None | If present, the client will ignore all events from any guild with a differnet id. |
- Hybrid Commands
- Debug mode featuring automatic reload