omar
omar

Reputation: 77

catching extension exceptions

So I want to catch every exception that would be raised from loading extensions, of which i found these in the docs

ExtensionErrors:

This is the code I've been trying to get something working with, but i is too dumb

@bot.command()
async def reload(ctx, extension):

    try:
        bot.reload_extension(f'Cogs.{extension}')
        await ctx.send(f'reloaded {extension}')

        # raise commands.ExtensionNotFound(extension) # makes **ExtensionNotFound* prints

    except commands.ExtensionNotLoaded: # this works
        bot.load_extension(f'Cogs.{extension}')
        await ctx.send(f'{extension} was not loaded in the first place but i loaded it up for you')

    except commands.ExtensionNotFound: # doesn't catch actual exception unless it's raised
        await ctx.send('commands.ExtensionNotFound')

    except commands.ExtensionError: # didn't test coz i got hung up on the last exception
        await ctx.send('commands.ExtensionError')

    except commands.ExtensionFailed: # didn't test
        await ctx.send('commands.ExtensionFailed')

    except commands.ExtensionAlreadyLoaded: # didn't test
        await ctx.send('commands.ExtensionAlreadyLoaded')

So what I want is a working example of catching the extension exceptions (that.. unlike my weak arse code, does actually work)

Edit1: If I call the reload function with a none existing cog !reload not_a_real_cog I get the following exception:

Ignoring exception in command reload:
Traceback (most recent call last):
  File "d:\Discord bots\Discord bot - Cogs V1\main.py", line 136, in reload
    bot.reload_extension(f'Cogs.{extension}')
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 759, in reload_extension  
    raise errors.ExtensionNotLoaded(name)
discord.ext.commands.errors.ExtensionNotLoaded: Extension 'Cogs.not_a_real_cog' has not been loaded.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "d:\Discord bots\Discord bot - Cogs V1\main.py", line 142, in reload
    bot.load_extension(f'Cogs.{extension}')
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 676, in load_extension    
    raise errors.ExtensionNotFound(name)
discord.ext.commands.errors.ExtensionNotFound: Extension 'Cogs.not_a_real_cog' could not be loaded.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "C:\Users\Bruh\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: ExtensionNotFound: Extension 'Cogs.not_a_real_cog' could not be loaded.

Testing ExtensionNotFound again by the methods provided by @CrazyChucky in the comments.. I think i misunderstood what the exception IS to actually to catch it, though I tried to catch:

But i catched nothing

Upvotes: 0

Views: 396

Answers (1)

CrazyChucky
CrazyChucky

Reputation: 3518

Based on your comments, I see that you were unclear on how try/except clauses work; you can only catch an exception in the try part, and a try will only catch the first exception it encounters, immediately aborting and going to the corresponding except (or else) clause.

In this case, you'll want to nest one try/except inside another, keeping in mind that you can generate several of the same errors whether you're loading or reloading, and you don't want your code to repeat itself.

@bot.command()
async def reload(ctx, extension):
    try:

        # This inner try/except only cares about whether the extension
        # can be REloaded, or whether it needs to be loaded from
        # scratch.
        try:
            await ctx.send(f'Attempting to reload {extension} extension...')
            bot.reload_extension(f'cogs.{extension}')
        except commands.ExtensionNotLoaded:
            await ctx.send(f'{extension} is not currently loaded. Attempting '
                            'to load...')
            bot.load_extension(f'cogs.{extension}')

        await ctx.send(f'{extension} has been freshly loaded.')

    # These except clauses will be reached if their exception occurs,
    # regardless of whether or not the inner except clause was entered.

    except commands.ExtensionNotFound:
        await ctx.send(f"Error: {extension} couldn't be found to load."))

    except commands.ExtensionFailed:
        await ctx.send(f'Error: {extension} failed to load properly.')

    except commands.ExtensionError:
        await ctx.send(f'Error: unknown error with {extension}')

Note: module names in Python are usually all lowercase by convention, so I renamed Cogs to cogs.

You might be tempted by the existence of the bot's extensions attribute to do something along these lines:

if extension in bot.extensions:
    bot.reload_extension(f'cogs.{extension}')
else:
    bot.load_extension(f'cogs.{extension}')

But this is dangerous in an asynchronous environment like this, because it's a race condition: it's possible that between the time you perform the in check and when you actually try to load/reload the extension, some other user or process could potentially have loaded/unloaded the extension.

Upvotes: 1

Related Questions