Интеграция Python Twisted с модулем Cmd

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

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

Вот мой код до сих пор:

#!/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 ответ

Решение

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

  • 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()
Другие вопросы по тегам