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)
| File | Size | Uploaded | |
|---|---|---|---|
| discord_wizard-1.5.0.tar.gz | 56.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|