Search code examples
pythondiscorddiscord.pykeyboardinterrupt

raise KeyboardInterrupt() KeyboardInterrupt | asyncio.exceptions.CancelledError


An error occurs when disabling the bot with Ctrl+C in VSCode Error:

Traceback (most recent call last):
  File "C:\Program Files\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "E:\Bots\Discord\tbot\main.py", line 46, in main
    await bot.start(config['token'])
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\discord\client.py", line 746, in start
    await self.connect(reconnect=reconnect)
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\discord\client.py", line 627, in connect
    await self.ws.poll_event()
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\discord\gateway.py", line 619, in poll_event
    msg = await self.socket.receive(timeout=self._max_heartbeat_timeout)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\aiohttp\client_ws.py", line 229, in receive
    msg = await self._reader.read()
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\aiohttp\streams.py", line 657, in read
    return await super().read()
           ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Artem\AppData\Roaming\Python\Python311\site-packages\aiohttp\streams.py", line 616, in read
    await self._waiter
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "E:\Bots\Discord\tbot\main.py", line 49, in <module>
    asyncio.run(main())
  File "C:\Program Files\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\Program Files\Python311\Lib\asyncio\runners.py", line 123, in run
    raise KeyboardInterrupt()
KeyboardInterrupt

main.py:

import discord
from discord.ext import commands
import json
import asyncio
import os

file = open('config.json', 'r')
config = json.load(file)

intents = discord.Intents.all()
intents.message_content = True
bot = commands.Bot((config['prefix']), intents=intents, help_command=None)


@bot.event
async def on_ready():
    await bot.tree.sync()
    await bot.change_presence(status=discord.Status.dnd, activity=discord.Game(name=".help"))
    print('Bot connected')

@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        embed = discord.Embed(
        description = f'{ctx.author.mention}, сommand not found!', 
        colour = discord.Color.red()
        )
        sent_message = await ctx.send(embed=embed)
        await asyncio.sleep(20)
        await sent_message.delete() 

async def load():
    for filename in os.listdir('./cogs'):
        if filename.endswith('.py'):
            await bot.load_extension(f'cogs.{filename[:-3]}')

async def main():
    await load()
    await bot.start(config['token'])


asyncio.run(main())

The bot uses hybrid commands, if you try to replace asyncio.run with bot.run, the slash commands do not work. Is this a bug or is it considered normal? If it is an error, can you help me solve it? Thanks. P.S. Python v3.11.1, discord.py v2.2.2


Solution

  • The error is expected - you can either handle it yourself or use bot.run to run the bot instead. bot.run will work as they're catching the error. To emulate it:

    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("Exiting...")
    

    Though, the better approach is to use the builtin bot.run command. To use that and register your commands; we need to move the loading of them into the setup_hook method. We can either subclass commands.Bot and override it, or set the function.

    To do the latter:

    async def my_setup_func()
        for filename in os.listdir('./cogs'):
            if filename.endswith('.py'):
                await bot.load_extension(f'cogs.{filename[:-3]}')
    
    
    bot.setup_hook = my_setup_func
    bot.run(config["token"])
    

    To do the former:

    class MyBot(commands.Bot):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
        async def setup_hook(self) -> None:
            for filename in os.listdir('./cogs'):
                if filename.endswith('.py'):
                    await bot.load_extension(f'cogs.{filename[:-3]}')
    
    intents = discord.Intents.all()
    intents.message_content = True
    bot = MyBot((config['prefix']), intents=intents, help_command=None)
    
    # rest of your setup code
    
    bot.run(config["token"])
    

    Hope that makes some sense. Some of the examples make use of the latter technique.