Listeners

discord_ui.listeners

A module for listeners that are going to be attached to a message. You could think of it like a cog but for message components.

from discord_ui import Listener

Usage

To use the Listener class, you need to create a subclass of it

Example

class MyListener(Listener):
    ...

Listeners

To add a button listener, you need to use the Listener.button deorator

class MyListener(Listener):
    ...

    @Listener.button("custom_id here")
    async def somebutton(self, ctx):
        ...

This will add a button listener that will wait for a button with the custom id “custom_id here”

To add a select listener, you need to use the Listener.select decoratorr

class MyListener(Listener):
    ...

    @Listener.select("my_id")
    async def someselect(self, ctx):
        ...

This will add a select menu listener that will wait for a select menu with the custom id “my_id”

You can filter the select callback with the values parameter

class MyListener(Listener):
    ...

    @Listener.select("my_id", values=["2"])
    async def someselect(self, ctx):
        ...

The callback will now be only called if the selected values of a select menu equal to values

There are some more useful things you can use

Class

You can add a timeout to the listener after which the listener will be removed from the message

class MyListener(Listener):
    def __init__(self):
        self.timeout = 20   # 20 seconds timeout

If you set timeout to None, the listener will never timeout

You can also add a list of target users to the listener

class MyListener(Listener):
    def __init__(self):
        self.target_users = [a, list, of, users]

And last but not least, you can supress the discord_ui.listener.NoListenerFound errors when no listener could be found

class MyListener(Listener):
    def __init__(self):
        self.supress_no_listener_found = True

Sending

To send components and add the listener, you can use five different ways

First method:

@bot.listen()
async def on_message(message)
    class MyListener(Listener):
        def __init__(self):
            pass
        @Listener.button("test")
        async def test(self, ctx):
            ...

    await message.channel.send("showcase", components=[Button("this is a showcase", "test")], listener=MyListener())

Second method:

@bot.listen()
async def on_message(message)
    class MyListener(Listener):
        def __init__(self):
            self.components = [Button("this is a showcase", "test")]
        @Listener.button("test")
        async def test(self, ctx):
            ...

    # MyListener.components will be used for the components in the message
    await message.channel.send("showcase", listener=MyListener())

Third method:

@bot.listen()
async def on_message(message)
    class MyListener(Listener):
        def __init__(self):
            ...

        @Listener.button("test")
        async def test(self, ctx):
            ...

    msg = await message.channel.send("showcase", components=[Button("this is a showcase", "test")])
    msg.attach_listener(MyListener())

Fourth method:

ui = discord_ui.UI(bot)

@bot.listen()
async def on_message(message)
    class MyListener(Listener):
        def __init__(self):
            pass
        @Listener.button("test")
        async def test(self, ctx):
            ...

    msg = await message.channel.send("showcase", components=[Button("this is a showcase", "test")])
    ui.components.attach_listener_to(msg, MyListener())

And the last method:

ui = discord_ui.UI(bot)

@bot.listen()
async def on_message(message)
    class MyListener(Listener):
        def __init__(self):
            pass
        @Listener.button("test")
        async def test(self, ctx):
            ...

    msg = await message.channel.send("showcase", components=[Button("this is a showcase", "test")])
    MyListener().attach_me_to(msg)
class discord_ui.listener.Listener(timeout=180.0, target_users=None)
A class for a listener attached to a message that will receive components of it.

To use this class you have to create a subclass inhering this class

class MyListener(Listener)
    ...
timeout: float, optional

A timeout after how many seconds the listener shouold be deleted. If None, the listener will never timeout

target_users: List[discord.Member | discord.User | int | str]

A list of users or user ids from which the interactions has to be be received. Every interaction by other users will be ignored

attach_me_to(message)

Attaches this listener to a message after it was sent

message: Message

The target message

static button(custom_id=None)

A decorator that will setup a callback for a button

custom_id: str, optional
The custom id of the target button. If no custom_id is passed, the name of the callback will be used for the custom id.

Note that you can’t have two callbacks with the same function name

class MyListener(Listener):
    def __init__(self, ...):
        ...

    @Listener.button("my_id")
    async def callback(self, ctx):
        ...
components: List[Union[List[Button, LinkButton, SelectMenu], Button, LinkButton, SelectMenu]]

The components that are going to be send together with the listener

message: Message

The target message

static on_error(exception_cls=<class 'BaseException'>)

Decorator for a function that will handle exceptions

exception_cls: class, optional

The type of the exception that should be handled; default Exception

from discord.ext.commands import CheckFailure

class MyListener(Listener):
    ...
# exception handler for checkfailures
@Listener.on_error(CheckFailure)
async def check_failure(self, ctx, exception):
    await ctx.send("check failed: " + str(exception), hidden=True)
@Listener.on_error(Exception)
async def exception(self, ctx, exception):
    await ctx.send("base exception occured " + str(exception))
async put_me_to(message)

Attaches this listener to a message and edits it if the message is missing components

message: Message

The target message

static select(custom_id=None, values=None)

A decorator that will set a callback up for a select menu

custom_id: str, optional
The custom id of the target menu. If no id specified, the name of the callback will be used.

Note that you can’t have two callbacks with the same function name

values: List[str], optional

What values must be selected in order to invoke the callback; default None

class MyListener(Listener):
def __init__(self, ...)
    ...

@Listener.select("my_id")
async def callback(self, ctx):
    ...

# This callback will be only called if the selected values of the menu are '2' 
@Listener.select("my_id", values=['2'])
async def othere_callback(self, ctx):
    ...
supress_no_listener_found: bool

Whether discord_ui.listener.NoListenerFound should be supressed and not get thrown when no target component listener could be found

property target_users: List[int]

A list of user ids from which the interaction has to come

timeout: float

Timeout after how many seconds the listener should timeout and be deleted

static wrong_user()

Decorator for a function that will be called when a user that is not in .target_users tried to use a component

class MyListener(Listener):
    def __init__(self):
        self.components = [Button()]
        self.target_users = [785567635802816595]
    @Listener.button()
    async def a_button(self, ctx):
        await ctx.send("you are allowed")
    @Listener.wrong_user()
    async def you_wrong(self, ctx):
        await ctx.send("this component is not for you")