使用pytest正确导入

时间:2014-09-13 20:02:50

标签: python import pytest

我刚刚设置为在Python 2.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

要运行,我从src /.

调用python main.py

在main.py中,我用

导入了vector和region
from geom.region import Region
from geom.vector import Vector

在vector.py中,我用

导入区域
from geom.region import Region

当我在标准运行中运行代码时,这些都可以正常工作。但是,当我打电话给" py.test"来自src /,它一直以导入错误退出。


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

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

import imp
util = imp.load_source("util", "util.py")

这适用于许多文件。它似乎也意味着当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 *

这两个都给出了

形式的错误
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"的目录。如下路径:

import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))

这使Python能够找到" ../ region.py"来自" geom / test / test_vector.py"。

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

1)与pytest或

兼容的导入策略

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

所以我将这个问题留待这些问题解答。

4 个答案:

答案 0 :(得分:13)

import 查看以下目录以查找模块:

  1. 该计划的主目录。这是根脚本的目录。当您运行pytest时,您的主目录是安装它的位置(可能是/ usr / local / bin)。无论你是从src目录运行它,因为pytest的位置决定了你的主目录。这就是为什么它找不到模块的原因。
  2. PYTHONPATH 即可。这是一个环境变量。您可以从操作系统的命令行进行设置。在Linux / Unix系统中,您可以执行以下操作:' 导出PYTHONPATH = / your / custom / path '如果您希望Python从测试目录中找到您的模块,则应在此变量中包含src路径。
  3. 标准库目录。这是安装所有库的目录。
  4. 使用 pth 文件时,有一个不太常见的选项。
  5. sys.path 是将主目录 PYTHONPATH 标准相结合的结果库目录。您正在做什么,修改 sys.path 是正确的。这是我经常做的事情。您可以尝试使用 PYTHONPATH ,如果您不想搞乱 sys.path

答案 1 :(得分:9)

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

您可以从这里说:

from geom.region import *

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

答案 2 :(得分:7)

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

Pytest通过查找不包含__init__.py文件的文件级别或更高级别的第一个目录,并声明包含模块树的模块树的“basedir”来找到这个test package name。从该文件生成的模块。然后它将basedir添加到sys.path并使用模块名称导入,该模块名称将相对于basedir找到该文件。

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

  1. 基本路径可能与您预期的基本路径不匹配,在这种情况下,模块的名称与您通常使用的名称不匹配。例如,您认为geom.test.test_vector在Pytest运行期间实际上只会被test_vector命名,因为它在__init__.py中找不到src/geom/test/,因此将该目录添加到{{1} }}

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

  3. 您在此处使用的系统(没有明确的geom/test/模块)正在为您的目录创建implicit namespace packages。 (包是一个带有子模块的模块。)理想情况下,我们将为Pytest配置一个路径,它也会生成它,但它似乎不知道如何做到这一点。

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

    问题How do I Pytest a project using PEP 420 namespace packages?讨论了其他解决方案。

答案 3 :(得分:6)

我想知道该怎么办这个问题。看了这篇文章,并玩了一下,我想出了一个优雅的解决方案。我创建了一个名为" 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_setup和test_util代码,以便仍然可以使用test_setup代码。