Skip to main content

A modern, beautiful Discord bot library for Python 3.10+

Project description

PyPI Python License

Disquerd

A modern, performant Discord bot library for Python 3.10+
Built on Discord API v10 · msgspec-powered models · Full component support


Features

  • Discord API v10 — no legacy cruft, only the latest API
  • msgspec Struct models — zero-copy JSON decoding, strict typing, no silent field misses
  • Slash commands — full support with options (USER, CHANNEL, ROLE, INTEGER, STRING, BOOLEAN, NUMBER, ATTACHMENT, MENTIONABLE)
  • Prefix commands — with aliases, shlex argument parsing, case_insensitive, strip_after_prefix
  • Context menus — user commands and message commands
  • Subcommands & groupsSubCommand, SubCommandGroup for organized command trees
  • Autocomplete — first-class autocomplete handler support
  • Components V1View, Button, SelectMenu, ActionRow, Modal, TextInput
  • Components V2Container, Section, Separator, TextDisplay, MediaGallery
  • Modal systemModalBuilder, @bot.modal() decorator, ModalContext.value()
  • Button listeners@bot.button() decorator, ComponentContext with defer_update()
  • Cog systemCog.listener() for event handlers inside cogs, auto-registration of commands
  • Command checksis_owner, has_permissions, has_role, has_any_role, guild_only, dm_only, nsfw, cooldown
  • Global checks@bot.check for prefix-wide validation
  • Invoke hooks@bot.before_invoke / @bot.after_invoke
  • Error eventsSLASH_COMMAND_ERROR, COMMAND_ERROR, COMPONENT_ERROR, MODAL_ERROR
  • Resolved objectsctx.get_user(), ctx.get_channel(), ctx.get_role() from interaction resolved data
  • Moderationbot.mute(), bot.unmute(), bot.set_nickname(), bot.set_slowmode(), bot.purge_messages()
  • Rich embedsEmbed with fluent builder API, embed() shorthand, ctx.send_success() / ctx.send_error()
  • Confirm dialogsctx.confirm() with ConfirmView (auto-responds to interactions)
  • Intents system — bit-flag Intents class with ALL, DEFAULT, ALL_PRIVILEGED
  • Beautiful logging — ANSI-colored formatter, startup banner with bot name/guilds/commands/latency
  • Lazy imports__getattr__-based, no circular dependency issues
  • Rate limiting — per-bucket rate limit handling with X-RateLimit-* header awareness
  • zlib-stream — full zlib-stream gateway decompression with session-persistent decompressor
  • Test mode — interactive CLI REPL for local testing
  • CLIdisquerd init <name> scaffolding

Installation

pip install disquerd

For development:

pip install disquerd[dev]

For performance extras:

pip install disquerd[speed]

Quick Start

Minimal Bot

import disquerd

bot = disquerd.Bot("YOUR_TOKEN")

@bot.slash_command(name="ping", description="Check latency")
async def ping(ctx):
    await ctx.respond("Pong!")

bot.run()

Full-Featured Bot

import disquerd

bot = disquerd.Bot(
    "YOUR_TOKEN",
    intents=disquerd.Intents.default(),
    prefix=["!", "?"],
    case_insensitive=True,
    strip_after_prefix=True,
)

# ── Slash command with options ──

@bot.slash_command(
    name="avatar",
    description="Show user avatar",
    options=[
        {"type": 6, "name": "user", "description": "Which user", "required": False},
    ],
)
async def avatar(ctx):
    target = ctx.get_user("user")
    url = getattr(target, "avatar_url", None)
    if not url:
        return await ctx.send_error("No avatar")
    e = disquerd.Embed(title="Avatar", colour=0x5865F2).set_image(url)
    await ctx.respond(embed=e)


# ── Prefix command with aliases ──

@bot.command(name="hello", aliases=["hi", "hey"])
async def hello(ctx):
    await ctx.reply(f"Hello, <@{ctx.author_id}>!")


# ── Modal with builder ──

@bot.slash_command(name="feedback", description="Send feedback")
async def feedback(ctx):
    m = disquerd.ModalBuilder(title="Feedback", custom_id="fb")
    m.add_text("topic", "Topic", placeholder="What about?")
    m.add_text("body", "Body", style=2, max_length=1000)
    await ctx.show_modal(m.build())


@bot.modal(custom_id="fb")
async def on_feedback(ctx):
    topic = ctx.value("topic", "No topic")
    body = ctx.value("body", "Empty")
    await ctx.respond(f"Thanks! **{topic}**: {body[:200]}")


# ── Button listener ──

@bot.button(custom_id="click_me")
async def on_click(ctx):
    await ctx.update_message(content="Clicked!")


# ── Cog with listener ──

class MyCog(disquerd.Cog):
    @disquerd.Cog.listener(disquerd.EventType.GUILD_MEMBER_ADD)
    async def on_member_join(self, member):
        gid = getattr(member, "guild_id", None)
        if gid:
            await self.bot.rest.create_message(
                channel_id=123456789,
                content=f"Welcome <@{getattr(member, 'id', '?')}>!",
            )

bot.add_cog(MyCog(bot))


# ── Hooks ──

@bot.before_invoke
async def log_cmd(ctx):
    print(f"Command by {ctx.author_id}")

@bot.check
async def global_check(ctx):
    return True


# ── Events ──

@bot.event(disquerd.EventType.READY)
async def on_ready():
    await bot.change_presence(activity={"name": "with disquerd", "type": 0})


@bot.event(disquerd.EventType.SLASH_COMMAND_ERROR)
async def on_slash_err(ctx, error):
    await ctx.send_error(str(error))


bot.run()

Option Types Reference

When defining slash command options, use these type values:

Type Value Description
STRING 3 Text input
INTEGER 4 Whole number
BOOLEAN 5 True/false
USER 6 User (with resolved)
CHANNEL 7 Channel (with resolved)
ROLE 8 Role (with resolved)
MENTIONABLE 9 User or role
NUMBER 10 Floating-point number
ATTACHMENT 11 File attachment

Access resolved objects in command handler:

  • ctx.get_user("option_name") — returns Member or User
  • ctx.get_channel("option_name") — returns Channel
  • ctx.get_role("option_name") — returns Role

Event Types

All EventType enum values available for @bot.event():

Event Description
READY Bot connected and ready
RESUMED Gateway session resumed
MESSAGE_CREATE New message received
MESSAGE_UPDATE Message edited
MESSAGE_DELETE Message deleted
INTERACTION_CREATE Any interaction
GUILD_CREATE Bot joined / guild available
GUILD_UPDATE Guild updated
GUILD_DELETE Bot removed from guild
GUILD_MEMBER_ADD Member joined
GUILD_MEMBER_UPDATE Member updated
GUILD_MEMBER_REMOVE Member left/kicked
GUILD_ROLE_CREATE Role created
GUILD_ROLE_UPDATE Role updated
GUILD_ROLE_DELETE Role deleted
CHANNEL_CREATE Channel created
CHANNEL_UPDATE Channel updated
CHANNEL_DELETE Channel deleted
COMMAND Prefix command invoked
COMMAND_COMPLETION Prefix command completed
COMMAND_ERROR Prefix command errored
SLASH_COMMAND_ERROR Slash command errored
COMPONENT_ERROR Component interaction errored
MODAL_ERROR Modal submit errored

Bot Properties

Property Type Description
user User | None Bot's own user
guilds list[Guild] Cached guilds
application_id int | None Application ID
state State Internal state/cache
rest RESTClient REST API client
cogs dict[str, Cog] Loaded cogs (copy)
modals dict[str, Modal] Registered modals (copy)
button_listeners dict[str, Callable] Button handlers (copy)
username str Bot's display name
avatar_url str | None Bot's avatar URL
mention str Bot's mention string
latency float Heartbeat interval (seconds)
latency_ms float Heartbeat interval (milliseconds)

Architecture

disquerd/
├── client.py          # Bot, Intents
├── gateway.py         # Gateway v10: identify, resume, heartbeat, zlib-stream
├── rest.py            # RESTClient: all REST endpoints
├── state.py           # State: cache + msgspec parsing with ID coercion
├── _http.py           # HTTPClient: rate-limit-aware requests
├── _websocket.py      # WebSocketClient: zlib decompression
├── _registry.py       # Global REST registry (msgspec workaround)
├── _types.py          # Status, EventType, MISSING sentinel
├── log.py             # ANSI formatter, banner, logging setup
├── template.py        # quick(), use_template()
├── test_mode.py       # Interactive REPL test mode
├── commands/
│   ├── core.py        # CommandBase, CooldownMapping
│   ├── slash.py       # SlashCommand
│   ├── prefix.py      # PrefixCommand
│   ├── context.py     # ApplicationContext, ComponentContext, ModalContext, Context
│   ├── context_menu.py # UserCommand, MessageCommand
│   ├── subcommands.py  # SubCommand, SubCommandGroup
│   ├── autocomplete.py # autocomplete decorator
│   ├── checks.py      # is_owner, has_permissions, etc.
│   ├── cog.py         # Cog + Cog.listener()
│   └── converters.py  # UserConverter, ChannelConverter, etc.
├── models/
│   ├── user.py        # User
│   ├── guild.py       # Guild
│   ├── channel.py     # Channel, TextChannel, VoiceChannel, etc.
│   ├── message.py     # Message, Attachment
│   ├── member.py      # Member
│   ├── role.py        # Role
│   ├── emoji.py       # Emoji, PartialEmoji
│   ├── interaction.py # Interaction, InteractionType
│   ├── application.py # ApplicationCommand, ApplicationCommandOption
│   ├── component.py   # Component models
│   ├── extras.py      # AllowedMentions, Thread, Invite, Sticker, etc.
│   └── webhook.py     # Webhook
├── ui/
│   ├── view.py        # View
│   ├── button.py      # Button, ButtonStyle
│   ├── select.py      # SelectMenu, SelectOption
│   ├── modal.py       # Modal, ModalBuilder, TextInput, combine_text_inputs
│   ├── action_row.py  # ActionRow
│   └── components_v2.py # Container, Section, Separator, etc.
├── events/
│   └── dispatch.py    # EventDispatcher
├── errors/
│   ├── gateway.py     # GatewayError
│   ├── rest.py        # RESTError, HTTPError, RateLimitError, etc.
│   └── command.py     # CommandError, CommandCheckFailure, etc.
└── utils/
    ├── snowflake.py   # Snowflake
    ├── cache.py       # Cache, LRUCache, TTLCache
    ├── colour.py      # Colour (int subclass with named constructors)
    ├── embed.py       # Embed, embed() shorthand
    ├── permissions.py # Permissions
    ├── file.py        # File
    ├── pagination.py  # Paginator
    └── confirm.py     # ConfirmView

Logging

By default, Disquerd is silent (WARNING+ level). Enable verbose output:

disquerd.verbose_logging()

Or pass debug=True to Bot():

bot = disquerd.Bot("TOKEN", debug=True)

CLI

# Scaffold a new bot project
disquerd init mybot

# Show version
disquerd version

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

disquerd-0.1.0.tar.gz (57.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

disquerd-0.1.0-py3-none-any.whl (77.2 kB view details)

Uploaded Python 3

File details

Details for the file disquerd-0.1.0.tar.gz.

File metadata

  • Download URL: disquerd-0.1.0.tar.gz
  • Upload date:
  • Size: 57.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for disquerd-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f5f61796d60c488b814cbfb9fe34492807f277f5cc8a5fd746843c39f2ceefc1
MD5 3432aa5fa9d30c1a6db5630cc0bad9f5
BLAKE2b-256 fd9d09ad7f1f7b8f5a0d5fd15b38d1e973a226a4674a7607d005e9c58bf4c5ba

See more details on using hashes here.

File details

Details for the file disquerd-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: disquerd-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 77.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for disquerd-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9778e2ba30ed0c3cf63e6ad2fbfec1ecb7bd41ea8ac00ec5674fd9a32da12679
MD5 e6b217af6c65f754a68354bf7a55bbb1
BLAKE2b-256 aa9da9e2dd03b98307f199e26aecc01ebdbdea8ae7831b7d1f08d36d1140ae38

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page