Skip to main content

discord-wizard

A batteries-included utility layer for discord.py. Zero import discord — all 318+ discord.py types re-exported through wizard.*.

from discord.wizard import wizard   # convenience singleton
# or
from discord.wizard import Wizard   # class, if you prefer
w = Wizard()

bt = wizard.Bot(command_prefix="!")  # wizard.bot also works
wizard.enable_stability(bt)

@bt.slash()
async def hello(interaction: wizard.Interaction):
    await wizard.respond(interaction, "Hello!")

Install

pip install discord-wizard

Requires Python 3.10+ and discord.py 2.x (installed automatically).

Why no import discord?

Every public name from discord.py is accessible as wizard.<Name>:

ChannelType, AppInfo, VoiceClient, FFmpegPCMAudio,
StageChannel, ForumChannel, Thread, DMChannel,
Permissions, MemberCacheFlags, AuditLogEntry,
Webhook, Sticker, Emoji, Template, Invite,
ScheduledEvent, AutoModRule, OnboardingPrompt,
Subscription, SKU, Entitlement, Poll, SoundboardSound,
...

All 318+ names. The only exception: wizard replaces Bot and Cog with its own enhanced versions (wizard.Bot / wizard.Cog).

Quick Start

from discord.wizard import wizard

bt = wizard.bot(command_prefix="!", intents=wizard.Intents.all())
wizard.enable_stability(bt)  # crash protection, auto-restart tasks, graceful shutdown


# ── Slash command with permission check ──────────────────────────────
@bt.slash()
@wizard.require("admin")
async def panel(interaction: wizard.Interaction):
    """Deploy a button panel."""
    p = wizard.Panel(title="Menu", buttons=[
        wizard.Button(label="Click me", style="primary",
                      callback=lambda i: wizard.respond(i, "Clicked!")),
    ])
    await p.send(interaction)


# ── Prefix command with type hints ──────────────────────────────────
@bt.cmd()
async def status(ctx, member: wizard.Member):
    e = wizard.embed(f"{member} Status", color="blue", fields=[
        ("ID", str(member.id)),
        ("Joined", str(member.joined_at)),
    ])
    await wizard.send(ctx, embed=e)


# ── Event with filter ──────────────────────────────────────────────
@wizard.on("member_join", guild_id=12345)
async def welcome(member):
    await member.send(f"Welcome {member.mention}!")


# ── Scheduled task ──────────────────────────────────────────────────
@wizard.every("30m")
async def clean_cache():
    print("Cache cleaned")


bt.run("TOKEN")

Module Overview

wizard.on — Event Decorators

Three syntaxes, same result:

@wizard.on("member_join")           # string — simplest
@wizard.on.member_join              # flat attribute
@wizard.on.member.join              # grouped attribute

@wizard.on("member_join", guild_id=12345)  # with filter

Available events: member_join/leave/ban/unban, message_create/delete/edit, voice_join/leave/move, role_create/delete/add, reaction_add/remove.

wizard.require — Permission Decorators

@wizard.require("admin")               # built-in level
@wizard.require("role:Admin")          # role name
@wizard.require_any("mod", "admin")    # any of
@wizard.require_all("admin", "owner")  # all of
@wizard.require_custom(lambda m: m.id == 123)
wizard.configure_permissions(guild_id, roles={"admin": ["Admin", "Staff"]})

wizard.ui — Declarative UI Components

# Form (modal)
form = wizard.Form(title="Feedback", fields=[
    wizard.TextInput(label="Name", max_length=50),
    wizard.TextInput(label="Message", style="long"),
], on_submit=callback)
await form.send(interaction)

# Panel (button group)
panel = wizard.Panel(title="Actions", buttons=[
    wizard.Button(label="Save", style="success", callback=save_fn),
    wizard.Button(label="Delete", style="danger", callback=del_fn),
])
await panel.send(interaction)        # respond to interaction
await panel.send_to(channel, embed=e)  # send to channel

# Other components: Dropdown, MultiSelect, Tabs, Paginator

wizard.tasks — Task Scheduling

@wizard.every("5m")
@wizard.cron("0 */6 * * *")
@wizard.at("09:00", timezone="US/Eastern")
# retry=3, retry_delay=10, on_error=handler

wizard.embed — One-Shot Embed Builder

e = wizard.embed("Title", "Description", color="green", fields=[
    ("Name", "Value", True),   # (name, value, inline)
    ("Name2", "Value2"),       # inline defaults to False
])

Colors accept strings: "blue", "green", "red", "#5865F2", 0x5865F2.

wizard.respond / wizard.reply / wizard.send — Unified Message Helpers

await wizard.respond(interaction, "Hello", ephemeral=True)  # auto followup
await wizard.reply(interaction, "Hello")                    # shorter alias
await wizard.send(channel, embed=e)                         # channel or ctx
await wizard.send(interaction, "Hello")                     # also works

wizard.color() — String Color Resolver

wizard.color("green")      # Color.green()
wizard.color("#5865F2")    # Color.from_str()
wizard.color(0x5865F2)     # Color(0x5865F2)
wizard.color("random")     # Color.random()

Simple Formatting Helpers

wizard.bold("text")        # **text**
wizard.italic("text")      # *text*
wizard.underline("text")   # __text__
wizard.strike("text")      # ~~text~~
wizard.spoiler("text")     # ||text||
wizard.code("text")        # `text`
wizard.codeblock("code", "py")  # ```py\ncode\n```
wizard.quote("text")       # > text
wizard.link("label", "url")     # [label](url)

Mention & Timestamp Helpers

wizard.mention(user)             # <@user_id>
wizard.mention_channel(channel)  # <#channel_id>
wizard.mention_role(role)        # <@&role_id>
wizard.ts(datetime, style="R")   # <t:1234567890:R>
# Styles: R=relative, d=short date, D=long date, t=short time, T=long time, f=short datetime, F=long datetime

Constructor Helpers

wizard.intents(all=True)                  # Intents.all()
wizard.intents(messages=True, members=True)  # specific flags
wizard.perms(kick_members=True)           # Permissions(...)
wizard.activity("Playing Minecraft")      # Activity(playing, "Minecraft")
wizard.activity("Listening to Lofi", type="listening")
wizard.file("image.png")                  # File("image.png")
wizard.obj(123456789)                     # Object(123456789)
wizard.mentions(users=True, roles=True)   # AllowedMentions(...)

UI Shortcuts

wizard.button("Click", style="primary")     # Button
wizard.button("Danger", style="danger")     # red button
wizard.select(["A", "B", "C"], placeholder="Pick")
wizard.select([{"label":"X","value":"1"}])

wizard.rateguard — Rate Limit Protection

wizard.enable_rateguard(bt, warn_at=0.8, max_retries=3)
print(wizard.rateguard_stats())  # {requests_sent: 42, ...}

wizard.errors — Error Formatting

wizard.enable_errors(bt, embed_mode=True)  # formats errors as embeds
print(wizard.format_terminal(error))         # structured terminal output

wizard.stability — Crash Protection (one-call)

wizard.enable_stability(bt)
# Crash-proof dispatch, safe tree.on_error, task auto-restart,
# connection health monitoring, graceful SIGINT/SIGTERM shutdown

wizard.simulate — Offline Bot Testing

discord-wizard simulate --port 8321  # web UI at localhost:8321
from discord.wizard import wizard

async def test():
    client = wizard.MockClient()
    result = await client.send("!hello")
    print(result.calls)

wizard.recorder — Event Recording

rec = wizard.Recorder(backend=wizard.SQLiteStore("bot.db"))
session = await rec.session.start(name="test")
# ... bot runs ...
await rec.session.stop()
await rec.export_json("log.json")

Backends: MemoryStore, SQLiteStore, PostgreSQLStore.

Discord.py Re-exports (all 318+)

Every public name from discord.py is accessible as wizard.<Type> — no import discord needed:

Channel types: TextChannel, VoiceChannel, CategoryChannel, StageChannel, ForumChannel, Thread, DMChannel, GroupChannel, PartialMessageable

Models: Member, User, Guild, Role, Message, Interaction, Embed, Emoji, Sticker, StickerPack, Webhook, Template, Invite, AppInfo, PartialAppInfo, ClientUser, Team, TeamMember, BanEntry, AuditLogEntry, AuditLogDiff, ScheduledEvent, AutoModRule, AutoModTrigger, Onboarding, OnboardingPrompt, Poll, Entitlement, SKU, Subscription, SoundboardSound

Enums: ChannelType, VideoQualityMode, VoiceRegion, NotificationLevel, ContentFilter, VerificationLevel, MFALevel, NSFWLevel, PrivacyLevel, EntityType, EventStatus, StickerType, StickerFormatType, AppCommandType, InteractionType, ComponentType, ButtonStyle, TextStyle, MessageType, AuditLogAction, AuditLogActionCategory, AutoModRuleEventType, AutoModRuleTriggerType, ForumLayoutType, ForumOrderType, InviteTarget, Locale, SKUType, SubscriptionStatus, WebhookType, EntitlementType, EntitlementOwnerType

Flags: Permissions, PermissionOverwrite, Intents, MemberCacheFlags, MemberFlags, MessageFlags, ChannelFlags, SystemChannelFlags, ApplicationFlags, PublicUserFlags, UserFlags, RoleFlags, AttachmentFlags, SKUFlags, InviteFlags, EmbedFlags

Exceptions: DiscordException, HTTPException, Forbidden, NotFound, InvalidData, ClientException, LoginFailure, GatewayNotFound, ConnectionClosed, PrivilegedIntentsRequired, InteractionResponded, RateLimited, DiscordServerError, MissingApplicationID, FFmpegProcessError

Voice: VoiceClient, VoiceProtocol, VoiceState, FFmpegPCMAudio, FFmpegOpusAudio, PCMAudio, PCMVolumeTransformer, AudioSource, opus

And everything else: Color, Colour, File, Asset, Object, Activity, Game, Status, CustomActivity, Spotify, Streaming, SelectOption, View, Button, ActionRow, TextInput, Component, AllowedMentions, PartialMessage, MessageReference, Reaction, ShardInfo, SessionStartLimits, Widget, WelcomeScreen, Integration, BotIntegration, StreamIntegration, IntegrationAccount, IntegrationApplication, VoiceChannelEffect, SoundboardDefaultSound, Container, Collectible, RoleTags, RoleSubscriptionInfo, ThreadMember, StageInstance, GuildPreview, GuildProductPurchase, PrimaryGuild, UnfurledMediaItem, MediaGalleryItem, CallMessage, DeletedReferencedMessage, MessageInteraction, MessageInteractionMetadata, MessageSnapshot, MessageApplication, RawMemberRemoveEvent, RawMessageDeleteEvent, RawMessageUpdateEvent, RawBulkMessageDeleteEvent, RawReactionActionEvent, RawReactionClearEvent, RawReactionClearEmojiEvent, RawTypingEvent, RawPresenceUpdateEvent, RawIntegrationDeleteEvent, RawThreadDeleteEvent, RawThreadMembersUpdate, RawThreadUpdateEvent, RawPollVoteActionEvent, RawAppCommandPermissionsUpdateEvent, PartialEmoji, PartialIntegration, PartialInviteChannel, PartialInviteGuild, PartialWebhookChannel, PartialWebhookGuild, SyncWebhook, SyncWebhookMessage, BaseActivity, BaseSoundboardSound, CustomActivity, `SpeakingState

Syntax Comparison

Pattern Raw discord.py Wizard
Event @bot.event / def on_member_join(m) @wizard.on("member_join")
Event filter Custom check function @wizard.on("member_join", guild_id=123)
Embed 3+ lines wizard.embed("T", fields=[...], color="blue")
Interaction response Check + followup + send_message wizard.respond(i, "msg", ephemeral=True)
Send (any target) Type check + different methods wizard.send(target, embed=e)
Color Color.blue(), Color.from_str() color="blue" or color="#5865F2"
Permissions Custom decorator @wizard.require("admin")
Task scheduling asyncio + manual @wizard.every("5m")

Import Styles

from discord.wizard import wizard   # singleton — most common
wizard.Bot(command_prefix="!", intents=wizard.Intents.all())

from discord.wizard import Wizard   # class — explicit
w = Wizard()
w.Bot(command_prefix="!", intents=w.Intents.all())

Both are equivalent. The singleton wizard is pre-instantiated and ready to use.

License

MIT

Metadata

Release files for discord-wizard 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for discord-wizard 1.5.0
File Size Uploaded
discord_wizard-1.5.0.tar.gz 56.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for discord-wizard 1.5.0
File Interpreter ABI Platform
discord_wizard-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 105.5 kB

Release files / discord_wizard-1.5.0.tar.gz

Download URL discord_wizard-1.5.0.tar.gz
Size 56.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5eaa3d24f8edeea3eae04b5ca715cf5efdcb43be80ee279e8f16435e388e6332
BLAKE2b-256 checksum
How to use checksums
8fcaee6258aff85423895863124d729d97d7246edb6b6bf228d3bd4384be022e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / discord_wizard-1.5.0-py3-none-any.whl

Download URL discord_wizard-1.5.0-py3-none-any.whl
Size 49.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8c953d45e30292f6736afcfdf27dbe8c86e3f8a6e0d8f3a2d07797f1115b0bf
BLAKE2b-256 checksum
How to use checksums
42863f72f491e4e2de161bfdc6fb00d195a5c961dc5c396d72f0c2258c9f4a61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 release files

1.1.0

1 release file

1.0.0

1 release file

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page