Python Twisted与Cmd模块的集成 [英] Python Twisted integration with Cmd module

查看:103
本文介绍了Python Twisted与Cmd模块的集成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢Python的 Twisted Cmd .我想一起使用它们.

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

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

#!/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()

除了制表符补全之外,这还可以工作.我可以输入"help"之类的命令,Cmd模块将打印结果.但是我已经失去了Cmd模块漂亮的制表符完成功能,因为Twisted一次缓冲一行.我尝试将LineProcessor.delimiter设置为空字符串,无济于事.也许我需要找到其他一些Twisted来代替LineReceiver使用?或者,也许有一种更简单的方法可以避免我必须一个一个地处理每个字符?

我不能单独使用Cmd,因为我想使它成为网络应用程序,在该应用程序中某些命令将导致发送数据,并且从网络接收数据将异步发生(并显示给用户).

因此,无论我们是从上面的代码开始还是完全不同的东西,我都想用Python构建一个不错的,友好的终端应用程序,以响应网络事件以及制表符完成.我希望我可以使用已有的东西,而不必自己过多实施.

解决方案

使用此方法会遇到很多困难:

  • 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()

I like Python's Twisted and Cmd. I want to use them together.

I got some things working, but so far I haven't figured out how to make tab-completion work, because I don't see how to receive tab keypres events right away (without pressing Enter) in Twisted's LineReceiver.

Here's my code so far:

#!/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()

Apart from tab completion, this somewhat works. I can enter a command like "help" and the Cmd module will print the results. But I've lost the nifty tab-complete functionality of the Cmd module, because Twisted is buffering one line at a time. I tried setting LineProcessor.delimiter to the empty string, to no avail. Maybe I need to find some other piece of Twisted to use instead of LineReceiver? Or maybe there's a simpler approach that will avoid my having to process every character one-by-one?

I can't use Cmd alone, because I want to make this a network application, where some commands will result in sending data, and receiving data from the network will happen asynchronously (and be displayed to the user).

So whether we start from the above code or something completely different, I'd like to build a nice, friendly terminal application in Python that responds to network events and also to tab completion. I hope I can use what's already out there and not have to implement too much myself.

解决方案

You have a couple of difficulties with this approach:

  • Cmd.onecmd is not going to do any tab processing.
  • Even if it did, your terminal needs to be in cbreak mode in order for individual keystrokes to make it to the Python interpreter (tty.setcbreak can take care of that).
  • As you know, Cmd.cmdloop is not reactor aware and will block waiting for input.
  • Yet, to get all of the cool line-editing you want, Cmd (actually readline) needs to have direct access to stdin and stdout.

Given all of these difficulties, you might want to look at letting the CommandProcessor run in its own thread. For example:

#!/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()

这篇关于Python Twisted与Cmd模块的集成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆