测试与Python包结构

9 投票
2 回答
4553 浏览
提问于 2025-04-16 13:01

我在整理我的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 个回答

5

我喜欢尽量使用完整的 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 来进入虚拟环境了。

13

当你使用 -m 这个选项来运行代码时,当前的文件夹会被添加到 sys.path 里。所以,运行你的测试的最简单方法就是在 proj 的上级目录下,使用以下命令:

python -m proj.tests.foo_test

为了让这个方法有效,你需要在你的测试文件夹里放一个 __init__.py 文件,这样测试才能被正确识别为这个包的一部分。

撰写回答