Disagreement
A Python library for interacting with the Discord API, with a focus on bot development.
Features
- Internationalization helpers
- Hybrid context for commands
- Built-in rate limiting
- Asynchronous design using
aiohttp - Gateway and HTTP API clients
- Slash command framework
- Message component helpers
Message.jump_urlproperty for quick links to messages- Built-in caching layer
- Experimental voice support
- Helpful error handling utilities
Installation
python -m pip install -U pip
pip install disagreement
# or install from source for development
pip install -e .
Requires Python 3.10 or newer.
To run the example scripts, you'll need the python-dotenv package to load
environment variables. Install the development extras with:
pip install "disagreement[dev]"
Basic Usage
import asyncio
import os
import disagreement
from disagreement.ext import commands
from dotenv import load_dotenv
load_dotenv()
class Basics(commands.Cog):
def __init__(self, client: disagreement.Client) -> None:
super().__init__(client)
@commands.command()
async def ping(self, ctx: commands.CommandContext) -> None:
await ctx.reply(f"Pong! Gateway Latency: {self.client.latency_ms} ms.")
token = os.getenv("DISCORD_BOT_TOKEN")
if not token:
raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set")
intents = disagreement.GatewayIntent.default() | disagreement.GatewayIntent.MESSAGE_CONTENT
client = disagreement.Client(token=token, command_prefix="!", intents=intents, mention_replies=True)
async def main() -> None:
client.add_cog(Basics(client))
await client.run()
if __name__ == "__main__":
asyncio.run(main())
Global Error Handling
To ensure unexpected errors don't crash your bot, you can enable the library's global error handler:
import disagreement
disagreement.setup_global_error_handler()
Call this early in your program to log unhandled exceptions instead of letting them terminate the process.
Configuring Logging
Use :func:disagreement.logging_config.setup_logging to configure logging for
your bot. The helper accepts a logging level and an optional file path.
import logging
from disagreement.logging_config import setup_logging
setup_logging(logging.INFO)
# Or log to a file
setup_logging(logging.DEBUG, file="bot.log")
HTTP Session Options
Pass additional keyword arguments to aiohttp.ClientSession using the
http_options parameter when constructing :class:disagreement.Client:
client = disagreement.Client(
token=token,
http_options={"proxy": "http://localhost:8080"},
)
These options are forwarded to HTTPClient when it creates the underlying
aiohttp.ClientSession. You can specify a custom connector or any other
session parameter supported by aiohttp.
Default Allowed Mentions
Specify default mention behaviour for all outgoing messages when constructing the client:
from disagreement.models import AllowedMentions
client = disagreement.Client(
token=token,
allowed_mentions=AllowedMentions.none().to_dict(),
)
This dictionary is used whenever send_message or helpers like Message.reply
are called without an explicit allowed_mentions argument.
Defining Subcommands with AppCommandGroup
from disagreement.ext.app_commands import AppCommandGroup, slash_command
from disagreement.ext.app_commands.context import AppCommandContext
settings_group = AppCommandGroup("settings", "Manage settings")
admin_group = AppCommandGroup("admin", "Admin settings", parent=settings_group)
@slash_command(name="show", description="Display a setting.", parent=settings_group)
async def show(ctx: AppCommandContext, key: str):
...
@slash_command(name="set", description="Update a setting.", parent=admin_group)
async def set_setting(ctx: AppCommandContext, key: str, value: str):
...
Fetching Guilds
Use Client.fetch_guild to retrieve a guild from the Discord API if it
isn't already cached. This is useful when working with guild IDs from
outside the gateway events.
guild = await client.fetch_guild("123456789012345678")
roles = await client.fetch_roles(guild.id)
Call Client.fetch_guilds to list all guilds the current user has access to.
guilds = await client.fetch_guilds()
for g in guilds:
print(g.name)
Sharding
To run your bot across multiple gateway shards, pass shard_count when creating
the client:
client = disagreement.Client(token=BOT_TOKEN, shard_count=2)
If you want the library to determine the recommended shard count automatically,
use AutoShardedClient:
client = disagreement.AutoShardedClient(token=BOT_TOKEN)
See examples/sharded_bot.py for a full example.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
See the docs directory for detailed guides on components, slash commands, caching, and voice features.
License
This project is licensed under the BSD 3-Clause license. See the LICENSE file for details.
Metadata
Release files for disagreement 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| disagreement-0.8.1.tar.gz | 180.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| disagreement-0.8.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 328.1 kB
Release files / disagreement-0.8.1.tar.gz
| Download URL | disagreement-0.8.1.tar.gz |
|---|---|
| Size | 180.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7187878f7a2b780fde4c430e33f6b0caebbf84da6a5cb3d4d3c75344ce0a238c
|
|
BLAKE2b-256 checksum How to use checksums |
4469edd5310c5e18ff7afeec775a9bcb33c7768f8c78f4eb1af9cd885bb49c04
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|
Release files / disagreement-0.8.1-py3-none-any.whl
| Download URL | disagreement-0.8.1-py3-none-any.whl |
|---|---|
| Size | 147.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1e656a4d718e7bc5b522910672959b3556c38baa578ac9dd6f246e12ff29c48
|
|
BLAKE2b-256 checksum How to use checksums |
92dffcfb1830cd80f2ab2eba3044c3f64d5231eac9714cdd68a69a6378fe52b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.3
|