关于python:Pytest,目录结构和导入错误

Pytest, directory structure and import errors

我正在用python编写我的第一个项目,我发现python和pytest令人沮丧的是,使目录结构和导入模块工作起来很复杂。

我有这样的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
Football
  football
    __init__.py
    file1.py
    file2.py
    file3.py
    main.py
  tests
    context.py
    test_file1.py
    test_file2.py
    test_file3.py

显然,这些文件的名称与上面的示例中的不同。

当我想从file1.py或main.py中的file2.py导入类file2时,然后在file1.py或main.py中写入:

1
from file2 import File2

context.py文件的内容是:

1
2
3
4
5
import os
import sys

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import football

这就是其中一个测试文件(例如"test_file1.py")的内容或多或少的样子:

1
2
from context import football
from football.file1 import File1

当我运行football/main.py时,它就工作了。

但是当我运行pytest时,我或多或少会得到这样的错误:

1
2
3
football/file1.py:2: in <module>
from file2 import File2
E   ImportError: No module named 'file2'

因此,它正确导入"file1.py"文件,但当该文件导入"file2.py"时,会引发无法导入的错误(尽管当我运行football/main.py而不进行测试时,此导入会起作用)。

那么,如何让所有这些导入都工作并且在测试期间没有错误呢?


您需要将__init__.py添加到您的足球/足球目录中,以便发现python包。然后,您可以做的一件事是在项目的根级别添加一个setup.py,在这个级别中使用find_packages()递归地查找要添加到python路径中的包。然后,在运行测试之前,您必须将项目安装到虚拟环境中。像tox这样的工具可以在调用测试命令之前自动设置虚拟环境,从而更容易完成这些步骤。

另一个选项是使用monkeypatch fixture(一个pytest内置)并修改测试的pythonpath。你可以把它放到tests/conftest.py中。不过,您仍然需要在足球/足球目录中创建一个__init__.py

1
2
3
4
@pytest.fixture(autouse=True)  # run this automatically before tests
def pythonpath(monkeypatch):
    path_to_project ="<path to your project root>"
    monkeypatch.setenv('PYTHONPATH', path_to_project)