Gears

Gears are a modular event handling system in Pycord that allow you to organize your event listeners into reusable components. They provide a clean way to structure event-driven code and enable composition by allowing gears to be attached to other gears or to the bot itself.

Gear

class discord.gears.Gear[source]

A gear is a modular component that can listen to and handle events.

You can subclass this class to create your own gears and attach them to your bot or other gears.

Example

@listen(once=False)[source]
Parameters:
Return type:

Callable[[Callable[[Any, TypeVar(E, bound= Event, covariant=True)], Awaitable[None]]], EventListener[TypeVar(E, bound= Event, covariant=True)]]

@listen_component(once=False)
Parameters:
Return type:

Callable[[Callable[[Any, ComponentInteraction[Any]], Awaitable[None]]], ComponentListener]

@listen_modal
Parameters:

predicate (Union[Callable[[str], bool | Awaitable[bool]], str])

Return type:

Callable[[Callable[[Any, ModalInteraction[Unpack[tuple[Any, ...]]]], Awaitable[None]]], ModalListener]

attach_gear(gear)[source]

Attaches a gear to this gear.

This will propagate all events from the attached gear to this gear.

Parameters:

gear (Gear) – The gear to attach.

Return type:

None

detach_gear(gear)[source]

Detaches a gear from this gear.

Parameters:

gear (Gear) – The gear to detach.

Raises:

KeyError – If the gear is not attached.

Return type:

None

add_listener(callback, *, event=Undefined.MISSING, is_instance_function=False, once=False)[source]

Adds an event listener to the gear.

Parameters:
  • callback (Callable[[TypeVar(E, bound= Event, covariant=True)], Awaitable[None]]) – The callback function to be called when the event is emitted.

  • event (type[TypeVar(E, bound= Event, covariant=True)] | Undefined) – The type of event to listen for. If not provided, it will be inferred from the callback signature.

  • once (bool) – Whether the listener should be removed after being called once.

  • is_instance_function (bool) – Whether the callback is an instance method (i.e., it takes the gear instance as the first argument).

Returns:

The registered listener. Use this to unregister the listener.

Return type:

EventListener

Raises:

TypeError – If the event type cannot be inferred from the callback signature.

remove_listener(listener, event=Undefined.MISSING, is_instance_function=False)[source]

Removes an event listener from the gear.

Parameters:
  • listener (EventListener[TypeVar(E, bound= Event, covariant=True)]) – The EventListener instance to be removed.

  • event (type[TypeVar(E, bound= Event, covariant=True)] | Undefined) – The type of event the listener was registered for. If not provided, it will be inferred from the callback signature. Only required if passing a callback instead of an EventListener.

  • is_instance_function (bool) – Whether the callback is an instance method (i.e., it takes the gear instance as the first argument).

Raises:
  • TypeError – If the event type cannot be inferred from the callback signature.

  • KeyError – If the listener is not found.

Return type:

None

add_component_listener(predicate, listener, once=False)

Registers a component interaction listener.

This method can be used to register a function that will be called when a component interaction occurs that matches the provided predicate.

Parameters:
  • predicate (Union[Callable[[str], bool | Awaitable[bool]], str]) – A (potentially async) function that takes a string (the component’s custom ID) and returns a boolean indicating whether the function should be called for that component. Alternatively, a string can be provided, which will match the component’s custom ID exactly.

  • listener (Union[Callable[[ComponentInteraction[Any]], Awaitable[Any]], Callable[[Any, ComponentInteraction[Any]], Awaitable[Any]]]) – The interaction callback to call when a component interaction occurs that matches the predicate.

  • once (bool) – Whether to unregister the listener after it has been called once.

Returns:

The registered listener. Use this to unregister the listener.

Return type:

ComponentListener

add_modal_listener(predicate, listener, once=False)

Registers a modal interaction listener.

This method can be used to register a function that will be called when a modal interaction occurs that matches the provided predicate.

Parameters:
  • predicate (Union[Callable[[str], bool | Awaitable[bool]], str]) – A (potentially async) function that takes a string (the modal’s custom ID) and returns a boolean indicating whether the function should be called for that modal. Alternatively, a string can be provided, which will match the modal’s custom ID exactly.

  • listener (Union[Callable[[ModalInteraction[Unpack[tuple[Any, ...]]]], Awaitable[Any]], Callable[[Any, ModalInteraction[Unpack[tuple[Any, ...]]]], Awaitable[Any]]]) – The interaction callback to call when a modal interaction occurs that matches the predicate.

  • once (bool) – Whether to unregister the listener after it has been called once.

Returns:

The registered listener. Use this to unregister the listener.

Return type:

ModalListener

remove_component_listener(listener)

Unregisters a component interaction listener.

This method can be used to unregister a previously registered component interaction listener.

Parameters:

listener (ComponentListener) – The listener to unregister.

Raises:

KeyError – If the listener is not registered.

Return type:

None

remove_modal_listener(listener)

Unregisters a modal interaction listener.

This method can be used to unregister a previously registered modal interaction listener.

Parameters:

listener (ModalListener) – The listener to unregister.

Raises:

KeyError – If the listener is not registered.

Return type:

None

Basic Usage

Creating a Gear

You can create a gear by subclassing discord.gears.Gear and using the listen() decorator to register event listeners:

from discord.gears import Gear
from discord.events import Ready, MessageCreate

class MyGear(Gear):
    @Gear.listen()
    async def on_ready(self, event: Ready) -> None:
        print(f"Bot is ready!")

    @Gear.listen()
    async def on_message(self, event: MessageCreate) -> None:
        print(f"Message: {event.content}")

Attaching Gears

Gears can be attached to a Client or Bot using the attach_gear() method:

bot = discord.Bot()
my_gear = MyGear()
bot.attach_gear(my_gear)

You can also attach gears to other gears, creating a hierarchy:

parent_gear = MyGear()
child_gear = AnotherGear()
parent_gear.attach_gear(child_gear)

Instance Listeners

You can also add listeners to a gear instance dynamically:

my_gear = MyGear()

@my_gear.listen()
async def on_guild_join(event: GuildJoin) -> None:
    print(f"Joined guild: {event.guild.name}")

Advanced Usage

One-Time Listeners

Use the once parameter to create listeners that are automatically removed after being called once:

class MyGear(Gear):
    @Gear.listen(once=True)
    async def on_first_message(self, event: MessageCreate) -> None:
        print("This will only run once!")

Component Interactions

Gears can handle component interactions (buttons, select menus, etc.) using the listen_component() decorator:

from discord.gears import Gear
from discord import ComponentInteraction

class ButtonGear(Gear):
    @Gear.listen_component("my_button")
    async def handle_button(self, interaction: ComponentInteraction) -> None:
        await interaction.respond("Button clicked!")

    @Gear.listen_component(lambda custom_id: custom_id.startswith("page_"))
    async def handle_pagination(self, interaction: ComponentInteraction) -> None:
        page = interaction.custom_id.split("_")[1]
        await interaction.respond(f"Navigating to page {page}")

The predicate can be:

  • A string for exact custom ID matching

  • A function (sync or async) that takes a custom ID and returns a boolean

You can also add component listeners to gear instances:

my_gear = ButtonGear()

@my_gear.listen_component("instance_button")
async def handle_instance_button(interaction: ComponentInteraction) -> None:
    await interaction.respond("Instance button clicked!")

Manual Listener Management

You can manually add and remove listeners using add_listener() and remove_listener():

from discord.events import MessageCreate

async def my_listener(event: MessageCreate) -> None:
    print(f"Message: {event.content}")

gear = MyGear()
gear.add_listener(my_listener, event=MessageCreate)

# Later, remove it
gear.remove_listener(my_listener, event=MessageCreate)

Detaching Gears

Remove a gear using detach_gear():

bot.detach_gear(my_gear)

Client and Bot Integration

Both Client and Bot provide gear-related methods:

These methods work identically to their Gear counterparts.

Example: Modular Bot Structure

Here’s an example of using gears to create a modular bot:

from discord import Bot
from discord.gears import Gear
from discord.events import Ready, MessageCreate, GuildJoin

class LoggingGear(Gear):
    @Gear.listen()
    async def log_ready(self, event: Ready) -> None:
        print("Bot started!")

    @Gear.listen()
    async def log_messages(self, event: MessageCreate) -> None:
        print(f"[{event.channel.name}] {event.author}: {event.content}")

class ModerationGear(Gear):
    @Gear.listen()
    async def welcome_new_guilds(self, event: GuildJoin) -> None:
        system_channel = event.guild.system_channel
        if system_channel:
            await system_channel.send("Thanks for adding me!")

bot = Bot()

# Attach gears to the bot
bot.attach_gear(LoggingGear())
bot.attach_gear(ModerationGear())

bot.run("TOKEN")