Thursday, 8 April 2021

How can I prevent getting an AttributeError after reloading a cog?

A more unusual question today, but maybe someone can help me.

I am working on a bot, which among other things has to do with music. The following problem:

If I change stuff in a cog and then reload it I always get an AttributeError: 'NoneType' object has no attribute 'XXXX' error for the particular command. Is there a way to fix/prevent this?

The error occurs when the bot is in a voice channel for example and then I reload the cog.

I query state for every command which has to do with music, is it maybe related to that?

state = self.get_state(ctx.guild)

Full function for get_state:

    def get_state(self, guild):
        """Gets the state for `guild`, creating it if it does not exist."""
        if guild.id in self.states:
            return self.states[guild.id]
        else:
            self.states[guild.id] = GuildState()
            return self.states[guild.id]

I tried to solve it with a try/except AttributeError, but of course that didn`t really work/the console still gave me the output.

Here is an example code:

    @commands.command()
    @commands.guild_only()
    @commands.check(audio_playing)
    @commands.check(in_voice_channel)
    @commands.check(is_audio_requester)
    async def loop(self, ctx):
        """Activates/Deactivates the loop for a song."""
        state = self.get_state(ctx.guild)
        status = state.now_playing.toggle_loop()
        if status is None:
            return await ctx.send(
                embed=discord.Embed(title=":no_entry:  Unable to toggle loop.", color=discord.Color.red()))
        else:
            return await ctx.send(embed=discord.Embed(
                title=f":repeat:  Loop: {'**Enabled**' if state.now_playing.loop else '**Disabled**'}.",
                color=self.bot.get_embed_color(ctx.guild)))

And if I make changes in the cog, reload it and then try to run loop again I get the following error:

In loop:
  File "C:\Users\Dominik\PycharmProjects\AlchiReWrite\venv\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "C:\Users\Dominik\PycharmProjects\AlchiReWrite\cogs\music.py", line 220, in loop
    status = state.now_playing.toggle_loop()
AttributeError: 'NoneType' object has no attribute 'toggle_loop'

(Same error for all the other commands)

Requested, we have the GuildState class:

class GuildState:
    """Helper class managing per-guild state."""

    def __init__(self):
        self.volume = 1.0
        self.playlist = []
        self.message_queue = []
        self.skip_votes = set()
        self.now_playing = None
        self.control_message = None
        self.loop = False
        self.skipped = False

    def is_requester(self, user):
        return self.now_playing.requested_by == user

How would I overcome this error?

The bot joins on the command play URL and then I built in the following:

if not state.now_playing:
    self._play_song(client, state, video)

_play_song is mainly defined the following:

    def _play_song(self, client, state, song):
        state.now_playing = song
    # Other things are not relevant


from How can I prevent getting an AttributeError after reloading a cog?

No comments:

Post a Comment