Python 使用pytest正确导入

Python 使用pytest正确导入,python,import,pytest,Python,Import,Pytest,我刚刚准备好在Python2.6中使用pytest。到目前为止,除了处理“import”语句外,它工作得很好:我似乎无法让pytest以与我的程序相同的方式响应导入 我的目录结构如下: src/ main.py util.py test/ test_util.py geom/ vector.py region.py test/ test_vector.py

我刚刚准备好在Python2.6中使用pytest。到目前为止,除了处理“import”语句外,它工作得很好:我似乎无法让pytest以与我的程序相同的方式响应导入

我的目录结构如下:

src/
    main.py
    util.py
    test/
        test_util.py
    geom/
        vector.py
        region.py
        test/
            test_vector.py
            test_region.py
import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))
要运行,我从src/调用
python main.py

在main.py中,我使用

from geom.region import Region
from geom.vector import Vector
from geom.region import Region
在vector.py中,我使用

from geom.region import Region
from geom.vector import Vector
from geom.region import Region
当我在标准运行中运行代码时,这些都可以正常工作。然而,当我从src/调用“py.test”时,它总是以导入错误的方式退出


一些问题和我的解决方法 我的第一个问题是,当运行“test/test\u foo.py”时,py.test不能直接“导入foo.py”。我用“imp”工具解决了这个问题。在“test_util.py”中:

这对许多文件都非常有效。这似乎还意味着,当pytest运行“path/test/test_foo.py”来测试“path/foo.py”时,它基于目录“path”

但是,对于“test_vector.py”,这将失败。Pytest可以找到并导入
向量
模块,但它无法找到任何
向量
的导入。使用pytest时,以下导入(来自“vector.py”)均失败:

from geom.region import *
from region import *
这两者都给出了形式上的错误

ImportError: No module named [geom.region / region]
我不知道下一步该怎么解决这个问题;我对Python导入的理解是有限的

使用pytest时,处理导入的正确方法是什么?


编辑:非常黑客的解决方案 在
vector.py
中,我将import语句从

from geom.region import Region
简单地

from region import Region
这使得导入相对于“vector.py”目录

接下来,在“test/test_vector.py”中,我将“vector.py”目录添加到路径中,如下所示:

src/
    main.py
    util.py
    test/
        test_util.py
    geom/
        vector.py
        region.py
        test/
            test_vector.py
            test_region.py
import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))
这使Python能够从“geom/test/test_vector.py”中查找“./region.py”

这是可行的,但问题似乎非常严重,因为我正在向路径中添加大量新目录。我要找的是

1) 与pytest兼容的导入策略,或

2) pytest中的一个选项,使其与我的导入策略兼容

因此,我将这个问题留给这些类型的答案。

import在以下目录中查找模块:

  • 程序的主目录。这是根脚本的目录。运行pytest时,主目录就是安装它的地方(/usr/local/bin)。无论您是从src目录运行它,因为pytest的位置决定了您的主目录。这就是它找不到模块的原因
  • 蟒蛇路径。这是一个环境变量。您可以从操作系统的命令行进行设置。在Linux/Unix系统中,可以通过执行:“export PYTHONPATH=/your/custom/path”来实现这一点。如果希望Python从测试目录中查找模块,则应在该变量中包含src路径
  • 标准库目录。这是安装所有库的目录
  • 使用pth文件有一个不太常见的选项

  • sys.path是将主目录PYTHONPATH标准库目录相结合的结果。您正在执行的操作,修改系统路径是正确的。这是我经常做的事。如果您不喜欢与sys.path混为一谈,可以尝试使用PYTHONPATH

    我也想知道如何解决这个问题。在阅读了这篇文章,并进行了一些尝试之后,我想出了一个优雅的解决方案。我创建了一个名为“test_setup.py”的文件,并将以下代码放入其中:

    import sys, os
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))
    
    我把这个文件放在顶层目录中(比如src)。当从顶级目录运行
    pytest
    时,它将运行包括此文件在内的所有测试文件,因为该文件的前缀为“test”。文件中没有测试,但它仍在运行,因为它以“test”开头

    代码将把test_setup.py文件的当前目录名附加到测试环境中的系统路径。这将只执行一次,因此不会向路径添加大量内容

    然后,从任何测试函数中,您可以导入与顶层文件夹相关的模块(例如
    import geom.region
    ),并且它知道在哪里可以找到它,因为src目录已添加到路径中

    如果要运行单个测试文件(例如test_util.py)而不是所有文件,则可以使用:

    pytest test_setup.py test\test_util.py
    

    这将运行test_设置和test_util代码,以便test_设置代码仍然可以使用。

    这里的问题是Pytest遍历文件系统以发现包含测试的文件,但随后需要生成一个模块名,该模块名将导致导入该文件。(记住,)

    Pytest通过查找不包含
    \uuuu init\uuuu.py
    文件的文件级别或其上的第一个目录,并声明包含从该文件生成的模块的模块树的“basedir”。然后,它将basedir添加到
    sys.path
    ,并使用模块名导入,该模块名将找到与basedir相关的文件

    您应该注意以下几点:

  • 基本路径可能与预期的基本路径不匹配,在这种情况下,模块的名称与您通常使用的名称不匹配。例如,在Pytest运行期间,您认为的
    geom.test.test\u vector
    实际上将被命名为
    test\u vector
    ,因为它在
    src/geom/test/
    中未找到
    \uuu init\uuuuuuuuuuuuuuuy
    ,因此将该目录添加到
    sys.path

  • 如果不同目录中的两个文件具有相同的名称,则可能会遇到模块命名冲突。例如,缺少
    \uuuu init\uuuuuu.py