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_component(once=False)¶
- @listen_modal¶
- attach_gear(gear)[source]¶
Attaches a gear to this gear.
This will propagate all events from the attached gear to this gear.
- 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:
- Return type:
- 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.
- remove_modal_listener(listener)¶
Unregisters a modal interaction listener.
This method can be used to unregister a previously registered modal interaction listener.
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!")
Modal Interactions¶
Similarly, gears can handle modal submissions using the listen_modal() decorator:
from discord.gears import Gear
from discord import ModalInteraction
from discord.components import PartialLabel, PartialTextInput
class FormGear(Gear):
@Gear.listen_modal("feedback_form")
async def handle_feedback(
self,
interaction: ModalInteraction[
PartialLabel[PartialTextInput],
PartialLabel[PartialTextInput],
],
) -> None:
title = interaction.components[0].component.value
content = interaction.components[1].component.value
await interaction.respond(f"Feedback received: {title}")
@Gear.listen_modal(lambda custom_id: custom_id.startswith("form_"))
async def handle_dynamic_form(self, interaction: ModalInteraction) -> None:
form_id = interaction.custom_id.split("_")[1]
await interaction.respond(f"Processing form {form_id}")
Like component listeners, modal listeners can use string or function predicates and support the once parameter.
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:
Client.attach_gear()- Attach a gear to the clientClient.detach_gear()- Detach a gear from the clientClient.add_listener()- Add an event listener directlyClient.remove_listener()- Remove an event listenerClient.listen()- Decorator to add listeners to the client
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")