Skip to content

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, JsonQuery
from scurrypy.enums import EventType

# --- Setup bot ---
client = Client(token=TOKEN)

async def on_ready(event: JsonQuery):
    name: str = event.get('user.username').value
    print(f"{name} is online!")

client.add_event_listener(EventType.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, JsonQuery
from scurrypy.enums import EventType

client = Client(token=TOKEN, intents=Intents.DEFAULT | Intents.MESSAGE_CONTENT)

# --- Setup bot ---
async def on_ping(event: JsonQuery):

    content: str = event.get('content').value

    if not content:
        return

    if not content.startswith('!ping'):
        return

    event_id: int = event.get('channel_id', t=int).value

    await client.channel(event_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, JsonQuery
from scurrypy.api.commands import SlashCommandPart
from scurrypy.enums import EventType, InteractionType

# --- 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: JsonQuery):
    """Respond to /greet"""

    interaction_type: InteractionType = event.get('type', t=InteractionType).value

    if interaction_type != InteractionType.APPLICATION_COMMAND:
        return # ignore non-command interactions

    name: str = event.get('data.name').value

    if name != "greet":
        return

    event_id = event.get('id', t=int).value
    event_token = event.get('token').value
    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, JsonQuery

from scurrypy.api.commands import SlashCommandPart
from scurrypy.api.components import ActionRow, Button
from scurrypy.api.messages import MessagePart

from scurrypy.resources import Interaction
from scurrypy.enums import EventType, ButtonStyle, InteractionType

# --- 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, event: JsonQuery):
    """Handle button_demo slash command."""

    name: str = event.get('data.name').value

    if 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, event: JsonQuery):
    """Handle btn demo custom ID."""

    custom_id: str = event.get('data.custom_id').value

    if custom_id != 'btn_demo':
        return

    await interaction.update(content="You pressed the button!", components=[])

async def dispatch(event: JsonQuery):
    """InteractionEvent is automatically resolved into a concrete interaction type."""

    event_id = event.get('id', t=int).value
    event_token = event.get('token').value

    interaction = client.interaction(event_id, event_token)
    interaction_type = event.get('type', t=InteractionType).value

    if interaction_type == InteractionType.APPLICATION_COMMAND:
        await handle_command(interaction, event)
    elif interaction_type == InteractionType.MESSAGE_COMPONENT:
        await handle_button(interaction, event)

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, JsonQuery
from scurrypy.api.commands import SlashCommandPart
from scurrypy.enums import EventType, InteractionType

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: JsonQuery):
        """Get points for the invoking user."""

        user_id: int = event.get('member.user.id', t=int).value

        async with self.dict_lock:
            pts = self.user_points.get(user_id, 0)

        event_id = event.get('id', t=int).value
        event_token = event.get('token').value

        await self.bot.interaction(event_id, event_token).respond(f"You have {pts} points!")

    async def on_add_points(self, event: JsonQuery):
        """Add points for the invoking user."""

        user_id: int = event.get('member.user.id', t=int).value

        async with self.dict_lock:
            self.user_points[user_id] = self.user_points.get(user_id, 0) + 1

        event_id = event.get('id', t=int).value
        event_token = event.get('token').value

        await self.bot.interaction(event_id, event_token).respond("Point added!")

    async def dispatch(self, event: JsonQuery):
        """Main entry point for commands."""

        interaction_type = event.get('type').transform(InteractionType).value

        if interaction_type != InteractionType.APPLICATION_COMMAND:
            return # ignore non-command interactions

        name: str = event.get('data.name').value

        handler = self.commands.get(name)

        event_id = event.get('id', t=int).value
        event_token = event.get('token').value

        if not handler:
            await self.bot.interaction(event_id, event_token).respond(f"No command named '{name}'!")
            return

        await handler(event)

client = Client(token=TOKEN)

# attach addon to client
StatefulBot(client)

# --- Run the bot ---
client.run()