【问题标题】:Imports in Python project with doctests使用 doctest 在 Python 项目中导入
【发布时间】:2011-01-23 05:57:25
【问题描述】:

我有一个 Python 项目,其目录结构如下:

/(一些文件) /模型/(python文件) /tools/(更多 python 文件) ...

所以,我在几个子目录中有 Python 文件,其中有一些 目录之间的依赖关系:模型使用工具等。现在 我的问题是我想为 modelstools 制作文档测试, 我希望能够像这样从命令行运行测试: ./model/car.py 。 我可以完成这项工作,但只能使用凌乱的样板代码。我想 想知道什么是正确的方法,或者有什么方法吗?

问题:我应该如何编写我的导入?

谢谢。这是一个例子......

tools/tool.py的内容:

#!/usr/bin/env python
"""
   >>> is_four(21)
   False
   >>> is_four(4)
   True
"""

def is_four(val):
    return val == 4

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

...和model/car.py

#!/usr/bin/env python   
"""
   >>> car = Car()
   >>> car.ok()
   True
"""

from tools.tool import *

class Car(object):
    def __init__(self):
        self.tire_count = 4
    def ok(self):
        return is_four(self.tire_count)

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

通过在 car.py 的开头添加以下行,它可以工作,但看起来不太好。 :(

if __name__ == '__main__':
    import sys
    import os
    sys.path.append(os.path.abspath(os.path.dirname('..')))

【问题讨论】:

    标签: python linux unix path


    【解决方案1】:

    您正在尝试做的是相对导入。它在 Python 中运行良好,但在模块级别,而不是在文件系统级别。我知道,这很令人困惑。

    这意味着如果您在子目录中运行脚本,它不会看到上层目录,因为对于正在运行的脚本,模块的根是当前目录:没有上层模块。

    那么相对导入有什么用?

    好吧,子目录中的模块汽车在上层目录中导入模块,只要它们自己是从上层目录中导入的。

    在您的情况下,这意味着您必须从“/”运行脚本,使其成为模块的根,并且允许子模块使用相对导入。

    解决您的问题的一个可能方法是删除您的 if __name__ == "__main__" 块并创建 /tests.py:

    import doctest
    from model import car
    from tools import tool
    
    doctest.testmod(car)
    doctest.testmod(tool)
    

    然后运行也启动所有测试。

    最终您会希望流程自动化,一个简单的解决方案是使用 unittest,这样您就可以创建测试套件并添加您想要测试的模块名称:

    import unittest
    import doctest
    
    modules = ("model.car", 
               "tools.tool")
    
    suite = unittest.TestSuite()
    for mod in modules:
        suite.addTest(doctest.DocTestSuite(mod))
    runner = unittest.TextTestRunner()
    runner.run(suite)
    

    另一个解决方案(推荐)是使用诸如 nose 之类的工具来为您自动执行此操作。

    easy_install nose
    nosetests --with-doctest # done :-)
    

    顺便说一句,避免from x import *。这适用于快速脚本,但是当您的程序增长时,您确实需要明确命名您导入的内容。 import xfrom x import y

    【讨论】:

    • 也许这是最好的可用解决方案。缺点是现在我必须在一个套件中运行所有测试,并且有一些非常慢的网络相关测试。 :( 无论如何,感谢您的回答。nose 和未来 (?) 关键字包(来自 Pierre 链接的 PEP366)听起来也值得更多调查。
    【解决方案2】:

    使用包。将__init__.py 文件添加到您的工作目录和所有子文件夹,然后如果在当前目录中找不到模块,您的导入将搜索父目录。

    http://www.network-theory.co.uk/docs/pytut/Packages.html

    此问题也与以下内容重复:

    Import a module from a relative path

    【讨论】:

    • 其实我也试过了,也有相对导入,好像并没有解决OP的问题。有趣的是,这么简单的问题竟然如此令人费解……
    【解决方案3】:

    不要以这种方式与sys.path 联系。而是在调用python 时使用$PYTHONPATH 强制进入基目录,或者从该目录使用python -m model.car

    【讨论】:

    • 这似乎不对。您无法设置 env 以适应软件需求,否则部署会遇到麻烦。
    • @e-satis:使用部署,正确的条目已经在 sys.path 中,您无需接触环境。
    • 当您的用户想要测试您的模块时,您可以让他们选择是为您的应用程序的每个目录运行 python -m 还是将它们安装在站点包中?
    • @e-satis:测试并不是大多数用户都期望做的事情,所以让他们跳过一点点……并不是我真正关心的事情。如果有足够多的抱怨,那就扔给他们一个 shell 脚本或批处理文件。
    • 老实说,当我花时间测试一个模块时,如果它没有用鼻子开箱即用,我会跳到下一个......
    猜你喜欢
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    • 1970-01-01
    • 2021-04-20
    • 2017-12-09
    相关资源
    最近更新 更多