2012-01-07 5 views
5

現在、コマンドラインインターフェイス用のcmd.Cmdモジュールを使用するアプリケーションがあり、タブ補完は完全に機能します。sys.stdoutが置き換えられたときのcmd.CmdのPython readlineタブ補完

今、私は別のオブジェクトと、sys.stdoutを交換したいのですが(書かれているもの捕捉するために、例えば。)

スニペットは、理論的には完全に透明でなければならないの後、すべての設定/操作するには、GetとしてStdオブジェクトはsys.__stdout__にリダイレクトされます。例えば

class Std(object): 
    def __getattribute__(self, name): 
     if name in ('__getattribute__', '__setattr__'): 
      return object.__getattribute__(self, name) 
     else: 
      return getattr(sys.__stdout__, name) 

    def __setattr__(self, name, value): 
     setattr(sys.__stdout__, name, value) 

sys.stdout = Std() 

sys.stdout.fileno()はまだしかし、Cmd.cmdのreadlineタブ補完は、もはや今動作しない1. を印刷されません...

さて、ファイルを継承してみましょう。

class Std(file): 
    def __init__(self): 
     pass 
    def __getattribute__(self, name): 
     if name in ('__getattribute__', '__setattr__'): 
      return object.__getattribute__(self, name) 
     else: 
      return getattr(sys.__stdout__, name) 

    def __setattr__(self, name, value): 
     setattr(sys.__stdout__, name, value) 

sys.stdout = Std() 

(stdoutがファイルオブジェクトである)そして今、私が手:

Traceback (most recent call last): 
    File "./shell.py", line 61, in <module> 
    print '#1' 
ValueError: I/O operation on closed file 

ただし、次のアサーションが失敗しない:

assert not sys.stdout.closed 

をどういうわけか、私は推測する、Pythonがあります過度に最適化し、Std.writeをバイパスします。

readlineサポートを失うことなく、stdoutを置き換えるにはどうすればよいですか?

ジョナサン

-edit-

私はまた、sys.stdinをを交換しようとしています。 raw_inputがreadlineサポートに使用され、Pythonのraw_inputがファイル記述子を受け入れないため、cmd.Cmdに渡すことはできません。 sys.stdinに割り当てられているptyに戻ります。

新しいpty(os.openpty()を使用して)を作成し、このペアをsys.stdin/outに割り当てると、そのptyを通じてreadline autocompletionが完璧に機能しますが、プロキシオブジェクトにラップされると、オートコンプリートはありません。

のreadlineのソースを理解しようとするが、それは簡単ではありません。 http://svn.python.org/projects/python/branches/release25-maint/Modules/readline.c

答えて

1

sys.stdoutを交換しても動作しませんが、いずれにしても、あなたが渡すことによって、あなたの当面の問題を修正することができ、なぜ私は正確には分かりませんcmd.Cmdのコンストラクタへの独自のファイルオブジェクト。ここで

はタブ補完を実証(一部PyMOTWから借りた)サンプルスクリプト、次のとおりです。あなたの目的のために

import sys, cmd 

class Std(object): 
    def __getattribute__(self, name): 
     if name in ('__getattribute__', '__setattr__'): 
      return object.__getattribute__(self, name) 
     else: 
      return getattr(sys.__stdout__, name) 

    def __setattr__(self, name, value): 
     setattr(sys.__stdout__, name, value) 

class HelloWorld(cmd.Cmd): 
    FRIENDS = [ 'Alice', 'Adam', 'Barbara', 'Bob' ] 

    def do_greet(self, person): 
     "Greet the person" 
     if person and person in self.FRIENDS: 
      greeting = 'hi, %s!' % person 
     elif person: 
      greeting = "hello, " + person 
     else: 
      greeting = 'hello' 
     print greeting 

    def complete_greet(self, text, line, begidx, endidx): 
     if not text: 
      completions = self.FRIENDS[:] 
     else: 
      completions = [f for f in self.FRIENDS 
          if f.startswith(text)] 
     return completions 

    def do_EOF(self, line): 
     return True 

if __name__ == '__main__': 

    HelloWorld(stdout=Std()).cmdloop() 

それはあなただけであることが保証されますので、これは、物事のより良い方法です。あなたのCmdインスタンスが生成する出力をキャプチャします。

渡すファイルオブジェクトは、Cmdインスタンスのstdout属性としても利用できます。

+0

ありがとうございますが、これは本当に役に立ちません。 'cmd.Cmd .__ init__'では、stdoutがNoneであるかどうかチェックされます。そうであれば、sys.stdoutにフォールバックします。つまり、sys.stdin/outignと同じです。 –

+0

@ JonathanSlenders私はそれを最初にテストせずにソリューションを提供していないでしょう。私にとっては、タブ補完で問題を解決します。 'stdin'のテストは、元の質問の一部ではなかったので、私はしませんでしたが、[cmd.Cmd]のドキュメントを読んでいました(http://docs.python.org/library/cmd.html #cmd.Cmd)および[use_rawinput](http://docs.python.org/library/cmd.html#cmd.Cmd.use_rawinput)を参照してください。 – ekhumoro

+0

@JonathanSlenders私はテストのために使ったスクリプトで自分の答えを更新しました。 – ekhumoro