Better Event Handling

Curious comes with several ways to fine-tune your event handling in your bot.


A full list of events can be found at Event reference.

Basic Event Listeners

Basic event listeners are the easiest way to handle events coming in from the bot. All event listeners take a EventContext as their first argument, and various other arguments depending on the event.

# simple client event
async def member_joined(ctx, member: Member):
    print("Member",, "joined!")

Basic event listeners can also be inside plugins:

from curious import event

class MyPlugin(Plugin):
    async def member_joined(self, ctx, member: Member):
        print("Member",, "joined!")

You can also add them manually to the event manager, but you must decorate them with the event() decorator.

from curious import event

async def member_joined(ctx, member: Member):
    print("Member",, "joined!")

The event decorator sets some attributes on on the function object that are introspected to register the event handler.

Finally, you can have multiple events on one function, but this is usually discouraged in favour of Event Hooks.

async def my_function(ctx): ...

Temporary Listeners

Temporary listeners are a way of listening to an event temporarily until a condition happens. This is used to implement waiting for a specific event, for example.

A listener is roughly the same as an event handler, but only sticks around for a short while; that is, until it either raises an exception (which is logged) or it raises ListenerExit. Either one will remove it from the list of temporary listeners; and it will not get any more events.

To add a listener, you can use EventManager.add_temporary_listener():

# example: adding messages to a queue until STOP is sent
async def message_listener(ctx, message: Message):
    if message.content == "STOP":
        raise ListenerExit

    await my_queue.add(message)"message_create", message_listener)

If you wish to remove a listener early, then you can do so with EventManager.remove_listener_early(); however, it is probably better to use ListenerExit appropriately.

Waiting For Events

Waiting for events from the websocket is a common usecase; curious provides some helper methods to allow waiting for these events easily.

  • EventManager.wait_for() allows waiting for an event based on a predicate.
  • EventManager.wait_for_manager() is a context-manager version of wait_for.

Both of these methods take an event name to listen to, and a predicate that should return True/False based on if this is an event you want. The return result of wait_for is the normal arguments provided to the event, without the EventContext.

pred = lambda message: message.content == "STOP"
stop_message = await client.wait_for("message_create", pred)  # shortcut for EventManager

EventManager.wait_for_manager() is not often useful inside user code.

Event Hooks

The final way of managing events is with event hooks. These are hooks that are called upon every single event fired by the event manager, and can be useful for sub-dispatchers that filter events. To register an event hook, use EventManager.add_event_hook().

async def my_hook(ctx: EventContext, *args):
    if ctx.event_name.startswith("guild_"):
        # do something


An event hook crashing will bring down the entire bot. Be warned.