Attrs¶
Step-by-Step¶
An example showcasing how attrs utilities can be used with disnake-compass.
Say we wish to create a component, but we do not know the number of options beforehand, and we would like the user to be able to select all of them. It can be cumbersome to manually keep updating the max_values parameter of the select.
@manager.register
async def callback(
self, interaction: disnake.MessageInteraction[disnake.Client]
) -> None:
selection = (
"\n".join(f"- {value}" for value in interaction.values)
if interaction.values
else "nothing :("
)
To create an instance of this select where all options are selectable, we would need to do the following:
options = [...]
select = CustomisableSelect(options=options, max_values=len(options))
Luckily, with the knowledge that disnake-compass is built upon attrs, a few options become available to us.
For this example, we will be making use of attrs classes’ __attrs_post_init__ method, which is called immediately after attrs finishes its normal initialisation logic. If you’re more familiar with dataclasses, this is essentially the same as dataclasses’ similarly named __post_init__ method.
@manager.register
class CustomisableSelect(disnake_compass.RichStringSelect):
def __attrs_post_init__(self) -> None:
self.max_values = len(self.options)
async def callback(
self, interaction: disnake.MessageInteraction[disnake.Client]
) -> None:
selection = (
"\n".join(f"- {value}" for value in interaction.values)
if interaction.values
else "nothing :("
)
This allows the select to be created as follows:
options = [...]
select = CustomisableSelect(options=options)
Then we create our test command and send the previously created customisable select.
1 ephemeral=True,
2 )
3
4
5@bot.slash_command()
6async def make_select(
7 interaction: disnake.CommandInteraction[disnake.Client], options: str
8) -> None:
9 if not options.strip():
10 await interaction.response.send_message("You must specify at least one option!")
11 return
12
13 actual_options = [
14 disnake.SelectOption(label=option.strip())
15 for option in options.split(",")
16 ] # fmt: skip
17
18 if len(actual_options) > 25:
19 await interaction.response.send_message("You must specify at most 25 options!")
If the string is empty or whitespace, the user did not provide options (lines 3-5). Next, we make the options by splitting over commas (lines 7-10). Before creating the component, validate that there’s max 25 options (lines 12-14). Finally, if everything went correctly, we send the component (lines 16-19).
Source Code¶
1"""An example showcasing how attrs utilities can be used with disnake-compass."""
2
3import os
4
5import disnake
6import disnake_compass
7from disnake.ext import commands
8
9bot = commands.InteractionBot()
10
11manager = disnake_compass.get_manager()
12manager.add_to_client(bot)
13
14
15@manager.register
16class CustomisableSelect(disnake_compass.RichStringSelect):
17 def __attrs_post_init__(self) -> None:
18 self.max_values = len(self.options)
19
20 async def callback(
21 self, interaction: disnake.MessageInteraction[disnake.Client]
22 ) -> None:
23 selection = (
24 "\n".join(f"- {value}" for value in interaction.values)
25 if interaction.values
26 else "nothing :("
27 )
28
29 await interaction.response.send_message(
30 f"You selected:\n{selection}",
31 ephemeral=True,
32 )
33
34
35@bot.slash_command()
36async def make_select(
37 interaction: disnake.CommandInteraction[disnake.Client], options: str
38) -> None:
39 if not options.strip():
40 await interaction.response.send_message("You must specify at least one option!")
41 return
42
43 actual_options = [
44 disnake.SelectOption(label=option.strip())
45 for option in options.split(",")
46 ] # fmt: skip
47
48 if len(actual_options) > 25:
49 await interaction.response.send_message("You must specify at most 25 options!")
50 return
51
52 component = await CustomisableSelect(options=actual_options).as_ui_component()
53 await interaction.response.send_message(
54 components=component,
55 )
56
57
58bot.run(os.getenv("EXAMPLE_TOKEN"))