Тебе довольно прямо сказано: "AttributeError: loop attribute cannot be accessed in non-async contexts."
Иными словами, атрибут Bot.loop (ссылку на рабочий цикл asyncio) можно читать, только если ты находишься внутри async def функции, прямо или косвенно.
Причина простая - asyncio.run() или эквивалентная функция как раз создаёт и запускает рабочий цикл asyncio (обычно называемый event loop или просто loop). Если рабочий цикл ещё не создан, то что должен вернуть атрибут Bot.loop? На этот вопрос просто нет правильного ответа. Поэтому доступ к атрибуту блокируется.
И насчёт решения тоже подсказано: "Consider using either an asynchronous main function and passing it to asyncio.run or using asynchronous initialisation hooks such as Client.setup_hook". Иными словами, тебе нужно сделать так, чтобы твой код, обращающийся к Bot.loop, выполнялся в асинхронной (async def) функции. Это можно сделать двумя способами.
Первый: вынести твой код из конструктора (который не может быть асинхронным) в отдельный метод. Например, Bot (и его предок Client) позволяют вызвать асинхронный метод on_ready() при запуске бота. Тут есть много оговорок - в частности, on_ready() может быть вызван неоднократно, если есть проблемы с соединением. Это нужно иметь ввиду.
Второй: завернуть вызов всего твоего конструктора в асинхронный метод. Упрощённо, вместо
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
# ...
bot.run('token')
можешь попробовать что-то вроде
import discord
from discord.ext import commands
async def main():
# асинхронная функция может быть выполнена ТОЛЬКО внутри рабочего цикла
# значит, рабочий цикл уже точно существует и выполняется
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
# конструктор сам по себе не асинхронный, но он выполняется в асинхронном контексте
bot = commands.Bot(command_prefix='!', intents=intents)
# ...
# мы уже в асинхронной функции, поэтому используем await start() вместо run()
await bot.start('token') # main() не завершит работу, пока бот не завершит работу
if __name__ == '__main__':
asyncio.run(main()) # создаём рабочий цикл. он будет работать, пока main() не завершит работу
Но я соглашусь с
Everything_is_bad - сначала разберись, как работает asyncio. Строить сложные конструкции с несколькими долгоживущими корутинами методом проб и ошибок - это слишком муторно.
Ну и очень большой вопрос от меня: ты, я вижу, мастеришь систему плагинов. Чем тебя не устроили
коги?