Core Examples
This section details examples using ScurryPy without scurrypy.ext.
Important
These examples assume you have ScurryPy set up.
If you've missed this part, it is recommended to start here.
Basic Event
Demonstrates responding to the READY event.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.events import ReadyEvent
# --- Setup bot ---
client = Client(token=TOKEN)
async def on_ready(event: ReadyEvent):
print(f"{event.user.username} is online!")
client.add_event_listener("READY", on_ready)
# --- 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.events import EventType, MessageCreateEvent
client = Client(token=TOKEN, intents=Intents.DEFAULT | Intents.MESSAGE_CONTENT)
# --- Setup bot ---
async def on_ping(event: MessageCreateEvent):
if not event.content:
return
if not event.content.startswith('!ping'):
return
await client.channel(event.channel_id).send("Pong!")
client.add_event_listener(EventType.MESSAGE_CREATE, on_ping)
# --- 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.api.commands import SlashCommandPart
from scurrypy.api.interactions import ApplicationCommandDataModel
from scurrypy.events import EventType, InteractionEvent
# --- Setup bot ---
client = Client(token=TOKEN)
async def register_commands():
"""Register slash commands on startup (before READY)."""
await client.guild_command(APP_ID, GUILD_ID).create(
SlashCommandPart("greet", "Greet the bot!")
)
client.add_startup_hook(register_commands)
async def on_greet(event: InteractionEvent):
"""Respond to /greet"""
if not isinstance(event.data, ApplicationCommandDataModel):
return # ignore non-command interactions
if event.data.name != "greet":
return
await client.interaction(event.id, event.token).respond("Hello!")
client.add_event_listener(EventType.INTERACTION_CREATE, on_greet)
# --- 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.commands import SlashCommandPart
from scurrypy.api.interactions import ApplicationCommandDataModel, MessageComponentDataModel
from scurrypy.api.components import ActionRow, Button, ButtonStyle
from scurrypy.api.messages import MessagePart
from scurrypy.resources import Interaction
from scurrypy.events import EventType, InteractionEvent
# --- Setup bot ---
client = Client(token=TOKEN)
async def register_commands():
"""Register slash commands on startup (before READY)."""
await client.guild_command(APP_ID, GUILD_ID).create(
SlashCommandPart('button_demo', 'A command with a button!')
)
client.add_startup_hook(register_commands)
async def handle_command(interaction: Interaction, data: ApplicationCommandDataModel):
"""Handle button_demo slash command."""
if data.name != 'button_demo':
return
await interaction.respond(
MessagePart(
content='Press the button!',
components=[
ActionRow([
Button(ButtonStyle.PRIMARY, 'btn_demo', 'Press me!')
])
]
)
)
async def handle_button(interaction: Interaction, data: MessageComponentDataModel):
"""Handle btn demo custom ID."""
if data.custom_id != 'btn_demo':
return
await interaction.update(content="You pressed the button!", components=[])
async def dispatch(event: InteractionEvent):
"""InteractionEvent is automatically resolved into a concrete interaction type."""
interaction = client.interaction(event.id, event.token)
data = event.data
if isinstance(event.data, ApplicationCommandDataModel):
await handle_command(interaction, data)
elif isinstance(event.data, MessageComponentDataModel):
await handle_button(interaction, data)
client.add_event_listener(EventType.INTERACTION_CREATE, dispatch)
# --- Run the bot ---
client.run()
|
Need to Refresh Your Commands?
Consider deleting your old commands before registering new ones:
| async def refresh_commands():
commands = await client.command(APP_ID, GUILD_ID).fetch_all()
for cmd in commands:
await client.command(APP_ID, GUILD_ID, cmd.id).delete()
# then create your new commands
client.add_startup_hook(refresh_commands)
...
|
If you are using
scurrypy.ext, this should be done for you.
Stateful Bot
Demonstrates grouping state and behavior using a class-based addon.
| # --- Core library imports ---
from scurrypy import Client
from scurrypy.api.commands import SlashCommandPart
from scurrypy.api.interactions import ApplicationCommandDataModel
from scurrypy.events import EventType, InteractionEvent
import asyncio
class StatefulBot:
def __init__(self, client: Client):
self.bot = client
# user registry
self.user_points = {}
self.dict_lock = asyncio.Lock()
# commands registry
self.commands = {
'points': self.on_points,
'addpoints': self.on_add_points
}
# hook up addon to client
client.add_startup_hook(self.register_commands)
client.add_event_listener(EventType.INTERACTION_CREATE, self.dispatch)
async def register_commands(self):
"""Register slash commands on startup (before READY)."""
bot_commands = self.bot.guild_command(APP_ID, GUILD_ID)
commands = [
SlashCommandPart('points', 'Check your points'),
SlashCommandPart('addpoints', 'Give points')
]
for cmd in commands:
await bot_commands.create(cmd)
async def on_points(self, event: InteractionEvent):
"""Get points for the invoking user."""
user_id = event.member.user.id
async with self.dict_lock:
pts = self.user_points.get(user_id, 0)
await self.bot.interaction(event.id, event.token).respond(f"You have {pts} points!")
async def on_add_points(self, event: InteractionEvent):
"""Add points for the invoking user."""
user_id = event.member.user.id
async with self.dict_lock:
self.user_points[user_id] = self.user_points.get(user_id, 0) + 1
await self.bot.interaction(event.id, event.token).respond("Point added!")
async def dispatch(self, event: InteractionEvent):
"""Main entry point for commands."""
if not isinstance(event.data, ApplicationCommandDataModel):
return # ignore non-command interactions
handler = self.commands.get(event.data.name)
if not handler:
await self.bot.interaction(event.id, event.token).respond(f"No command named '{event.data.name}'!")
return
await handler(event)
client = Client(token=TOKEN)
# attach addon to client
StatefulBot(client)
# --- Run the bot ---
client.run()
|