Как реализовать python REPL, который хорошо обрабатывает асинхронный вывод? - PullRequest
12 голосов
/ 13 января 2009

У меня есть приложение на основе Python, которое может принимать несколько команд в простом цикле read-eval-print-loop. Я использую raw_input('> '), чтобы получить ввод. На Unix-системах я также import readline заставлял себя вести себя немного лучше. Все это работает нормально.

Проблема в том, что появляются асинхронные события, и я хотел бы напечатать вывод, как только они произойдут. К сожалению, из-за этого все выглядит ужасно. Строка ">" больше не появляется после вывода, и если пользователь наполовину набирает текст, он разбивает его текст пополам. Вероятно, он должен перерисовывать пользовательский текст после печати чего-либо.

Кажется, это должно быть решенной проблемой. Как правильно это сделать?

Также обратите внимание, что некоторые из моих пользователей работают под управлением Windows.

1011 * ТИА *

Редактировать: Принятый ответ работает на платформах Unixy (когда доступен модуль readline), но если кто-нибудь знает, как заставить это работать под Windows, это было бы очень полезно!

Ответы [ 6 ]

8 голосов
/ 13 января 2009

Может быть, что-то вроде этого поможет:

#!/usr/bin/env python2.6

from __future__ import print_function

import readline
import threading

PROMPT = '> '

def interrupt():
    print() # Don't want to end up on the same line the user is typing on.
    print('Interrupting cow -- moo!')
    print(PROMPT, readline.get_line_buffer(), sep='', end='')

def cli():
    while True:
        cli = str(raw_input(PROMPT))

if __name__ == '__main__':
    threading.Thread(target=cli).start()
    threading.Timer(2, interrupt).start()

Я не думаю, что stdin является поточно-ориентированным, так что вы можете в конечном итоге потерять символы в прерывающем потоке (что пользователь должен будет перепечатать в конце interrupt). Я преувеличил количество interrupt времени с вызовом time.sleep. В вызове readline.get_line_buffer не отображаются потерянные символы, поэтому все получается хорошо.

Обратите внимание, что сам stdout не является потокобезопасным, поэтому, если у вас есть несколько прерывающих потоков выполнения, это все равно может выглядеть брутто.

5 голосов
/ 14 января 2009

Почему вы пишете свой собственный REPL, используя raw_input()? Вы смотрели на cmd.Cmd класс? Редактировать: Я только что нашел библиотеку sclapp , которая также может быть полезна.

Примечание: класс cmd.Cmd (и sclapp) может или не может напрямую поддерживать вашу первоначальную цель; вам, возможно, придется разделить его на подклассы и при необходимости изменить, чтобы обеспечить эту функцию.

2 голосов
/ 22 декабря 2010

запустите это:

python -m twisted.conch.stdio

Вы получите красивый цветной асинхронный REPL без использования потоков Пока вы набираете приглашение, цикл событий работает.

0 голосов
/ 09 декабря 2010

загляните в модуль кода, он также позволяет создавать объекты для интерпретации кода Python (бесстыдный плагин) https://github.com/iridium172/PyTerm позволяет создавать интерактивные программы командной строки, которые обрабатывают ввод необработанных данных с клавиатуры (например, ^ C вызовет KeyboardInterrupt) .

0 голосов
/ 13 января 2009

Я думаю, у вас есть 2 основных варианта:

  1. Синхронизируйте ваш вывод (т.е. блокируйте, пока он не вернется)
  2. Разделите ваш ввод и ваш (асинхронный) вывод, возможно, в двух отдельных столбцах.
0 голосов
/ 13 января 2009

Это не ответ, но я бы посмотрел код IPython , чтобы увидеть, как они это делают.

...