def captureOutput(self, func, *args, **kwargs):
pass
sys.stdout.flush()
sys.stderr.flush()
(outfd, fn) = tempfile.mkstemp()
fout = os.fdopen(outfd, 'r')
os.unlink(fn)
(errfd, fn) = tempfile.mkstemp()
ferr = os.fdopen(errfd, 'r')
os.unlink(fn)
try:
oldstdout = os.dup(sys.stdout.fileno())
oldstderr = os.dup(sys.stderr.fileno())
os.dup2(outfd, sys.stdout.fileno())
os.dup2(errfd, sys.stderr.fileno())
try:
ret = func(*args, **kwargs)
finally:
sys.stderr.flush()
sys.stdout.flush()
os.dup2(oldstdout, sys.stdout.fileno())
os.close(oldstdout)
os.dup2(oldstderr, sys.stderr.fileno())
os.close(oldstderr)
os.lseek(outfd, 0, 0)
out = fout.read()
os.lseek(errfd, 0, 0)
err = ferr.read()
finally:
fout.close()
ferr.close()
return ret, out, err
运行此代码时,出现错误:
AttributeError: StringIO instance has no attribute 'fileno'
为什么我会收到此错误,如何更正?
答案 0 :(得分:13)
{1}}方法未在StringIO中实现,因为它不是真实文件(因此没有关联的文件描述符)。来自消息来源:
fileno()
有人可能会使用StringIO实例替换- fileno() is left unimplemented so that code which uses it
triggers an exception early.
来捕获输出。
例如,当我以这种方式运行代码时,我得到了相同的异常:
sys.stdout
错误:
from StringIO import StringIO
sys.stdout = StringIO()
captureOutput(testfunc)
最好从头到尾跟踪代码,寻找覆盖 oldstdout = os.dup(sys.stdout.fileno())
AttributeError: StringIO instance has no attribute 'fileno'
的点。这是一个link to another answer I gave,显示如何使用跟踪活动来执行代码:
sys.stdout
答案 1 :(得分:5)
您使用的是标准的普通python解释器吗?当您使用覆盖stdout / stderr的解释器(例如IDLE)时可能会出现此错误(尽管IDLE本身会给您一个不同的错误)。它也可能是由一个覆盖stdout / stderr的库引起的。
有时您可以通过编写sys.stdout = sys.__stdout__
将stdout重置为默认标准输出,但不要指望它始终有效。例如,它在Pythonwin中不起作用。
无论如何,您尝试对代码执行的操作似乎是自己重定向stdout / stderr。如果是这样的话,你应该继续这样做。如果您有文件描述符outfd
和errfd
:
sys.stdout = os.fdopen(outfd, 'w')
sys.stderr = os.fdopen(errfd, 'w')
现在我可以看到你的整个代码,我根本不会使用临时文件。
def captureOutput(self, func, *args, **kwargs):
import cStringIO # You can also use StringIO instead
sys.stderr.flush()
sys.stdout.flush()
olderr, oldout = sys.stderr, sys.stdout
try:
sys.stderr = cStringIO.StringIO()
sys.stdout = cStringIO.StringIO()
try:
ret = func(*args, **kwargs)
finally:
stderr.seek(0)
stdout.seek(0)
err = stderr.read()
out = stdout.read()
finally:
sys.stderr = olderr
sys.stdout = oldout
return ret, out, err
答案 2 :(得分:1)
我的猜测是代码中的其他地方,sys.stdout或sys.stderr被重新分配为StringIO的一个实例。这个代码运行在什么环境(比如某些Web框架,来自命令行)?这可能会让熟悉该环境的人知道正确的答案。
答案 3 :(得分:1)
简短的回答是您遇到了标准库中的错误。 StringIO不符合其IOBase基类的合同。有些类写入IOBase类接口,然后失败。
更具体地说,Subprocess.run()或其他一些函数使用了IOBase fileno函数。子类StringIO抛出此异常,因为它不是真正的子类。在某个地方,IOBase的许多用户之一失败了。记录StringIO对此没有帮助。
你可以围绕它编码。或者可能不是。像contextlib.redirect_stdout()这样的各种函数都会失败。