Интеграция Python Twisted с модулем Cmd - PullRequest
6 голосов
/ 20 декабря 2011

Мне нравятся Python's Twisted и Cmd . Я хочу использовать их вместе.

У меня все работает, но до сих пор я не выяснил, как заставить работать завершение табуляции, потому что я не вижу, как сразу получать события клавиш табуляции (без нажатия Enter) в Twisted LineReceiver.

Вот мой код:

#!/usr/bin/env python

from cmd import Cmd
from twisted.internet import reactor
from twisted.internet.stdio import StandardIO
from twisted.protocols.basic import LineReceiver

class CommandProcessor(Cmd):
    def do_EOF(self, line):
        return True

class LineProcessor(LineReceiver):
    from os import linesep as delimiter # makes newline work

    def __init__(self):
        self.processor = CommandProcessor()
        self.setRawMode()

    def connectionMade(self):
        self.transport.write('>>> ')

    def rawDataReceived(self, data):
        self.processor.onecmd(data)
        self.transport.write('>>> ')

StandardIO(LineProcessor())
reactor.run()

Помимо завершения табуляции, это несколько работает. Я могу ввести команду типа «помощь», и модуль Cmd напечатает результаты. Но я потерял изящную функциональность полного табуляции модуля Cmd, потому что Twisted буферизует по одной строке за раз. Я попытался установить LineProcessor.delimiter в пустую строку, но безрезультатно. Может быть, мне нужно найти другой кусок Twisted для использования вместо LineReceiver? Или, может быть, есть более простой подход, который позволит избежать необходимости обрабатывать каждый символ один за другим?

Я не могу использовать Cmd в одиночку, потому что я хочу сделать это сетевым приложением, где некоторые команды приведут к отправке данных, а получение данных из сети будет происходить асинхронно (и будет отображаться для пользователя).

Так что, независимо от того, начинаем ли мы с приведенного выше кода или с чего-то совершенно другого, я хотел бы создать хорошее, дружественное терминальное приложение на Python, которое реагирует на сетевые события, а также на завершение вкладок. Я надеюсь, что смогу использовать то, что уже есть, и мне не придется слишком много реализовывать.

1 Ответ

9 голосов
/ 20 декабря 2011

У вас есть пара трудностей с этим подходом:

  • Cmd.onecmd не собирается обрабатывать вкладки.
  • Даже если это так, ваш терминал должен бытьв режиме cbreak для отдельных нажатий клавиш, чтобы сделать это для интерпретатора Python (tty.setcbreak может позаботиться об этом).
  • Как вы знаете, Cmd.cmdloop не распознает реактор и заблокирует ожидание ввода.
  • Тем не менее, чтобы получить все интересное редактирование строк, Cmd (фактически readline) должен иметь прямой доступ к stdin и stdout.

Учитывая все эти трудности,Возможно, вы захотите посмотреть, как CommandProcessor запускается в своем собственном потоке.Например:

#!/usr/bin/env python

from cmd import Cmd
from twisted.internet import reactor

class CommandProcessor(Cmd):
    def do_EOF(self, line):
        return True

    def do_YEP(self, line):
        reactor.callFromThread(on_main_thread, "YEP")

    def do_NOPE(self, line):
        reactor.callFromThread(on_main_thread, "NOPE")

def on_main_thread(item):
    print "doing", item

def heartbeat():
    print "heartbeat"
    reactor.callLater(1.0, heartbeat)

reactor.callLater(1.0, heartbeat)
reactor.callInThread(CommandProcessor().cmdloop)
reactor.run()
...