可以在Python doctest的行首放省略号吗?
Python 的 doctests 很酷。让我先给你一个简单的例子:
def foo():
"""
>>> foo()
hello world
"""
print "hello world"
现在假设有些部分是变化的,比如说时间值或者随机数。一般来说,doctests 允许我使用 +ELLIPSIS 选项来指定一个通配符。
当“world”是一个变化的字符串时,这个方法很好用:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
hello ...
"""
print "hello world"
但是在我的情况下,变化的字符串是在行的开头:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
... world
"""
print "hello world"
这就不好了,因为行首的三个点被当作行继续符号,而不是输出的省略号。所以,这个测试失败了:
Failed example:
foo() # doctest: +ELLIPSIS
world
Expected nothing
Got:
hello world
所以,我可以重写我的代码,把变化的部分放在别的地方,但有没有办法让 doctest 知道行首的三个点是省略号呢?
5 个回答
5
这里有一个比较简单的方法来实现这个功能:
在你不知道输出内容的那一行之前,先打印一个假字符串。
像这样:
def foo():
"""
>>> print 'ignore'; foo() # doctest: +ELLIPSIS
ignore... world
"""
print "hello world"
8
你可以更新一下 ELLIPSIS_MARKER
,这样 ...
就不会和换行的点搞混了:
def foo():
"""
>>> import doctest
>>> doctest.ELLIPSIS_MARKER = '-ignore-'
>>> foo()
hello world
>>> foo() # doctest: +ELLIPSIS
-ignore- world
"""
print "hello world"
if __name__ == "__main__":
import doctest
doctest.testmod()
免责声明: 上面的例子在以
$ py.test --doctest-module foo.py
或者
$ python foo.py
的方式运行 doctests 时是有效的。
不过,我不太明白的是,当通过
$ python -m doctest foo.py
来运行 doctests 时,这个方法就不管用了。
11
这里有个简单粗暴的解决办法:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
[...] world
"""
print "hello world"
if __name__ == "__main__":
import doctest
OC = doctest.OutputChecker
class AEOutputChecker(OC):
def check_output(self, want, got, optionflags):
from re import sub
if optionflags & doctest.ELLIPSIS:
want = sub(r'\[\.\.\.\]', '...', want)
return OC.check_output(self, want, got, optionflags)
doctest.OutputChecker = AEOutputChecker
doctest.testmod()
这个方法仍然能识别正常的省略号(...),但它增加了一种新的省略号([...]),这样就不会引起行首的混淆了。
对于 doctest 来说,判断是否有行继续的内容或者是行首的省略号,真的很难。理论上可以通过创建一个 DocTestParser 的子类来实现这个功能,但这样做可能会很麻烦。
在复杂的情况下,你可能需要自己写一个 DocTestRunner,使用新的 OutputChecker,而不是用普通的 testmod,但在简单的场景下,这个方法应该就够用了。