2011-12-19 16 views
6

Me gusta Python's Twisted y Cmd. Quiero usarlos juntos.Integración de Python Twisted con el módulo Cmd

Tengo algunas cosas en funcionamiento, pero hasta ahora no he descubierto cómo hacer que funcione la finalización de pestañas, porque no veo cómo recibir eventos de tecla de tabulación de forma inmediata (sin presionar Intro) en LineReceiver de Twisted.

Aquí está mi código hasta ahora:

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

Además de la implementación del tabulador, esto funciona en cierta medida. Puedo ingresar un comando como "ayuda" y el módulo Cmd imprimirá los resultados. Pero he perdido la ingeniosa funcionalidad de completar pestañas del módulo Cmd, porque Twisted está almacenando una línea por vez. Intenté configurar LineProcessor.delimiter en la cadena vacía, pero no sirvió. ¿Quizás necesito encontrar alguna otra pieza de Twisted para usar en lugar de LineReceiver? ¿O tal vez hay un enfoque más simple que evitará que tenga que procesar cada personaje uno por uno?

No puedo usar Cmd solo, porque quiero hacer de esto una aplicación de red, donde algunos comandos darán como resultado el envío de datos y la recepción de datos de la red ocurrirá de forma asincrónica (y se mostrará al usuario).

Entonces, ya sea que comencemos con el código anterior o algo completamente diferente, me gustaría construir una aplicación de terminal agradable y amigable en Python que responda a eventos de red y también a la finalización de pestañas. Espero poder usar lo que ya existe y no tener que implementar demasiado yo mismo.

+0

echar un vistazo a [trenzado de boca] (http://twistedmatrix.com/trac/wiki/TwistedConch), [ejemplo] (http://twistedmatrix.com/documents/current/conch /examples/demo_manhole.tac) – jfs

+0

Observé a Manhole y Conch, pero no tenían mucho sentido para mí por lo que estaba haciendo. La documentación describe a Conch como una implementación de SSHv2, tanto cliente como servidor, e ilustra cómo puede crear un servidor SSH que realice la coloración para sus clientes. Mis necesidades son similares y diferentes a eso. Si tienes una sugerencia más específica sobre cómo puedo usar Manhole, soy todo oídos ... uno de los problemas es la falta de documentación. –

Respuesta

9

usted tiene un par de problemas con este enfoque:

  • Cmd.onecmd no va a hacer ningún tipo de procesamiento pestaña.
  • Incluso si lo hizo, su terminal necesita estar en modo bloqueo para que las pulsaciones de teclas individuales lleguen al intérprete de Python (tty.setcbreak puede encargarse de eso).
  • Como usted sabe, Cmd.cmdloop no es consciente del reactor y bloqueará la espera de entrada.
  • Sin embargo, para obtener toda la genial edición de línea que desee, Cmd (en realidad readline) necesita tener acceso directo a stdin y stdout.

Dadas todas estas dificultades, es posible que desee ver dejar que CommandProcessor se ejecute en su propio hilo. Por ejemplo:

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

Estaba pensando en llamar a los métodos de finalización en el módulo Cmd yo mismo en las pulsaciones de tecla Tab. Gracias por señalar el colapso: no sabía de eso. Probaré tu enfoque, gracias por escribirlo. –

+0

De nada. Básicamente, readline es una aplicación de mini curses. Creo que terminará teniendo que volver a implementar la mayoría de sus funcionalidades si intenta mediar el acceso a stdin/stdout. Este enfoque permite gestionar directamente stdin/stdout (incluido el modo cbreak), lo que debería simplificar las cosas. –

+0

twisted.internet.threads.blockingCallFromThread es una función retorcida muy útil que permite que CommandProcessor obtenga el valor de retorno. –