pytest的问题'导入错误:没有名为YadaYadaYada的模块'

Mat*_*odd 194 python unit-testing pytest

我使用easy_install在mac上安装pytest并开始为具有文件结构的项目编写测试,如下所示:

repo/
repo/app.py
repo/settings.py
repo/models.py
repo/tests/
repo/tests/test_app.py
Run Code Online (Sandbox Code Playgroud)

py.test在repo目录中运行时,一切都按预期运行

但是当我在linux或windows上尝试相同的东西时(两者都有pytest 2.2.3),每当它从我的应用程序路径首次导入某些东西时就会吠叫.比如说from app import some_def_in_app

我是否需要编辑我的PATH才能在这些系统上运行py.test?有没有人经历过这个?

Apt*_*ryx 236

我不确定为什么py.test不会在PYTHONPATH本身中添加当前目录,但这是一个解决方法(从存储库的根目录执行):

python -m pytest tests/
Run Code Online (Sandbox Code Playgroud)

它的工作原理是因为Python为您添加了PYTHONPATH中的当前目录.

  • 如果您有运行应用程序的代码不在执行命令的级别,则需要将相对导入重写为绝对导入。例如:`project/test/all-my-tests` 和 `project/src/app.py` 并且由于这一变化,需要使用 `__main__.py` 文件间接调用 `app.py` `project/src`,以便可以使用调用 `python -m src`。据我所知,相当凌乱的东西。 (3认同)
  • 我在测试中添加了`__init __.py`,解决了这个问题.现在我可以使用`pytest` (3认同)
  • @Zelphir:建议使用绝对导入.Habnabit有一篇关于打包最佳实践的好文章:http://blog.habnab.it/blog/2013/07/21/python-packages-and-you/,PEP8说"绝不应该使用隐式相对导入,已在Python 3中删除." 请参阅:https://www.python.org/dev/peps/pep-0008/. (2认同)
  • @Apteryx 您的意思是“绝对项目”,对吗?因为像 `/home/user/dev/projectxyz/src ...` 这样的东西在大多数情况下会非常糟糕并且不能在其他机器上运行。我想我的意思是,即使模块与文件运行在同一文件夹中,我也必须始终将整个项目根目录写入模块路径。我不知道这被认为是最佳实践,所以这是一个有用的信息,谢谢。我同意 pep8 的大部分内容,尽管它仍然不完美。 (2认同)
  • @Zelphir,是的,这就是我的意思。我相信 Python 中的绝对导入一词总是指“项目绝对”。请参阅:https://www.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports。事实上,我很确定你不能从随机的绝对路径位置导入,至少使用默认的“导入”机制。 (2认同)

Aro*_*zon 109

我有同样的问题.我通过__init__.py在我的tests目录中添加一个空文件来修复它.

  • 请注意,这是*不*由py.test推荐:`避免"__init__.py"文件在您的测试目录中.这样,您的测试可以轻松地针对已安装的mypkg版本运行,如果它包含测试,则独立于已安装的软件包.SRC:http://pytest.org/latest/goodpractises.html (72认同)
  • 我带着同样的问题来到这里,发现从我的测试目录中删除`__init __.py`为我解决了这个问题. (23认同)
  • 你去了:http://doc.pytest.org/en/latest/goodpractices.html很容易找到谷歌. (6认同)
  • 在`test /`的子目录中添加`__init __.py`使得绝对导入工作可以在该子目录中针对要安装的模块运行特定测试.谢谢. (5认同)
  • @mafro我没有看到问题?测试不必是可导入的代码,测试运行者可以找到它们.只有要测试的代码应该是已安装的软件包/模块,而不是测试. (3认同)
  • 通过查看https://docs.pytest.org/zh-CN/latest/goodpractices.html(当前最新== pytest-4.0),不再弃用测试路径中的__init__.py文件。如果您具有更大的测试主体并想模块化您的代码(是的,测试代码!),这对我来说非常有意义。 (3认同)
  • @ K.-MichaelAye如果测试目录不是包,你应该如何在测试中导入模块? (2认同)
  • 测试代码不应该使用相对导入,是的.明智的导入方式,您应该将测试代码视为不是软件包的一部分,而只是通过已安装的软件包名称导入所有内容.但是,我还是看不出这样理论上如何通过将测试代码作为包来解决? (2认同)
  • @K.-MichaelAye 链接已失效 (2认同)

hoe*_*ing 105

conftest

最小侵入性的解决方案是添加一个名为的空文件conftest.pyrepo/目录:

$ touch repo/conftest.py
Run Code Online (Sandbox Code Playgroud)

而已.无需编写自定义代码来修改sys.path或记住拖动PYTHONPATH,或放入__init__.py不属于它的dirs.

之后的项目目录:

repo
??? conftest.py
??? app.py
??? settings.py
??? models.py
??? tests
     ??? test_app.py
Run Code Online (Sandbox Code Playgroud)

说明

pytest查找conftest测试集合上的模块以收集自定义挂钩和夹具,并且为了从中导入自定义对象,pytest将其父目录添加conftest.pysys.path.

其他项目结构

如果您有其他项目结构,请将其repo放在包根目录(包含包但包含自身的包,但包含包conftest.py)中,例如:

repo
??? conftest.py
??? spam
?   ??? __init__.py
?   ??? bacon.py
?   ??? egg.py
??? eggs
?   ??? __init__.py
?   ??? sausage.py
??? tests
     ??? test_bacon.py
     ??? test_egg.py
Run Code Online (Sandbox Code Playgroud)

用同样的方法__init__.py布局:发生srcsrc目录:

repo
??? src
?   ??? conftest.py
?   ??? spam
?   ?   ??? __init__.py
?   ?   ??? bacon.py
?   ?   ??? egg.py
?   ??? eggs 
?       ??? __init__.py
?       ??? sausage.py
??? tests
     ??? test_bacon.py
     ??? test_egg.py
Run Code Online (Sandbox Code Playgroud)

从这往哪儿走

当然,conftest.py模块不仅仅是一些帮助源代码发现的文件; 它是src框架的所有项目特定增强和测试套件定制的所在.src有很多关于PYTHONPATH分散在整个文档中的模块的信息; 开头src:本地每目录插件

另外,SO对src模块有一个很好的问题:在py.test中,conftest.py文件有什么用?

  • 从逻辑上讲,“conftest.py”不属于应用程序代码,并且在我看来,将其放在“src/”下是不正确的。 (4认同)
  • 这是行不通的,就这么简单。尝试将文件放在根目录中,然后从测试中导入该文件。将 PYTHONPATH 设置为 root 工作正常,这个 hack 根本没有帮助。 (2认同)
  • @aaa90210 虽然我无法重现您的问题(从根目录中的 conftest 导入在任何级别都有效),但您永远不应从 conftest 文件导入,因为它是 `pytest` 的保留名称,强烈建议不要这样做。通过这样做,您可以为未来的错误播下种子。创建另一个名为 `utils.py` 的模块,并将在测试中重用的代码放在那里。 (2认同)

Not*_*fer 77

是的,如果你cd到tests目录,源文件夹不在Python的路径中.

你有2个选择:

  1. 手动将路径添加到测试文件,如下所示:

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用env var运行测试PYTHONPATH=../.

  • 什么时候我在CD目录?我从我的根运行`py.test`.除非我弄错了你的意思是因为pytest走过我的文件夹 (10认同)
  • 是的,但我的目录结构通常略有不同 - 我通常将/ src和/ test保存在根目录下. (4认同)

Ste*_*ina 39

pytest自身作为模块运行: python -m pytest tests

  • 当项目层次结构是例如:```package/src package/tests```和```你从`src`导入时,会发生这种情况.作为模块执行会将导入视为绝对值而不是相对于执行位置. (4认同)
  • 来自 [Pytest](https://docs.pytest.org/en/latest/pythonpath.html#pythonpath) “使用 python -m pytest [...] 而不是 pytest [...] 运行 pytest 会产生几乎相同的行为,除了前一个调用会将当前目录添加到 sys.path 中。” (4认同)
  • 这似乎是一个可行的解决方案,但是有人可以解释为什么吗?我宁愿解决根本原因,而不是只使用`python -m pytest`而不作任何其他解释,而不是“因为它起作用” (3认同)

For*_*Guo 37

您可以在项目根目录中使用PYTHONPATH运行

PYTHONPATH=. py.test
Run Code Online (Sandbox Code Playgroud)

或者使用pip install作为可编辑导入

pip install -e .   # install package using setup.py in editable mode
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说不起作用,`test`目录不在`src`目录结构中,并且从包含`test`和`src`目录的目录中调用. (3认同)

小智 22

我在 Flask 中遇到了同样的问题。

当我添加:

__init__.py
Run Code Online (Sandbox Code Playgroud)

到测试文件夹,问题消失了:)

可能应用程序无法将文件夹测试识别为模块


Jef*_*ald 21

我创建这个作为你的问题的答案和我自己的困惑.我希望它有所帮助.注意py.test命令行和tox.ini中的PYTHONPATH.

https://github.com/jeffmacdonald/pytest_test

具体来说:你必须告诉py.test和tox在哪里找到你所包含的模块.

使用py.test,你可以这样做:

PYTHONPATH=. py.test
Run Code Online (Sandbox Code Playgroud)

使用tox,将其添加到tox.ini中:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}
Run Code Online (Sandbox Code Playgroud)

  • 虽然并非绝对必要,但通常的政策是在答案本身中包含答案的主要内容,因为它确保答案在x年后可以理解,因为链接的资源可能早已消失. (5认同)

Til*_*lus 9

有点遗憾的是,这是 Python 中的一个问题......但仅添加这个环境变量是最舒服的方法,IMO:

export PYTHONPATH=$PYTHONPATH:.
Run Code Online (Sandbox Code Playgroud)

您可以将此行放入.zshrc.bashrc文件中。

  • 这确实是一种耻辱,而不是半点耻辱。 (5认同)

jba*_*sko 7

ConftestImportFailure: ImportError('No module named ...当我不小心将__init__.py文件添加到我的src目录(不应该是Python包,只是所有源的容器)时,我开始得到奇怪的错误.


Gon*_*alo 5

我通过删除__init__.py源文件的父文件夹中的顶层来修复它。

  • 为我修好了。有人可以解释一下吗? (2认同)

Lui*_*ldi 5

我在遵循 Flask 教程时遇到了同样的问题,我在官方 Pytest文档中找到了答案 这与我(以及我认为许多其他人)习惯做事的方式略有不同。

您必须setup.py在项目的根目录中创建一个至少包含以下两行的文件:

from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())
Run Code Online (Sandbox Code Playgroud)

其中 PACKAGENAME 是您的应用程序的名称。然后你必须用pip安装它:

pip install -e .
Run Code Online (Sandbox Code Playgroud)

-e标志告诉 pip 以可编辑或“开发”模式安装包。因此,下次运行pytest它时应该会在标准PYTHONPATH.