Интеграция 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()