测试和python包结构

Tests and python package structure

我在构建Python项目时遇到了一些问题。目前它是同一文件夹中的一组文件。我试着把它设计成

1
2
3
4
5
6
7
8
9
10
11
12
proj/
  __init__.py
  foo.py
  ...
  bar/
    __init__.py
    foobar.py
    ...
  tests/
    foo_test.py
    foobar_test.py
    ...

问题是,我无法从内部目录从外部目录导入模块。这对测试尤其烦人。

我已经阅读了关于相对导入的PEP 328和关于主模块的相对导入的PEP 366。但这两种方法都要求基本包在我的pythonpath中。实际上,我得到了以下错误

ValueError: Attempted relative import in non-package.

所以我在测试文件的顶部添加了以下样板代码

1
2
import os, sys
sys.path.append(os.path.join(os.getcwd(), os.path.pardir))

但我还是有同样的错误。正确的方法是什么

  • 构建一个包含测试的包,以及
  • 是否将基目录添加到允许导入的路径?

根据注释中的要求进行编辑,我添加了一个失败的示例导入(在文件foo_test.py中)

1
2
3
import os, sys
sys.path.append(os.path.join(os.getcwd(), os.path.pardir))
from ..foo import Foo


当使用-m开关运行代码时,当前目录将添加到sys.path中。因此,运行测试的最简单方法是从proj的父目录中使用以下命令:

1
python -m proj.tests.foo_test

要实现这一点,您需要在测试目录中包含一个__init__.py文件,以便将测试正确地识别为包的一部分。


我喜欢尽可能使用完整的proj.NAME包前缀导入模块。这是google python样式指南推荐的方法。

允许您保留包结构、使用完整的包路径并继续进行开发的一个选项是使用virtualenv并将项目置于开发模式。你项目的setup.py需要使用setuptools而不是distutils来获取develop命令。

这样您就可以避免上面提到的sys.path.append类内容:

1
2
3
4
5
% virtualenv ~/virt
% . ~/virt/bin/activate
(virt)~% cd ~/myproject
(virt)~/myproject% python setup.py develop
(virt)~/myproject% python tests/foo_test.py

其中,foo_test.py使用:

1
from proj.foo import Foo

现在,当您在virtualenv中运行python时,您的PYTHONPATH将指向项目中的所有包。您可以创建一个较短的shell别名来输入virtualenv,而不必每次都键入. ~/virt/bin/activate