Examples
The following examples use the scurrypy.ext module.
Basic Event
Demonstrates responding to the READY event.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.events import EventType, ReadyEvent
from scurrypy.ext.events import EventsAddon
# --- Setup bot ---
client = Client(token=TOKEN)
events = EventsAddon(client)
@events.listen(EventType.READY)
async def on_ready(bot: Client, event: ReadyEvent):
print(f"{event.user.username} is online!")
# --- Run the bot ---
client.run()
|
Basic Prefix Command
Demonstrates registering and responding to a prefix command.
Legacy
While prefix commands are supported, they are deemed a legacy feature.
Discord encourages using interactions. See the next example.
| # --- Core library imports ---
from scurrypy import Client, Intents
from scurrypy.ext.prefixes import PrefixAddon, PrefixCommandContext
client = Client(token=TOKEN, intents=Intents.DEFAULT | Intents.MESSAGE_CONTENT)
prefixes = PrefixAddon(client, APP_ID, '!')
# --- Setup bot ---
@prefixes.listen('ping')
async def on_ping(ctx: PrefixCommandContext):
await ctx.send("Pong!")
# --- Run the bot ---
client.run()
|
Basic Slash Command
Demonstrates registering and responding to a slash command interaction.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.ext.commands import CommandsAddon, ApplicationCommandContext
# --- Setup bot ---
client = Client(token=TOKEN)
commands = CommandsAddon(client, APP_ID)
@commands.slash_command('greet', 'Greet the bot!', guild_ids=[GUILD_ID])
async def on_greet(ctx: ApplicationCommandContext):
await ctx.respond("Hello!")
# --- Run the bot ---
client.run()
|
About guild commands
Guild commands appear instantly when registered to a guild.
Global commands can take up to 1 hour to propagate.
Component Interactions
Demonstrates building and responding to a button interaction.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.api.components import ActionRow, Button, ButtonStyle
from scurrypy.api.messages import MessagePart
from scurrypy.ext.commands import CommandsAddon, ApplicationCommandContext
from scurrypy.ext.components import ComponentsAddon, MessageComponentContext
# --- Setup bot ---
client = Client(token=TOKEN)
commands = CommandsAddon(client, APP_ID)
components = ComponentsAddon(client)
@commands.slash_command('button_demo', 'Button demo!', guild_ids=[GUILD_ID])
async def handle_command(ctx: ApplicationCommandContext):
await ctx.respond(
MessagePart(
content='Press the button!',
components=[
ActionRow([
Button(ButtonStyle.PRIMARY, 'btn_demo', 'Press me!')
])
]
)
)
@components.button('btn_demo')
async def handle_button(ctx: MessageComponentContext):
await ctx.update(content="You pressed the button!", components=[])
# --- Run the bot ---
client.run()
|
Stateful Bot
Demonstrates grouping state and behavior using a class-based addon.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.ext.commands import CommandsAddon, ApplicationCommandContext
# --- Setup bot and addons ---
client = Client(token=TOKEN)
commands = CommandsAddon(client, APP_ID)
user_points = {}
import asyncio
dict_lock = asyncio.Lock()
@commands.slash_command("points", "Check your points", guild_ids=[GUILD_ID])
async def points(ctx: ApplicationCommandContext):
async with dict_lock:
pts = user_points.get(ctx.user.id, 0)
await ctx.respond(f"You have {pts} points!")
@commands.slash_command("addpoints", "Give points", guild_ids=[GUILD_ID])
async def addpoints(ctx: ApplicationCommandContext):
async with dict_lock:
user_points[ctx.user.id] = user_points.get(ctx.user.id, 0) + 1
await ctx.respond("Point added!")
# --- Run the bot ---
client.run()
|
Handling Command Errors
Demonstrates handling invalid user input inside a prefix command.
Tip
By default, ScurryPy catches unhandled command errors and logs a traceback.
The bot will not crash.
| from scurrypy import Client, Intents
from scurrypy.ext.prefixes import PrefixAddon, PrefixCommandContext
client = Client(token=TOKEN, intents=Intents.DEFAULT | Intents.MESSAGE_CONTENT)
prefixes = PrefixAddon(client, APP_ID, '!')
@prefixes.listen('divide')
async def divide(ctx: PrefixCommandContext):
try:
a = int(ctx.args[0])
b = int(ctx.args[1])
await ctx.send(f"{a}/{b} = {a/b:.2f}")
except ZeroDivisionError:
await ctx.send("The second value cannot be zero!")
except IndexError:
await ctx.send("This command requires 2 numbers! Try `!divide 6 3`")
except ValueError:
await ctx.send("Command args must be integers!")
client.run()
|
Role Restricted Command
Demonstrates a command needing a certain role to use.
| from scurrypy import Client
from scurrypy.ext.commands import CommandsAddon, ApplicationCommandContext
# Set EXCLUSIVE_ROLE_ID to ID of role in which command is available.
client = Client(token=TOKEN)
commands = CommandsAddon(client, APP_ID)
@commands.slash_command('exclusive', 'Only certain roles can use this command!', guild_ids=[GUILD_ID])
async def on_exclusive(ctx: ApplicationCommandContext):
if not EXCLUSIVE_ROLE_ID in ctx.member.roles:
await ctx.respond(f"You need the <@&{EXCLUSIVE_ROLE_ID}> role to use this command!", ephemeral=True)
return
# ephemeral because its a secret!
await ctx.respond("Welsh Myth Secret: Corgis were once ridden by faries!", ephemeral=True)
client.run()
|
Background Task
ScurryPy uses standard asyncio tasks for background jobs.
| from scurrypy import Client
client = Client(token=TOKEN)
import asyncio
async def my_task():
while True:
print("Running background task...")
await asyncio.sleep(5)
async def start_my_task():
asyncio.create_task(my_task())
client.add_startup_hook(start_my_task)
client.run()
|
Modals
Demonstrates submitting feedback with the modal.
| from scurrypy import Client
from scurrypy.api.interactions import ModalPart
from scurrypy.api.components import Label, TextInput, TextInputStyle
from scurrypy.ext.commands import CommandsAddon, ApplicationCommandContext
from scurrypy.ext.components import ComponentsAddon, ComponentModalContext
client = Client(token=TOKEN)
commands = CommandsAddon(client, APP_ID)
components = ComponentsAddon(client)
@components.modal("feedback_modal")
async def on_feedback(ctx: ComponentModalContext):
feedback = ctx.data.get_modal_data("feedback_input")
await ctx.respond(f"Thanks for your feedback:\n{feedback}", ephemeral=True)
@commands.slash_command("feedback", "Send feedback", guild_ids=[GUILD_ID])
async def feedback(ctx: ApplicationCommandContext):
feedback_input = Label(
label="Your feedback",
component=TextInput(
custom_id="feedback_input",
style=TextInputStyle.PARAGRAPH,
placeholder="Type something...",
required=True
)
)
modal = ModalPart(
title="Feedback Form",
custom_id="feedback_modal",
components=[feedback_input]
)
await ctx.respond_modal(modal)
client.run()
|
More Examples...
Want more control?
Check out core examples.
Want more customization?
Check out using Addons.
Ready for a challenge?
Check out advanced patterns.