我编写了一个python包,我已经设法与python 2.7和python 3.4完全兼容,但有一个例外是我到目前为止所困扰的。该软件包包含一个命令行脚本,在我的单元测试中,我使用此代码运行脚本的主例程,同时覆盖sys.argv以传递argparse的命令行参数,并捕获脚本的stdout以进行比较:
@contextlib.contextmanager
def runmain(mainfunction, arglist):
"""Run mainfunction with arglist in sys.srgv, and capture stdout."""
origargv, sys.argv = sys.argv, arglist
origout, sys.stdout = sys.stdout, io.StringIO()
rtn = mainfunction()
sys.stdout.seek(0)
yield (rtn, sys.stdout.read())
sys.stdout = origout
sys.argv = origargv
class test_imdutil_main(unittest.TestCase):
def test_help(self):
"""Test -h option."""
with runmain(imdutil_main, ['imdutil.py', '-h']) as (rtn, capture):
# do stuff with rtn and capture...
这在python 3.4中运行良好,但在python 2.7中它会生成错误:
TypeError: unicode argument expected, got 'str'
我还没有设法从python 2.7和python 3.4之间移植的任意函数中找到一种捕获stdout的方法。
顺便说一句,我不得不承认,我根本不了解装饰,上下文管理器或“yield”关键字。我的runmain()函数的灵感来自:
http://schinckel.net/2013/04/15/capture-and-test-sys.stdout-sys.stderr-in-unittest.testcase/
顺便提一下,我的完整包来自此代码:
https://github.com/NF6X/pyImageDisk
目前,由于此问题,其单元测试在python 2.7下部分被破坏。任何人都可以帮我弄清楚如何以便携式,pythonic方式解决这个stdout重定向问题,最好不要再添加任何外部依赖项?
您将仅使用Python的2字节sys.stdout
替换为仅使用Unicode的try:
# Python 2
from cStringIO import StringIO
except ImportError:
# Python 3
from io import StringIO
。您必须在此处调整Python版本的策略,并使用其他对象:
io.
并在上下文管理器中删除origout, sys.stdout = sys.stdout, StringIO()
前缀:
cStringIO.StringIO
io.BytesIO
对象是unicode
的Python 2等价物;它要求你写简单的字节串,而不是aio.BytesIO
对象。
你也可以在Python 2中使用sys.stdout
,但是你想测试io.TextIOBase
subclass是否是BytesIO
;如果不是,用二进制StringIO
对象替换对象,否则使用import io
if isinstance(sys.stdout, io.TextIOBase):
# Python 3
origout, sys.stdout = sys.stdout, io.StringIO()
else:
# Python 2 or an unorthodox binary stdout setup
origout, sys.stdout = sys.stdout, io.BytesIO()
对象:
from __future__ import unicode_literals
你试过吗? (可以留在Python 3.x下的代码中)
io.StringIO
还有我在我的代码中使用f = io.StringIO(datafile.read().decode('utf-8'), newline=None)
时使其兼容:
yield (rtn, sys.stdout.read())
看看你的代码然后:
yield (rtn, sys.stdout.read().decode('utf-8'))
可以改为:
qazxswpoi