2011-12-19 9 views
6

Mi piace Python Twisted e Cmd. Voglio usarli insieme.Python Integrazione intrecciata con modulo Cmd

Ho alcune cose funzionanti, ma finora non ho capito come fare il lavoro di completamento delle tabulazioni, perché non vedo come ricevere gli eventi di keypres della scheda subito (senza premere Invio) in LineReceiver di Twisted.

Ecco il mio codice finora:

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

A parte il completamento automatico, questo funziona un po '. Posso inserire un comando come "help" e il modulo Cmd stamperà i risultati. Ma ho perso la funzionalità completa di tabulazione completa del modulo Cmd, perché Twisted sta tamponando una riga alla volta. Ho provato a impostare LineProcessor.delimiter sulla stringa vuota, inutilmente. Forse ho bisogno di trovare qualche altro pezzo di Twisted da usare al posto di LineReceiver? O forse c'è un approccio più semplice che eviterà di dover elaborare ogni personaggio uno per uno?

Non posso usare Cmd da solo, perché voglio fare di questa un'applicazione di rete, dove alcuni comandi si tradurranno nell'invio di dati, e la ricezione di dati dalla rete avverrà in modo asincrono (e mostrata all'utente).

Quindi, se iniziamo dal codice precedente o qualcosa di completamente diverso, mi piacerebbe creare un'applicazione terminale simpatica e intuitiva in Python che risponda agli eventi di rete e anche al completamento delle schede. Spero di poter usare ciò che è già là fuori e non dover implementare troppo me stesso.

+0

un'occhiata a [ritorto di botola] (http://twistedmatrix.com/trac/wiki/TwistedConch), [ad esempio] (http://twistedmatrix.com/documents/current/conch /examples/demo_manhole.tac) – jfs

+0

Ho notato Manhole e Conch ma non avevano molto senso per me per quello che sto facendo. La documentazione descrive Conch come un'implementazione SSHv2, sia client che server, e illustra come è possibile creare un server SSH che faccia colorazione per i propri client. I miei bisogni sono entrambi simili e diversi da quello. Se hai un suggerimento più specifico su come posso usare il tombino, sono tutto orecchie ... uno dei problemi con esso è una notevole mancanza di documentazione. –

risposta

9

avete un paio di problemi con questo approccio:

  • Cmd.onecmd non ha intenzione di fare qualsiasi elaborazione scheda.
  • Anche se così fosse, il terminale deve essere in modalità cbreak in modo che le singole combinazioni di tasti possano arrivare all'interprete Python (tty.setcbreak può occuparsene).
  • Come noto, Cmd.cmdloop non è a conoscenza del reattore e bloccherà l'attesa di input.
  • Tuttavia, per ottenere tutte le modifiche alla linea che desideri, Cmd (in realtà readline) deve avere accesso diretto a stdin e stdout.

Considerate tutte queste difficoltà, è possibile che si desideri consentire a CommandProcessor di eseguire il proprio thread. Per esempio:

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

Stavo pensando di chiamare i metodi di completamento nel modulo Cmd da solo sulla pressione dei tasti Tab. Grazie per aver segnalato il cbreak - non lo sapevo. Proverò il tuo approccio, grazie per averlo scritto. –

+0

Prego. Fondamentalmente, readline è un'applicazione mini curses. Penso che finirai per dover reimplementare la maggior parte delle sue funzionalità se proverai a mediare l'accesso a stdin/stdout. Questo approccio filettato consente di gestire direttamente stdin/stdout (inclusa la modalità cbreak) che dovrebbe semplificare le cose. –

+0

twisted.internet.threads.blockingCallFromThread è una funzione intrecciata molto utile che consente al CommandProcessor di ottenere il valore restituito. –