"RuntimeWarning: coroutine 'BotBase.load_extension' was never awaited" after updating discord.py

Question:

The discord bot I made a year ago and deployed to Heroku has worked until now. However, after changing some cogs and updating python to version 3.9.10, I get the following warning in the Heroku logs:

app[worker.1]: /app/m_bot.py:120: RuntimeWarning: coroutine 'BotBase.load_extension' was never awaited
app[worker.1]: client.load_extension(f"cogs.{filename[:-3]}")
app[worker.1]: RuntimeWarning: Enable tracemalloc to get the object allocation traceback
app[worker.1]: Bot is ready.
app[api]: Build succeeded> 

The 120 line block is:

for filename in os.listdir("./cogs"):
    if filename.endswith(".py"):
        # cut of the .py from the file name
        client.load_extension(f"cogs.{filename[:-3]}")

The bot goes online but doesn’t respond to any command. I haven’t made any other changes apart from what was listed above.

It works when I run my bot on my PC, so I suspect it might be a version problem.

How can I resolve this?

Asked By: TrickyDeath

||

Answers:

Explanation

As of discord.py version 2.0, Bot.load_extension is now a coroutine and has to be awaited. This is to allow Cog subclasses to override cog_unload with a coroutine.

Code

await must be used in front of client.load_extension, as shown:

await client.load_extension("your_extension")

In each of your cogs:

Replace the standard setup function with an asynchronous one:

async def setup(bot):
    await bot.add_cog(YourCog(bot))

If you want to use the normal convention for adding extensions, you’ll need to use the following code:

In your client’s file:

async def load_extensions():
    for filename in os.listdir("./cogs"):
        if filename.endswith(".py"):
            # cut off the .py from the file name
            await client.load_extension(f"cogs.{filename[:-3]}")

You should also wrap your login in an asynchronous ‘main’ function, where you would call this function. Note that the code below does not setup logging, you need to do so yourself:

async def main():
    async with client:
        await load_extensions()
        await client.start('your_token')

asyncio.run(main())

These two functions replace the old way:

client.run("your_token")

along with the code you posted in your question.

Reference

discord.py 2.0 async changes (Thank you ChrisDewa for mentioning this in your comment)

Answered By: TheFungusAmongUs
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.