Search code examples
pythondiscordnextcord

How to call a function in a cog from a view using Nextcord?


I have a Cog and a view in nextcord. I'm trying to call the function magic_function from my view, but I've found no way of achieving it. Do you know how is it possible ? Here is a simplification of the situation :

class MyView(nextcord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)
    
    @nextcord.ui.button(label='Send Magic', style=nextcord.ButtonStyle.primary)
    async def magicbutton(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
        magic_word = MyCog.get_magic_word() # Here, I would like to access MyCog, but can't figure how
        await interaction.response.send_message(magic_word)


class MyCog(commands.Cog):
    def __init__(self, client):
        self.client = client

    def get_magic_word(self):
        # Doing stuff
        return "Banana"

    @nextcord.slash_command(description="Sends the button")
    async def send_the_view(self, interaction: nextcord.Interaction):
        view = MyView()
        await interaction.response.send_message("Here is the view :", view=view)


def setup(client):
    client.add_cog(MyCog(client=client))

I thought I could define my view inside the Cog, but I find it useless, since i coulden't access the function either. Also, I thought I could bring the function get_magic_word() outside the cog, but this is a bad idea since the function needs to call self to do stuff.


Solution

  • An easy way to do this is to provide the view with a reference to the instantiated Cog object:

    class MyView(nextcord.ui.View):
        def __init__(self, my_cog):
            super().__init__(timeout=None)
            self.my_cog = my_cog  # store the cog object as a class variable
    
        @nextcord.ui.button(label='Send Magic', style=nextcord.ButtonStyle.primary)
        async def magicbutton(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
            magic_word = self.my_cog.get_magic_word()  # interact with the cog object
            await interaction.response.send_message(magic_word)
    
    
    class MyCog(commands.Cog):
        def __init__(self, client):
            self.client = client
    
        def get_magic_word(self):
            # Doing stuff
            return "Banana"
    
        @nextcord.slash_command(description="Sends the button")
        async def send_the_view(self, interaction: nextcord.Interaction):
            view = MyView(self)  # pass self to the view
            await interaction.response.send_message("Here is the view :", view=view)
    

    This way, MyView can access methods/attributes on the instantiated MyCog.