【问题标题】:Python Twisted integration with Cmd modulePython Twisted 与 Cmd 模块的集成
【发布时间】:2011-12-19 22:11:59
【问题描述】:

我喜欢 Python 的 TwistedCmd。我想同时使用它们。

我做了一些工作,但到目前为止,我还没有弄清楚如何使制表符完成工作,因为我看不到如何在 Twisted 的 LineReceiver 中立即(不按 Enter)接收制表键按键事件。

到目前为止,这是我的代码:

#!/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 构建一个漂亮、友好的终端应用程序,它可以响应网络事件以及 tab 补全。我希望我可以使用已经存在的东西,而不必自己实现太多。

【问题讨论】:

  • 我注意到了 Manhole 和 Conch,但它们对我的工作没有多大意义。该文档将 Conch 描述为客户端和服务器的 SSHv2 实现,并说明了如何制作一个为其客户端进行着色的 SSH 服务器。我的需求与此既相似又不同。如果您对如何使用 Manhole 有更具体的建议,我会全力以赴……其中一个问题是明显缺乏文档。

标签: python twisted stdin tab-completion python-cmd


【解决方案1】:

您在使用这种方法时遇到了一些困难:

  • Cmd.onecmd 不会进行任何制表符处理。
  • 即使是这样,您的终端也需要处于 cbreak 模式,以便单独的击键能够进入 Python 解释器(tty.setcbreak 可以解决这个问题)。
  • 如您所知,Cmd.cmdloop 无法识别反应器,并且会阻塞等待输入。
  • 然而,要获得您想要的所有酷行编辑,Cmd(实际上是 readline)需要直接访问标准输入和标准输出。

鉴于所有这些困难,您可能希望考虑让 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()

【讨论】:

  • 我正在考虑自己在 Tab 按键上调用 Cmd 模块中的完成方法。感谢您指出 cbreak——我不知道。我会试试你的方法,谢谢你写出来。
  • 不客气。基本上,readline 是一个迷你诅咒应用程序。如果您尝试调解对标准输入/标准输出的访问,我认为您最终将不得不重新实现其大部分功能。这种线程化的方法让它直接管理标准输入/标准输出(包括 cbreak 模式),这应该让事情变得简单。
  • twisted.internet.threads.blockingCallFromThread 是一个非常有用的twisted函数,它允许CommandProcessor获取返回值。
猜你喜欢
  • 2013-04-04
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 2014-03-02
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
相关资源
最近更新 更多