TypeError: object async_generator can't be used in 'await' expression

Рейтинг: 0Ответов: 1Опубликовано: 31.03.2023

Выводит следующую ошибку в терминале:

discord.ext.commands.bot Ignoring exception in command punishments
Traceback (most recent call last):
  File "/home/runner/GlaringSteepArchives/venv/lib/python3.10/site-packages/discord/ext/commands/core.py", line 229, in wrapped
    ret = await coro(*args, **kwargs)
  File "main.py", line 110, in punishments
    bans = await ctx.guild.bans()
TypeError: object async_generator can't be used in 'await' expression

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

Traceback (most recent call last):
  File "/home/runner/GlaringSteepArchives/venv/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 1350, in invoke
    await ctx.command.invoke(ctx)
  File "/home/runner/GlaringSteepArchives/venv/lib/python3.10/site-packages/discord/ext/commands/core.py", line 1023, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
  File "/home/runner/GlaringSteepArchives/venv/lib/python3.10/site-packages/discord/ext/commands/core.py", line 238, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: object async_generator can't be used in 'await' expression

Сам код:

@bot.command()
async def punishments(ctx, member: discord.Member):
    # Получаем список банов на сервере
    bans = await ctx.guild.bans()
    # Получаем список киков с сервера
    kicks = await ctx.guild.audit_logs(limit=100, action=discord.AuditLogAction.kick).flatten()
    # Получаем список мутов с сервера
    mutes = await ctx.guild.audit_logs(limit=100, action=discord.AuditLogAction.mute).flatten()

    # Списки наказаний для пользователя
    user_bans = [ban for ban in bans if ban.user == member]
    user_kicks = [kick for kick in kicks if kick.target == member]
    user_mutes = [mute for mute in mutes if mute.target == member]

    # Список всех наказаний
    punishment_list = []

    # Добавляем в список все баны пользователя
    for ban in user_bans:
        punishment_list.append(f'Banned on {ban.created_at.strftime("%Y-%m-%d %H:%M:%S")}')

    # Добавляем в список все кики пользователя
    for kick in user_kicks:
        punishment_list.append(f'Kicked on {kick.created_at.strftime("%Y-%m-%d %H:%M:%S")}')

    # Добавляем в список все муты пользователя
    for mute in user_mutes:
        punishment_list.append(f'Muted on {mute.created_at.strftime("%Y-%m-%d %H:%M:%S")}')

    # Если у пользователя нет наказаний, то сообщаем об этом
    if len(punishment_list) == 0:
        await ctx.send(f'{member} has no punishments.')
    # Иначе отображаем все наказания
    else:
        # Сортируем список по дате создания
        punishment_list.sort()
        # Преобразуем список в строку и отправляем на сервер
        await ctx.send(f'{member} punishments:\n' + '\n'.join(punishment_list))

Ответы

▲ 2

Ошибка

    bans = await ctx.guild.bans()
TypeError: object async_generator can't be used in 'await' expression

говорит, что метод .bans() - это асинхронный генератор, и его нельзя использовать вместе с конструкцией await.

Для работы с асинхронными генераторами (в целом - с асинхронными итераторами или итерируемыми объектами) нужно использовать async for.

В данном случае, чтобы получить элементы из асинхронного генератора можно использовать такую конструкцию:

bans = [ban async for ban in ctx.guild.bans()]

Минимальный пример с демонстрацией:

import asyncio


async def get_bans():
    """Пример асинхронного генератора"""
    for ban in range(10):
        await asyncio.sleep(0.1)
        yield ban


async def main():
    # bans = await get_bans() выдаст ошибку TypeError: object async_generator can't be used in 'await' expression
    bans = [ban async for ban in get_bans()]
    print(bans)
    # Вывод: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


if __name__ == "__main__":
    asyncio.run(main())

Еще вариант - использовать aiostream.stream.list из модуля aiostream (pip install aiostream):

bans = await stream.list(ctx.guild.bans())

Ссылки: