A unified Discord.py utility library — events, rate limiting, UI, permissions, tasks, errors, simulation, and recording.
Project description
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.send — Unified Message Helpers
await wizard.respond(interaction, "Hello", ephemeral=True) # auto followup
await wizard.send(channel, embed=e) # channel or ctx
await wizard.send(interaction, "Hello") # also works
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file discord_wizard-1.5.0rc0.tar.gz.
File metadata
- Download URL: discord_wizard-1.5.0rc0.tar.gz
- Upload date:
- Size: 54.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5760af66b4d1a14daa06573ae90411c408223d46c8f33974e37f5fb21f06a907
|
|
| MD5 |
80a2059219f7138e15be29a5a6f45d18
|
|
| BLAKE2b-256 |
200ba14c5f9a72b9ba415a94eca0b71ec143296d72e2bdc54fd2f1622a1aeae7
|
File details
Details for the file discord_wizard-1.5.0rc0-py3-none-any.whl.
File metadata
- Download URL: discord_wizard-1.5.0rc0-py3-none-any.whl
- Upload date:
- Size: 47.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
edc56178d6df99eda1ffd2c39f8a2332ba95d14846402f986590c52fe0339d9f
|
|
| MD5 |
e07cd818ef25dff0e0235a02052da0ce
|
|
| BLAKE2b-256 |
f11c5c076e11e1d4a476a18ff148051a7673fba64400f8d8aa60bf3ab8d439bb
|