Использование Python PyInquirer и asyncio для создания пользовательского интерфейса для запуска асинхронных действий - PullRequest
0 голосов
/ 23 апреля 2020

Я хотел бы использовать PyInquirer и asyncio для создания пользовательского интерфейса, который можно использовать для запуска асинхронных действий.

Должна появиться подсказка (с использованием PyInquirer), из которой пользователь может выбрать действие. Это создаст отложенную задачу, и приглашение появится снова. После завершения отложенной задачи результат будет распечатан на стандартный вывод, даже если приглашение все еще отображается на экране.

Если я хочу, чтобы это запускалось один раз, это не проблема, и может сделать это так:

import asyncio
from PyInquirer import prompt

options = {
'type': 'list',
'name': 'functionToCall',
'message': 'Choose Command',
'choices': [
    'Say Hello',
    'Exit'
]
}

async def sayHello():
    await asyncio.sleep(2)
    print("hello")

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)   

async def main():
    answers = prompt(options)
    kill = False;
    if answers['functionToCall'] == 'Say Hello':
        loop.create_task(sayHello())
    else:
        kill = True
        loop.stop()

if __name__ == "__main__":
    loop.create_task(main())
    loop.run_forever()

Если выбрано 'Say Hello', оно будет печататься на выходе через 2 секунды.

Но если я хочу, чтобы подсказка появлялась сразу после предыдущее действие было выбрано, это блокирует результат от появления. Т.е.

async def main():
    answers = prompt(options)
    kill = False;
    if answers['functionToCall'] == 'Say Hello':
        loop.create_task(sayHello())
    else:
        kill = True
        loop.stop()

    if not kill:
        loop.create_task(main())

Подсказка появится сразу после того, как было выбрано последнее действие (по желанию), но «Hello» никогда не печатается на выходе. Я думаю, это потому, что функция prompt() из PyInquire блокирует выполнение другой задачи.

Как я могу заставить задачу sayHello() выполняться в фоновом режиме, пока программа находится внутри блокировки prompt(), а затем получите команду sayHello() для печати ее результата, даже если она все еще внутри функции prompt()?

Спасибо.

1 Ответ

0 голосов
/ 23 апреля 2020

Я выяснил ответ:

Функция prompt может быть передана patch_stdout = True и return_asyncio_coroutine = True

Это заставит ее возвращать слово будущих строк, вместо строки струн. Будущие строки могут быть обработаны как асинхронные задачи.

import asyncio
from PyInquirer import prompt

options = {
'type': 'list',
'name': 'functionToCall',
'message': 'Choose Command',
'choices': [
    'Say Hello',
    'Exit'
]
}

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)   


async def sayHello():
    await asyncio.sleep(2)
    print("hello!")

def handleChoice(future):
    choice = future.result()
    if choice == "Say Hello":
        loop.create_task(sayHello())
        loop.create_task(myprompt())
    else:
        loop.stop()

async def myprompt():
    future_answers_generator = prompt(options, patch_stdout = True, return_asyncio_coroutine = True)['functionToCall']    
    future = asyncio.ensure_future(future_answers_generator)
    future.add_done_callback(handleChoice)


if __name__ == "__main__":
    loop.create_task(myprompt())
    loop.run_forever()
...