2017-06-01 14 views
1

readlineをインポートして私のプログラムにカスタマイズされたタブ補完を追加しました。今私はプログラムの出力を保存する必要がありますが、stdoutをリダイレクトしようとすると、タブの完成機能が損なわれます。Pythonモジュール "readline"が出力リダイレクトを処理できません

私はpython3 script.py | tee txt.txtの魔女がstdoutとテキストファイルの両方に最も近いように見えましたが、うまくいきませんでした。ここ

は(念のため)、メインからの関数呼び出しを使用してカスタムタブ補完クラスです:stdoutに書かれたものも取得するように、「サル・パッチ」sys.stdout.write方法:

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

[おそらく関連するPythonの問題](https://bugs.python.org/issue24829)背景:readlineは対話型端末で動作するように設計されていますが、出力を別の場所にリダイレクトすると(たとえ 'tee'のように返すとしても)、端末はreadlineに対して非対話的に見えるようになります。 –

+1

( 'tee'ではなく)対話的セッションの出力を記録したい場合は、' typescript'を使用するほうがいいでしょうか? –

答えて

0

ここで可能な解決策ですファイルに送信されます。私はこれがちょうどエレガントではないことを認めますが、それは機能します。 ;)

LoggerクラスをContext Managerクラスにして、withステートメントで使用できるようにしました。

:あなたは withを使用しない場合

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

デモ

> 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 

、あなたはこのようなLoggerを使用することができます

関連する問題