[英]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.