簡體   English   中英

更換sys.stdout時,cmd.Cmd中的Python readline選項卡完成

[英]Python readline tab-completion in cmd.Cmd, when sys.stdout has been replaced

目前,我有一個應用程序,它使用cmd.Cmd模塊作為命令行界面,tab-completion完美地工作。

現在,我想用另一個對象替換sys.stdout (例如,為了捕獲正在編寫的內容。)

在理論上,以下代碼段應該是完全透明的,因為對Std對象的每個get / set操作都被重定向到actial 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()仍將打印1.但是, Cmd.cmd的readline選項卡完成現在不再有效...

好的,讓我們繼承文件。 (stdout是一個文件對象。)

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

現在我得到:

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應該怎么辦?

喬納森

-編輯-

我也試圖替換sys.stdin。 將其傳遞給cmd.Cmd不起作用,因為raw_input用於readline支持,而Python的raw_input不接受文件描述符。 它回退到分配給sys.stdin的pty。

當我創建一個新的pty(通過os.openpty()),並將該對賦值給sys.stdin / out時,通過該pty的readline自動完成工作完美,但同樣,當包裝在代理對象中時,它可以工作,但沒有自動完成。

試圖理解readline的來源,但這並不容易: http//svn.python.org/projects/python/branches/release25-maint/Modules/readline.c

sys.stdout地知道為什么替換sys.stdout不起作用,但無論如何你可以通過將自己的文件對象傳遞給cmd.Cmd的構造函數來解決你的問題。

這是一個示例腳本(部分借用PyMOTW ),演示了tab-completion:

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屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM