EQUENOS / dislash.py

A Python wrapper for discord slash-commands and buttons, designed to extend discord.py.
https://dislashpy.readthedocs.io/en/latest
MIT License
167 stars 29 forks source link

Error when I start the server #36

Open YoanGab opened 3 years ago

YoanGab commented 3 years ago

I get this error when I start the server. The 1st request doesn't work. When I print the ctx, the channel is None for the 1st request but isn't for the next ones. Then I have this error when I use : await ctx.send(...)

Ignoring exception in on_socket_response
Traceback (most recent call last):
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1050, in _on_socket_response
    await self._process_interaction(payload["d"])
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1137, in _process_interaction
    raise err
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1134, in _process_interaction
    await slash_parent.invoke(inter)
  File "opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 342, in invoke
    raise err
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 338, in invoke
    await self._maybe_cog_call(self._cog, interaction, interaction.data)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 131, in _maybe_cog_call
    return await self(inter, **params)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 95, in __call__
    return await self.func(*args, **kwargs)
  File "project/src/main.py", line 473, in add_notif
    await msg.delete()
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/discord/message.py", line 1023, in delete
    await self._state.http.delete_message(self.channel.id, self.id)
AttributeError: 'NoneType' object has no attribute 'id'

I tried with bot.command and it works

@bot.command(
    name="add_notif"
)

But not when I use slash.command


@slash.command(
    name="add_notif"
)
MisileLab commented 3 years ago

Can you give me full code?

YoanGab commented 3 years ago

I receive this error only on DMs, the 2nd message to send gives me the error but ctx["channel"] is None at the beginning of the function.

import os
import discord
from discord.ext import commands
from dislash import SlashClient, SelectMenu, SelectOption, Option, Type
from dotenv import load_dotenv
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from orm.tables import Player
from classes.classes import Card

load_dotenv()

TOKEN = os.getenv('DISCORD_TOKEN')
GUILD_ID = int(os.getenv('GUILD_ID'))
CONNECT_STRING = os.getenv('CONNECT_STRING')

engine = create_engine(CONNECT_STRING)
Session = sessionmaker(bind=engine)
session = Session()

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

slash = SlashClient(bot)

@slash.command(
    name="get_player",
    options=[
        Option("name", "Specify any player", Type.STRING, required=True)
    ]
)
async def get_player(ctx, name):
    players = session.query(Player).filter(Player.name.like("%" + name + "%")).limit(5).all()
    msgs = []
    if len(players) == 0:
        await ctx.send(embed=discord.Embed(
            title="No player with name"
        ))
        return

    elif len(players) == 1:
        chosen_card = Card(name=players[0].name, slug=players[0].slug)

    else:
        for player in players:
            emb = discord.Embed(
                title=f"{player.name}",
                color=ctx.author.color
            )
            card = Card(name=player.name, slug=player.slug)
            if card.image:
                emb.set_image(url=card.image)
            # Error here when sending the 2nd embed
            msgs.append(await ctx.reply(embed=emb))

        msg = await ctx.send(
            "Choose a player",
            components=[
                SelectMenu(
                    custom_id="choose_player",
                    placeholder="Choose a player",
                    max_values=1,
                    options=[
                        SelectOption(player.name, player.slug)
                        for player in players
                    ]
                )
            ]
        )

        def check(inter):
            return ctx.author == inter.author

        # Wait for a menu click under the message you've just sent
        inter = await msg.wait_for_dropdown(check)
        # Tell which options you received
        option = inter.select_menu.selected_options[0]

        for message in msgs:
            await message.delete()
        await msg.delete()
        chosen_card = Card(name=option.label, slug=option.value)
    embed = discord.Embed(
        title=f"Chosen card is {chosen_card.name}"
    )
    embed.set_image(url=chosen_card.image)
    await ctx.send(embed=embed)

    await ctx.send(embed=discord.Embed(
        title="Error here when len(players) == 1"
    ))

bot.run(TOKEN)
EQUENOS commented 3 years ago

Okay, here's the problem: ctx.reply (as well as ctx.send (alias for reply), ctx.respond and ctx.create_response (alias for respond)) can never be called more than once, because these methods create a response for a given interaction. One interaction can only have one response. Instead of attempting to create multiple responses, you can use ctx.channel.send, which can be used an unlimited amount of times

YoanGab commented 3 years ago

I tried that but it doesn't even send 1 message, because ctx.channel is None. Moreover, ctx.send works when it's not the 1st time that someone interacts with the bot

EQUENOS commented 3 years ago

ctx.channel being None is super weird, maybe it's related to some caching reasons Speaking of ctx.send working more than once, it indeed should work like that, because it automatically detects whether to use create_response or channel.send, I forgot to mention that

YoanGab commented 3 years ago

What I don't understand is that it doesn't happen when I use @discord.commandinstead of @slash.command