测试与Python包结构
我在整理我的Python项目时遇到了一些问题。目前我的项目就是一堆文件放在同一个文件夹里。我尝试把它整理成下面这样的结构:
proj/
__init__.py
foo.py
...
bar/
__init__.py
foobar.py
...
tests/
foo_test.py
foobar_test.py
...
问题是,我无法从内部目录导入外部目录的模块。这在测试时特别麻烦。
我看过关于相对导入的PEP 328和关于从主模块进行相对导入的PEP 366。但是这两种方法都要求基础包在我的PYTHONPATH中。实际上,我得到了以下错误信息:
ValueError: 尝试在非包中进行相对导入。
所以我在测试文件的顶部添加了以下模板代码:
import os, sys
sys.path.append(os.path.join(os.getcwd(), os.path.pardir))
但我仍然遇到同样的错误。正确的做法是:
- 如何结构化一个完整的包,包括测试,
- 以及如何将基础目录添加到路径中以允许导入?
编辑 根据评论的要求,我添加了一个失败的导入示例(在文件 foo_test.py
中)
import os, sys
sys.path.append(os.path.join(os.getcwd(), os.path.pardir))
from ..foo import Foo
2 个回答
我喜欢尽量使用完整的 proj.NAME
包前缀来导入模块。这是谷歌的Python风格指南推荐的方法。
为了保持你的包结构,使用完整的包路径,同时还能继续开发,你可以选择使用虚拟环境(virtualenv),并将你的项目设置为开发模式。你的项目中的 setup.py
文件需要使用 setuptools
而不是 distutils
,这样才能使用 develop
命令。
这样你就可以避免上面提到的 sys.path.append
的麻烦:
% virtualenv ~/virt
% . ~/virt/bin/activate
(virt)~% cd ~/myproject
(virt)~/myproject% python setup.py develop
(virt)~/myproject% python tests/foo_test.py
在这里, foo_test.py
使用了:
from proj.foo import Foo
现在,当你在虚拟环境中运行 python
时,你的 PYTHONPATH
会指向你项目中的所有包。你还可以创建一个更短的命令别名,这样就不用每次都输入 . ~/virt/bin/activate
来进入虚拟环境了。
当你使用 -m
这个选项来运行代码时,当前的文件夹会被添加到 sys.path
里。所以,运行你的测试的最简单方法就是在 proj
的上级目录下,使用以下命令:
python -m proj.tests.foo_test
为了让这个方法有效,你需要在你的测试文件夹里放一个 __init__.py
文件,这样测试才能被正确识别为这个包的一部分。