Python项目目录结构 / pytest故障

68

这应该是世上最容易的问题之一,但即便经过了大量的搜索和尝试,我仍然在为找到一个“正确”的方法来布置目录结构并成功地运行pytest等工具而苦恼。

假设我有一个叫做apple的程序。

|- README.md
|- apple
|   |-- __init__.py
|   |-- apple.py
| - tests
|   |-- test_everything.py

apple.py包含一些函数,例如我们可以称其为eat()。而test_everything.py文件包含一些测试,如assert eat() ==“foobar”。到这里还好,但接下来就有趣了:

  • apple目录中的__init__.py应该是什么?空的还是要加入内容?
  • 从根目录调用py.test好还是从tests目录下调用更好?
  • 许多项目在其测试目录中都有__init__.py文件,但在py.test文档中明确说明这是错误的。为什么会这样?
  • test_everything.py文件的顶部应该是一个import apple还是from apple import *?还是其他的?
  • 您是通过eat()还是apple.eat()来调用函数的?
  • 甚至有人建议在python中操纵os.path.dirname

这似乎很容易,但我见过上述每种组合方式,更不用说tox和其他工具了。但只要稍有错误,你就会遇到一些奇怪的错误,比如ImportError: No module named 'apple'

什么是“正确”的方法?github等现有代码和建议遵循极其不同的惯例。对于中等经验的程序员来说,这应该会容易得多。


如果您创建了单独的测试,请将您的苹果别名源代码放入“src”目录中。 - droid192
2个回答

37
  1. apple目录中的__init__.py应该是空的还是有什么内容?

是的,通常为空。如果你在其中放置foo = 42,那么稍后可以使用from apple import foo进行调用,而如果将其放在apple.py中,则需要使用from apple.apple import foo进行调用。虽然这样做可能看起来很方便,但应该谨慎使用。

  1. 从根目录调用py.test最好的做法是什么?还是从测试目录py.test tests?

py.test应该能够找到你的测试文件,无论在哪里都可以。但参见下文...

  1. 许多项目在其测试目录中都有一个__init__.py,但在py.test文档中明确表示这是错误的。那么为什么还要这样做呢?

这样可以在测试中导入提供公共测试功能的文件。在py.test中,这可以通过在名为tests/conftest.py的文件中创建夹具来更好地实现。

  1. test_everything.py文件的开头是什么:import apple,还是from apple import *?还是其他内容?

from apple import apple

  1. 你是通过eat()还是apple.eat()来调用函数的?

apple.eat()

  1. 有些人甚至建议在Python中操纵os.path.dirname

那似乎非常脆弱。我建议:

(a) 将环境变量PYTHONPATH设置为指向README.md所在的文件夹,或者更好地

(b) 创建一个setup.py文件(与你的README.md文件处于同一级别),这里是一个最小的示例:

from setuptools import setup
setup(name='apple', packages=['apple'])

按如下方式运行文件:

python setup.py develop

现在 apple 已经全球可用,您不应再看到 no module named apple 的问题,即您可以从根目录或测试文件夹运行 py.test。

您可以在 Python 包装用户指南中阅读有关 setup.py 的更多信息,网址为 https://packaging.python.org/


2
我已经创建了一个存储库,展示如何使用“setup.py”方法完成任务。链接 - Seanny123
from apple import apple doesn't work inside test_everything.py: ModuleNotFoundError: No module named 'apple' - endolith
@endolith,它确实可以,尽管可能不适用于cwd = apple或者你没有运行setup.py develop等情况。这是一个2014年得分为7的被接受的答案,如果你无法使其工作,很有可能是你自己的问题 - 如果你留下缺乏上下文/细节的评论,你得到帮助的可能性要小得多,相比之下,提出一个新问题会更有帮助... - thebjorn

5
我已经准备好一个有效的示例,可以在这里查看。
我认为将模块都命名为apple可能会令人感到困惑,这也许是混淆的一个来源。在我看来,唯一不太明显的部分是,如果您没有使用适当的setup.py distutils软件包来安装您的apple包,则必须将PYTHONPATH设置为当前目录。

确实有些令人困惑。我原本的假设是 from apple import apple 中的第一个 'apple' 是指文件夹名称,因此是包名。而第二个 'apple' 则是指文件名,也就是模块名称。现在,为了真正设置好一个项目,必须正确配置和执行一个强制性的 setup.py 文件。我猜需要事先知道很多信息吧?比如我需要多少个包,它们应该如何命名。或者说,是否有一种常见的使用 setup.py 的工作流程?比如不时地运行 python setup.py 来��入新文件到项目中? - atripes
1
@atripes 通常只需要运行 python setup.py develop 或更好的 pip install -e .(注意点号,且必须在包含 setup.py 文件的目录中)。唯一需要重新运行它的时候是如果您有其他依赖于它的本地项目(即在其 requirements.txt 文件中有类似 -e ../apple 的内容),并且您更改了 setup 中的 install_requires 参数。这真的很简单 ;-) - thebjorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接