使用pytest正确导入

NcA*_*ams 35 python import pytest

我刚刚设置为使用python与Python 2.6.到目前为止,除了处理"导入"语句之外,它运行良好:我似乎无法以与我的程序相同的方式响应导入.

我的目录结构如下:

src/
    main.py
    util.py
    test/
        test_util.py
    geom/
        vector.py
        region.py
        test/
            test_vector.py
            test_region.py
Run Code Online (Sandbox Code Playgroud)

要运行,我python main.py从src/调用.

在main.py中,我导入了vector和region

from geom.region import Region
from geom.vector import Vector
Run Code Online (Sandbox Code Playgroud)

在vector.py中,我导入了区域

from geom.region import Region
Run Code Online (Sandbox Code Playgroud)

当我在标准运行中运行代码时,这些都可以正常工作.但是,当我从src /调用"py.test"时,它会一直退出导入错误.


一些问题和我的解决方案尝试

我的第一个问题是,当运行"test/test_foo.py"时,py.test无法直接"导入foo.py".我通过使用"imp"工具解决了这个问题.在"test_util.py"中:

import imp
util = imp.load_source("util", "util.py")
Run Code Online (Sandbox Code Playgroud)

这适用于许多文件.它似乎也暗示当pytest运行"path/test/test_foo.py"来测试"path/foo.py"时,它基于目录"path".

但是,"test_vector.py"失败了.Pytest可以找到并导入vector模块,但它无法找到任何vector的进口.使用pytest时,以下导入(来自"vector.py")都会失败:

from geom.region import *
from region import *
Run Code Online (Sandbox Code Playgroud)

这些都给出了表格的错误

ImportError: No module named [geom.region / region]
Run Code Online (Sandbox Code Playgroud)

我不知道接下来要做什么来解决这个问题; 我对Python中导入的理解是有限的.

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


编辑:非常黑客的解决方案

vector.py,我更改了import语句

from geom.region import Region
Run Code Online (Sandbox Code Playgroud)

简单地说

from region import Region
Run Code Online (Sandbox Code Playgroud)

这使得导入相对于"vector.py"目录.

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

import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))
Run Code Online (Sandbox Code Playgroud)

这使Python能够从"geom/test/test_vector.py"中找到"../region.py".

这是有效的,但它似乎非常有问题,因为我在路径中添加了大量的新目录.我正在寻找的是

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

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

所以我将这个问题留给这些问题的答案.

off*_*pta 21

如果您在测试目录中包含一个__init__.py文件,那么当程序要设置主目录时,它将“向上”移动,直到找到不包含 init 文件的主目录。在这种情况下 src/.

从这里你可以通过说导入:

from geom.region import *
Run Code Online (Sandbox Code Playgroud)

您还必须确保在任何其他子目录中都有一个 init 文件,例如其他嵌套的测试目录

  • 这是一个正确的答案(而且非常短!)!只需在测试目录中创建一个空的“__init__.py”并输入“from import geom.region import *” (2认同)

Cur*_*son 16

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

Pytest 通过查找不包含文件的文件级别或更高级别的第一个目录,并声明包含从该文件生成的模块的模块树的"basedir" 来提供此测试包名称__init__.py.然后它sys.path使用模块名称将basedir添加到前面并导入,该模块名称将找到相对于basedir的文件.

您应该注意这一点的一些含义:

  1. 基本路径可能与您的预期基路径不匹配,在这种情况下,模块的名称将与您通常使用的名称不匹配.例如,你所认为的geom.test.test_vector实际上将刚刚任命test_vector的Pytest运行过程中,因为它没有发现__init__.pysrc/geom/test/,因此补充说,到路径.

  2. 如果不同目录中的两个文件具有相同的名称,则可能会遇到模块命名冲突.例如,缺少sys.path文件的任何地方,添加__init__.py将与冲突geom/test/test_util.py,因为两者都加载test/test_util.py,既import test_util.pytest/路径.

您在这里使用的系统,没有显式geom/test/模块,就是让Python 为您的目录创建隐式命名空间包.(包是一个带有子模块的模块.)理想情况下,我们将为Pytest配置一个路径,从中也可以生成它,但它似乎不知道如何做到这一点.

这里最简单的解决方案就是将空__init__.py文件添加到所有子目录下__init__.py; 这将导致Pytest使用以目录名开头的包/模块名称导入所有内容src/.

  • 我不明白这一点,似乎存在一些混乱,因为大多数评论都是关于“测试”目录下的“__init__.py”,而您的大部分谈话似乎都是关于“tests”目录下的“__init__.py”应用程序(即在“src”目录下)。在“src”下(包括“src”)下的每个目录下添加“__init__.py”并不能解决应用程序文件无法导入同级文件的极其令人烦恼的问题。您是否有机会尝试更多地解释一下实现这一目标所需采取的步骤? (4认同)
  • 我的问题是测试文件夹中缺少__init__.py。谢谢。 (3认同)
  • 似乎每个测试文件夹(任何级别)都应该有一个“__init__.py”。 (3认同)

Jos*_*rez 15

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

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

sys.path中是结合的结果主目录, PYTHONPATH标准库目录.你正在做什么,修改 sys.path是正确的.这是我经常做的事情.如果您不喜欢使用 sys.path,可以尝试使用 PYTHONPATH


小智 9

很晚才回答这个问题,但使用 python 3.9 或 3.10 你只需要__init__.py在测试文件夹中添加文件夹。

当你添加这个文件时,python 将此文件夹解释为一个模块。会是这样

src/
main.py
util.py
test/
    __init__.py
    test_util.py
geom/
    vector.py
    region.py
    test/
        __init__.py
        test_vector.py
        test_region.py
Run Code Online (Sandbox Code Playgroud)

所以你就跑吧pytest

抱歉我的英语不好


Joe*_*mig 6

我想知道该怎么办这个问题.看了这篇文章,并玩了一下,我想出了一个优雅的解决方案.我创建了一个名为"test_setup.py"的文件,并将以下代码放入其中:

import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
Run Code Online (Sandbox Code Playgroud)

我把这个文件放在顶级目录(例如src)中.当pytest从顶级目录运行时,它将运行包括此文件在内的所有测试文件,因为该文件的前缀为"test".文件中没有测试,但它仍然运行,因为它以"test"开头.

代码将test_setup.py文件的当前目录名附加到测试环境中的系统路径.这只会进行一次,因此路径中没有添加任何东西.

然后,从任何测试函数中,您可以导入相对于该顶级文件夹的模块(例如import geom.region),并且它知道在将src目录添加到路径之后的位置.

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

pytest test_setup.py test\test_util.py
Run Code Online (Sandbox Code Playgroud)

这将运行test_setup和test_util代码,以便仍可以使用test_setup代码.