#sub_command decorator is not properly preserving the instance (i.e., self) when it's being called

1 messages · Page 1 of 1 (latest)

jovial pumice
#
@commands.slash_command(dm_permission=False, admin_permission=True)
    async def source(self, inter):
        await inter.response.defer(ephemeral=True)
        if not inter.author.guild_permissions.administrator:
            return await inter.followup.send('You must be an administrator to use this command.', ephemeral=True)
        guild = await self.guilds_db.find_one({'_id': str(inter.guild.id)})
        if not guild:
            return await inter.followup.send('You must `/configure` your server first.', ephemeral=True)
        inter.guild_object = guild
        print("source", self) #working

    @source.sub_command_group()
    async def channel(self, inter):
        print("channel", self) #working
        pass

    @channel.sub_command()
    async def list(self, inter):
        """
        List all source channels.
        Parameters
        ----------
        inter: necessary for bot commands
        """
        print("list", self) #None
        guild = inter.guild_object
        index_embed = disnake.Embed(
            title='**Source Channels**', description="", color=self.color)
        channels = []
        for channel_id in guild['channels']:
            channel = self.bot.get_channel(int(channel_id))
            if channel:
                channels.append(channel.mention)
        if len(channels) > 0:
            index_embed.description = "\n".join(channels)
        else:
            index_embed.description = "None."
        await inter.followup.send(embed=index_embed)
silk juniper
#

admin_permission is not a valid kwarg for slash command.

#

Use commands.has_permissions(administrator=True)

#

Also, source is a parent command. It is called every single time. So, typically you do not want to have any responses here.

#

self is the cog instance. Not sure what you're actually trying to do here.

dusty elk
#

also, can't reproduce it - what version are you using?

#

simplified, but works fine on my end:

    @commands.slash_command()
    async def source(self, inter):
        print("source", self)

    @source.sub_command_group()
    async def channel(self, inter):
        print("channel", self)

    @channel.sub_command()
    async def list(self, inter):
        print("list", self)
2023-07-07 18:49:57,358: [DEBUG] (MainThread) disnake.client: Dispatching event slash_command
source <test_bot.cogs.misc.Misc object at 0x7f9c927089d0>
channel <test_bot.cogs.misc.Misc object at 0x7f9c927089d0>
list <test_bot.cogs.misc.Misc object at 0x7f9c927089d0>
jovial pumice
#

cc: @silk juniper

#

hm i think the issue is the name being list()

silk juniper
#

You could move the checks to a cog_slash_command_check and cog_slash_command_error handler

#

But yeah, you shouldn't use reserved python keywords for naming objects.

jovial pumice
#

Yup, changed list() to show and it works now

#

thank you

dusty elk
#

hmm, not quite sure why that did it, but if it works it works tHONK

#

in any case, you can use @channel.sub_command(name="list") to keep it as "list" on Discord and name your method whatever you want c:

jovial pumice
#

nevermind, show is still messing it up

#
    @commands.slash_command(dm_permission=False)
    @commands.default_member_permissions(administrator=True)
    async def source(self, inter):
        pass

    @source.sub_command_group()
    async def channel(self, inter):
        print("channel", self)
        pass

    @channel.sub_command()
    async def show(self, inter):
        """
        Show all source channels.
        """
        print("show", self)
        await inter.response.defer(ephemeral=True)
        guild = await self.guilds_db.find_one({'_id': str(inter.guild.id)})
        if not guild:
            return await inter.followup.send('You must `/configure` your server first.', ephemeral=True)
        index_embed = disnake.Embed(
            title='**Source Channels**', description="", color=self.color)
        channels = []
        for channel_id in guild['channels']:
            channel = self.bot.get_channel(int(channel_id))
            if channel:
                channels.append(channel.mention)
        if len(channels) > 0:
            index_embed.description = "\n".join(channels)
        else:
            index_embed.description = "None."
        await inter.followup.send(embed=index_embed)
jovial pumice
#

only way I'm getting around is:

source()
inter.self = self

show()
self = inter.self

silk juniper
#

I still have no idea what it is you're trying to do.

jovial pumice
#

guilds_db is the database

#

i could send the entire file if you'd like

silk juniper
#

I get that, but I don't understand the involvement of self

#

thew inter.self part is what is confusing me.

jovial pumice
#
class Core(commands.Cog):
    def __init__(self, bot) -> None:
        self.bot = bot
        self.color = 0xEBE1DB
        self.guilds_db = MongoDB('Clarify', 'guilds')

#

this is my class @silk juniper

silk juniper
#

I see.

jovial pumice
#

I need to access self.guilds_db and self.bot

silk juniper
#

Right.

jovial pumice
#

I did, but its None

silk juniper
#

That's just odd.

jovial pumice
#

Yeah and for some reason, the other command group, url, works

silk juniper
#

Yeah, this is an odd one.

#

It worked when you simplified the commands, though?

jovial pumice
#

and i'm printing self before everything else so even if there's an error, i should be notified

jovial pumice
#
    @commands.slash_command(dm_permission=False)
    @commands.default_member_permissions(administrator=True)
    async def source(self, inter):
        print("source", self)
        inter.self = self
        pass

    @source.sub_command_group()
    async def channel(self, inter):
        print("channel", self)
        pass

    @channel.sub_command()
    async def show(self, inter):
        """
        Show all source channels.
        """
        print("show", self)
        # self = inter.self
        # await inter.response.defer(ephemeral=True)
        # guild = await self.guilds_db.find_one({'_id': str(inter.guild.id)})
        # if not guild:
        #     return await inter.followup.send('You must `/configure` your server first.', ephemeral=True)
        # index_embed = disnake.Embed(
        #     title='**Source Channels**', description="", color=self.color)
        # channels = []
        # for channel_id in guild['channels']:
        #     channel = self.bot.get_channel(int(channel_id))
        #     if channel:
        #         channels.append(channel.mention)
        # if len(channels) > 0:
        #     index_embed.description = "\n".join(channels)
        # else:
        #     index_embed.description = "None."
        # await inter.followup.send(embed=index_embed)

still printing None

silk juniper
#

Yeah, that is super weird.

source <__main__.Cog object at 0x000002B8DB6BED90>
channel <__main__.Cog object at 0x000002B8DB6BED90>
show <__main__.Cog object at 0x000002B8DB6BED90>
#

What disnake version?

#

I think that was asked already, though

jovial pumice
#
@commands.slash_command(dm_permission=False)
    @commands.default_member_permissions(administrator=True)
    async def source(self, inter):
        print("source", self)
        inter.self = self
        pass

    @source.sub_command_group()
    async def channel(self, inter):
        print("channel", self)
        pass

    @channel.sub_command()
    async def test(self, inter):
        print("test", self)
        pass

    @channel.sub_command()
    async def show(self, inter):
        """
        Show all source channels.
        """
        print("show", self)
        # self = inter.self
        # await inter.response.defer(ephemeral=True)
        # guild = await self.guilds_db.find_one({'_id': str(inter.guild.id)})
        # if not guild:
        #     return await inter.followup.send('You must `/configure` your server first.', ephemeral=True)
        # index_embed = disnake.Embed(
        #     title='**Source Channels**', description="", color=self.color)
        # channels = []
        # for channel_id in guild['channels']:
        #     channel = self.bot.get_channel(int(channel_id))
        #     if channel:
        #         channels.append(channel.mention)
        # if len(channels) > 0:
        #     index_embed.description = "\n".join(channels)
        # else:
        #     index_embed.description = "None."
        # await inter.followup.send(embed=index_embed)

adding new subcommand, test, works

#

disnake==2.9.0

#

changed the name= parameter and it fixed it, will keep testing and let you know if it breaks

silk juniper
#

It almost seems like it's a sync issue. You make a change, the command resyncs and it works, until something breaks it.

#

Because it worked temporarily after the last change which would have forced a resync.

coarse dirge
#

It looks to me like they had something in the class namespace of the same name as the function

#

If you remember, methods are wrapped in descriptors, and descriptors outside classes receive None as the instance, which is then passed as self to the function

coarse dirge
final ore