discord.py icon indicating copy to clipboard operation
discord.py copied to clipboard

Multiple selects error

Open Randomneo opened this issue 3 years ago • 7 comments

Summary

master commit breaks multiple selects

Reproduction Steps

this commit provides global state for Select object

Minimal Reproducible Code

No response

Expected Results

No global state

Actual Results

global state

Intents

...

System Information

...

Checklist

  • [X] I have searched the open issues for duplicates.
  • [X] I have shown the entire traceback, if possible.
  • [X] I have removed my token from display, if visible.

Additional Context

No response

Randomneo avatar Aug 09 '22 16:08 Randomneo

I have this problem too :/

chredeur avatar Aug 09 '22 18:08 chredeur

Could you give more context to the issue? The actual behavior you're experiencing? Code to reproduce it?

The commit goal was to remove global state, which I believe it did successfully, solving race conditions as described in the PR. I'm fairly sure I tested this before submitting the PR, just tested again and I'm not experiencing any issues.

Test code:

# generate 4 options labeled 1-4
options = [SelectOption(label=f'option {n}') for n in range(1, 5)]

class Select(ui.Select):
    async def callback(self, interaction: Interaction):
        original = self.values[0]
        await interaction.response.defer()
        await asyncio.sleep(10)
        after_sleep = self.values[0]
        await interaction.followup.send(f'{original = }\n{after_sleep = }')

class View(ui.View):
    def __init__(self):
        super().__init__()
        self.add_item(Select(options=options[:2]))  # first select has options 1 and 2
        self.add_item(Select(options=options[2:]))  # second select has options 3 and 4

In quick succession, all before the first followup was sent, I selected in order: "option 1" from the first select "option 4" from the second select "option 2" from the first select And these were the resulting followups: image

EDIT: I also repeated this test with both selects using @ui.select() inside the view and with one a subclass, one decorated. Both gave the same result as the initial test where both were using the subclass.

sgtlaggy avatar Aug 09 '22 19:08 sgtlaggy

import sys

import discord
from discord import Intents
from discord.ext import commands

bot = commands.Bot(command_prefix='/', intents=Intents.all())


@bot.tree.command()
async def create_event(interaction: discord.Interaction):
    '''
    Creates embed message for event on server
    '''
    event_category = list(
        filter(lambda x: 'event' in x.name.lower(), interaction.guild.categories)
    )[0]

    class TestModal(discord.ui.Modal, title='Test Modal'):
        text_channel = discord.ui.Select(
            options=[
                discord.SelectOption(label=channel.name, value=channel.id)
                for channel in event_category.text_channels
            ],
            placeholder='Channel for event message',
        )
        voice_channel = discord.ui.Select(
            options=[
                discord.SelectOption(label=channel.name, value=channel.id)
                for channel in event_category.voice_channels
            ],
            min_values=0,
            placeholder='Voice channel for auto connect button',
        )

        async def on_submit(self, interaction: discord.Interaction):
            await interaction.guild.get_channel(int(self.text_channel.values[0])).send(
                content='test',
            )
            await interaction.response.send_message('message added', ephemeral=True)

    await interaction.response.send_modal(TestModal())


def run():
    bot.run('TOKEN')


if __name__ == '__main__':
    run()
    sys.exit(0)

Error:

Traceback (most recent call last):
  File "/home/randomneo/.virtualenvs/discord-edge/lib/python3.10/site-packages/discord/ui/modal.py", line 184, in _scheduled_task
    await self.on_submit(interaction)
  File "/home/randomneo/projects/personal/fucking-discord/main.py", line 37, in on_submit
    await interaction.guild.get_channel(int(self.text_channel.values[0])).send(
IndexError: list index out of range

If redefine function Modal._refresh to prevent calling of second item._refresh_state then no error

    def _refresh(self, components: Sequence[ModalSubmitComponentInteractionDataPayload]) -> None:
        for component in components:
            if component['type'] == 1:
                self._refresh(component['components'])
                return
            else:
                item = find(lambda i: i.custom_id == component['custom_id'], self._children)  # type: ignore
                if item is None:
                    _log.debug("Modal interaction referencing unknown item custom_id %s. Discarding", component['custom_id'])
                    continue
                item._refresh_state(component)  # type: ignore

Randomneo avatar Aug 09 '22 20:08 Randomneo

So this is specifically regarding modals. All selects get the last one's values, instead of their own. The error you're getting is because the last select is voice channels, which you selected no options for. I guess this is confirmed, then.

sgtlaggy avatar Aug 09 '22 20:08 sgtlaggy

@Puncher1 on which version/commit are you running? Issue reproducible after this commit

Randomneo avatar Aug 10 '22 13:08 Randomneo

I am also experiencing this bug in a modal select All selects get the value of the last select

imanataee avatar Aug 10 '22 16:08 imanataee

@Randomneo ~~I'm running it on the latest commit, when I list my packages with pip list I get this~~

Can confirm this bug. It tries to send the message to the voice channel. It just doesn't throw any errors. Sorry for the confusion

codeofandrin avatar Aug 10 '22 17:08 codeofandrin