【问题标题】:unicode_literals and doctest in Python 2.7 AND Python 3.5Python 2.7 和 Python 3.5 中的 unicode_literals 和 doctest
【发布时间】:2017-06-28 18:19:06
【问题描述】:

考虑以下演示脚本:

# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import unicode_literals

def myDivi():
    """
    This is a small demo that just returns the output of a divison.
    >>> myDivi()
    0.5
    """
    return 1/2

def myUnic():
    """
    This is a small demo that just returns a string.
    >>> myUnic()
    'abc'
    """
    return 'abc'

if __name__ == "__main__":
    import doctest
    extraglobs = {}
    doctest.testmod(extraglobs=extraglobs)

doctest 在 Python 3.5 上通过,但在 Python 2.7.9 上失败。
奇怪的是,除法测试有效,但 unicode 测试失败。

我看过各种问题,包括以下问题

但它们都有些不同(例如,它们已过时(指 Py 2.6 或 Py 3.0),import 语句在 doctest 中而不是全局范围内,使用 pytest 而不是标准 doctest,切换到不同的 assert 等)
尽管如此,我还是根据这些问题尝试了各种替代方案,包括例如

if __name__ == "__main__":
    import doctest
    import __future__
    extraglobs = {'unicode_literals': __future__.unicode_literals}
    doctest.testmod(extraglobs=extraglobs)

或

def myUnic():
    """
    This is a small demo that just returns a string.
    >>> myUnic()
    u'abc' # doctest: +ALLOW_UNICODE
    """
    return 'abc'

但它仍然无法正常工作,无论是在 Python 2 还是 3 上,或者出现其他错误。
有没有办法让它在 3.5+ 和 2.7.9+ 上都通过,而没有丑陋的黑客? 我也使用这些文档字符串来生成文档,所以我希望它们或多或少保持原样。

【问题讨论】:

标签: python-3.x python-2.x doctest unicode-literals


【解决方案1】:

这使用纯 doctest 完成工作:

if __name__ == "__main__":
    import doctest, sys, logging, re
    from doctest import DocTestFinder, DocTestRunner
    # Support print in doctests.
    L_ = logging.getLogger(":")
    logging.basicConfig(level=logging.DEBUG)
    pr = print = lambda *xs: L_.debug(" ".join(repr(x) for x in xs))

    # Make doctest think u"" and "" is the same.
    class Py23DocChecker(doctest.OutputChecker, object):
        RE = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)

        def remove_u(self, want, got):
            if sys.version_info[0] < 3:
                return (re.sub(self.RE, r'\1\2', want), re.sub(
                    self.RE, r'\1\2', got))
            else:
                return want, got

        def check_output(self, want, got, optionflags):
            want, got = self.remove_u(want, got)
            return super(Py23DocChecker, self).check_output(
                want, got, optionflags)

        def output_difference(self, example, got, optionflags):
            example.want, got = self.remove_u(example.want, got)
            return super(Py23DocChecker, self).output_difference(
                example, got, optionflags)

    finder = DocTestFinder()
    runner = DocTestRunner(checker=Py23DocChecker())
    for test in finder.find(sys.modules.get('__main__')):
        runner.run(test)
    runner.summarize()
  • 将 u"foo" 视为与 "foo" 相同
  • 在运行文档测试时使用 print("foo") 或 pr("foo") 进行调试。这仅在您仅将 print 用于调试目的时才有效。

我从不记得的地方偷走了大部分。感谢这些互联网的无名英雄。

【讨论】:

    【解决方案2】:

    与Multi version support for Python doctests 中的 Martijn Pieters cmets 一致,我建议依靠使用一些真实单元测试框架进行测试。

    您仍然可以使用 doctest 字符串,因为它们可能对文档很有用。为未来着想,为 Python 3 编写它们。同时,为另一个单元测试框架编写单元测试。不要依赖 doctest 来获取您的应用程序/模块的 Python 2 版本。

    【讨论】:

      猜你喜欢
      • 2018-12-24
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      • 2016-02-18
      • 2014-05-16
      • 1970-01-01
      • 2016-11-26
      • 2015-12-25
      相关资源
      最近更新 更多