python 2.7,3.x doctest兼容性与FileNotFoundError

时间:2017-05-06 06:11:04

标签: python python-2.7 python-3.x

编写适用于Python 2.7和Python 3.x的代码的doctests和示例时,we typically use # doctest: +IGNORE_EXCEPTION_DETAIL to paper over differences between Python 2.x and 3.x tracebacks。例如,这会照顾BarError vs music.BarError,但它会因OSError(errno.ENOENT, ...)IOError(errno.ENOENT, ...)而分崩离析,因为,请参阅:

import errno

def testme():
    """
    Test doctest vs ENOENT

    >>> testme()
    Traceback (most recent call last):
        ...
    OSError: [Errno 2] so far so good
    """
    raise OSError(errno.ENOENT, 'so far so good')

if __name__ == '__main__':
    import doctest
    doctest.testmod()

当使用python2.7运行时,一切都很好:

$ python2 test3.py -v
Trying:
    testme()
Expecting:
    Traceback (most recent call last):
        ...
    OSError: [Errno 2] so far so good
ok
1 items had no tests:
    __main__
1 items passed all tests:
   1 tests in __main__.testme
1 tests in 2 items.
1 passed and 0 failed.
Test passed.

然而,当使用Python 3.x运行时:

$ python3 test3.py
**********************************************************************
File "test3.py", line 7, in __main__.testme
Failed example:
    testme()
Expected:
    Traceback (most recent call last):
        ...
    OSError: [Errno 2] so far so good
Got:
    Traceback (most recent call last):
      File "/usr/local/lib/python3.6/doctest.py", line 1330, in __run
        compileflags, 1), test.globs)
      File "<doctest __main__.testme[0]>", line 1, in <module>
        testme()
      File "test3.py", line 12, in testme
        raise OSError(errno.ENOENT, 'so far so good')
    FileNotFoundError: [Errno 2] so far so good
**********************************************************************
1 items had failures:
   1 of   1 in __main__.testme
***Test Failed*** 1 failures.

Python 3.6用OSError替换FileNotFoundError

同样的事情发生在IOError上。文件test4.py已将OSError替换为IOError中的raise和文档字符串。没有引用所有内容:

$ python2 test4.py
$ python3 test4.py
...
    FileNotFoundError: [Errno 2] so far so good
***Test Failed*** 1 failures.

使用IGNORE_EXCEPTION_DETAIL没有帮助,因为(显然)只会在错误消息中的第一个冒号之前跳过前缀.,这里的问题是字符串文字{{1 }和OSError vs IOError

我有一个基于装饰的解决方案,我将其作为答案包含在内,但是有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

我有一个基于装饰器的解决方案,这不是最漂亮的事情:

2

现在代码可以在python2(2.7)或python3(3.x)中运行。

装饰器可能有点聪明(例如,不将[Errno]硬编码为{{1}}值),但它可以工作。

有更好的解决方法吗?