Как загрузить на Google Drive в асинхронном методе в Python - PullRequest
0 голосов
/ 19 декабря 2018

В настоящее время я создаю бот Discord, который загружает файл на Google Drive при использовании команды.Однако методы команды являются асинхронными, а метод files (). Create () - синхронным, и его вызов просто приводит к зависанию бота.

@bot.command(pass_context = True)
@commands.has_role(name = 'Archivist')
async def archivechannel(ctx, channel : discord.Channel, filename):
await bot.say("Archiving....")
try:
    with open("{}.txt".format(filename), "w") as openfile:
        lines = []
        async for message in bot.logs_from(channel, limit=500, reverse=True):
            if not (message.author.bot or message.content.startswith("]")):
                print ("<{}> {}#{}: {}".format(message.timestamp, message.author.name, message.author.discriminator, message.content))
                lines.append("<{}> {}#{}: {}\n".format(message.timestamp, message.author.name, message.author.discriminator, message.content))
        openfile.writelines(lines)
        await bot.say("Archive Complete!")
except IOError:
    await bot.say("Error: IOException")
await bot.say("Uploading....")
metadata = {'name' : "{}.txt".format(filename), 'mimetype' : 'application/vnd.google.apps.document', 'parents' : folderID}
media = MediaFileUpload('{}.txt'.format(filename), mimetype='text/plain')
res = service.files().create(body=metadata, media_body=media).execute()
print(res)

Строка, вызывающая проблему:

res = service.files().create(body=metadata, media_body=media).execute()

Бот просто застревает после произнесения "Загрузка ...." и ничего не загружает.

Кто-нибудь знает, как я могу это исправить?

Редактировать: Используя ThreadPoolExecutor, ни DefaultExecutor не работал, ни настраивать синхронную функцию, которая запускает методы создания и выполнения, принимая метаданные и параметры мультимедиа

Редактировать 2: После еще нескольких попыток выяснить, что проблема теперь в следующей строке:

media = MediaFileUpload('{}.txt'.format(filename), mimetype='text/plain')

Однако из моего теста, на вопрос, который я задал, Патрик прав, и я отметилвопрос как ответ.

1 Ответ

0 голосов
/ 19 декабря 2018

Вы можете запустить операцию блокировки в другом потоке, пока ваш асинхронный код ожидает его завершения, не блокируя цикл обработки событий.

Мы создадим новый ThreadPoolExecutor,затем используйте run_in_executor, чтобы использовать его для запуска задачи.

from concurrent.futures import ThreadPoolExecutor

def upload_file(metadata, media):
    return service.files().create(body=metadata, media_body=media).execute()

@bot.command(pass_context = True)
@commands.has_role(name = 'Archivist')
async def archivechannel(ctx, channel : discord.Channel, filename):
    await bot.say("Archiving....")
    try:
        with open("{}.txt".format(filename), "w") as openfile:
            lines = []
            async for message in bot.logs_from(channel, limit=500, reverse=True):
                if not (message.author.bot or message.content.startswith("]")):
                    print ("<{}> {}#{}: {}".format(message.timestamp, message.author.name, message.author.discriminator, message.content))
                    lines.append("<{}> {}#{}: {}\n".format(message.timestamp, message.author.name, message.author.discriminator, message.content))
            openfile.writelines(lines)
            await bot.say("Archive Complete!")
    except IOError:
        await bot.say("Error: IOException")
    await bot.say("Uploading....")
    metadata = {filename : "{}.txt".format(filename), 'mimetype' : 'application/vnd.google.apps.document', 'parents' : folderID}
    media = MediaFileUpload('{}.txt'.format(filename), mimetype='text/plain')
    with ThreadPoolExecutor() as pool:
        res = await bot.loop.run_in_executor(
               pool, upload_file, metadata, media
              )
    print(res)

Вы также можете использовать исполнителя по умолчанию, удалив диспетчер контекста и передав None вместоpool.У меня проблемы с поиском информации об исполнителе по умолчанию, поэтому вы можете поэкспериментировать.

...