2017-06-01 2 views
1

Ich habe readline importiert, um eine benutzerdefinierte Tab-Vervollständigung zu meinem Programm hinzuzufügen. Jetzt muss ich die Ausgabe des Programms speichern, aber jeder Versuch, stdout umzuleiten, bricht die Tab-Vervollständigungsfunktionalität.Das Python-Modul "readline" kann die Ausgabeumleitung nicht verarbeiten.

Ich probierte python3 script.py | tee txt.txt Hexe schien am nächsten zum Drucken zu sowohl stdout und eine Textdatei, aber es funktioniert nicht.

hier ist die individuelle Tabulatorvervollständigung Klasse mit Funktionsaufruf von main (für alle Fälle):

import readline 

class MyCompleter(object): 

    def __init__(self, options): 
     self.options = sorted(options) 

    def complete(self, text, state): 
     if state == 0: 
      if text: 
       self.matches = [s for s in self.options if s and s.startswith(text)] 
      else: 
       self.matches = self.options[:] 
     try: 
      return self.matches[state] 
     except IndexError: 
      return None 

def readlineset(a): # function called from main to turn on tab completion 
        # a is list of strings 
    readline.set_completer(MyCompleter(a).complete) 
    readline.parse_and_bind('tab: complete') 
+2

[Möglicherweise verwandt Python-Problem] (https://bugs.python.org/issue24829). Hintergrund: readline wurde entwickelt, um an interaktiven Terminals zu arbeiten, aber wenn die Ausgabe an einen anderen Ort umgeleitet wird (selbst wenn es zu Ihnen zurückreflektiert wird, wie "tee"), wird das Terminal für readline nicht interaktiv. –

+1

Vielleicht würden Sie lieber 'typescript' verwenden, wenn Sie die Ausgabe Ihrer interaktiven Sitzung (anstelle von' tee') aufzeichnen möchten? –

Antwort

0

Hier ist eine mögliche Lösung: „monkey-patch“ die sys.stdout.write Methode so, dass alles zu stdout geschrieben wird auch an eine Datei gesendet. Ich gebe zu, dass das nicht gerade elegant ist, aber es funktioniert. ;)

Ich habe die Logger Klasse ein Context Manager gemacht, so dass es in einer with Aussage verwendet werden kann.

import readline 
import sys 

class MyCompleter(object): 
    def __init__(self, options): 
     self.options = sorted(options) 

    def complete(self, text, state): 
     if state == 0: 
      if text: 
       self.matches = [s for s in self.options if s and s.startswith(text)] 
      else: 
       self.matches = self.options[:] 
     try: 
      return self.matches[state] 
     except IndexError: 
      return None 

class Logger(object): 
    ''' Monkey-patch sys.stdout 
     to copy output to a file 
    ''' 
    def __init__(self, fname): 
     self.fh = open(fname, 'w') 
     self.oldwrite = sys.stdout.write 
     sys.stdout.write = self.write 

    def write(self, s): 
     self.oldwrite(s) 
     self.fh.write(s) 

    def close(self): 
     self.fh.close() 
     sys.stdout.write = self.oldwrite 

    # Define Context Manager methods so Logger 
    # can be used in a `with` statement 
    def __enter__(self): 
     return self 

    def __exit__(self, *args): 
     self.close() 
     return False 

def readlineset(a): 
    ''' Turn on tab completion. 
     `a` is list of strings that will be completed 
    ''' 
    readline.set_completer(MyCompleter(a).complete) 
    readline.parse_and_bind('tab: complete') 

def main(): 
    readlineset(['python', 'stack', 'overflow', 'exchange']) 
    with Logger('mylog.txt'): 
     while True: 
      s = input('> ') 
      if s == 'quit': 
       break 
      print(repr(s), len(s)) 

    print('bye') 

if __name__ == '__main__': 
    main() 

Demo

> This is a test 
'This is a test' 14 
> python on stack overflow 
'python on stack overflow' 24 
> quit 
bye 

mylog.txt

'This is a test' 14 
'python on stack overflow' 24 

Wenn Sie nicht with verwenden möchten, können Sie Logger wie folgt verwenden:

def main(): 
    readlineset(['python', 'stack', 'overflow', 'exchange']) 
    logger = Logger('mylog.txt') 
    while True: 
     s = input('> ') 
     if s == 'quit': 
      break 
     print(repr(s), len(s)) 

    logger.close() 
    print('bye') 
Verwandte Themen