简体   繁体   English

pytest 'ImportError: No module named YadaYadaYada' 的 PATH 问题

[英]PATH issue with pytest 'ImportError: No module named YadaYadaYada'

I used easy_install to install pytest on a mac and started writing tests for a project with a file structure likes so:我使用 easy_install 在 Mac 上安装 pytest 并开始为具有如下文件结构的项目编写测试:

repo/
   |--app.py
   |--settings.py
   |--models.py
   |--tests/
          |--test_app.py

run py.test while in the repo directory, everything behaves as you would expect在 repo 目录中运行py.test ,一切都如你所料

but when I try that same thing on either linux or windows (both have pytest 2.2.3 on them) it barks whenever it hits its first import of something from my application path.但是当我在 linux 或 windows 上尝试同样的事情时(两者都有 pytest 2.2.3),每当它从我的应用程序路径中第一次导入某些东西时,它就会吠叫。 Say for instance from app import some_def_in_app例如from app import some_def_in_app

Do I need to be editing my PATH to run py.test on these systems?我是否需要编辑我的 PATH 才能在这些系统上运行 py.test? Has Anyone experienced this?有没有人经历过这个?

I'm not sure why py.test does not add the current directory in the PYTHONPATH itself, but here's a workaround (to be executed from the root of your repository):我不确定为什么 py.test 没有在 PYTHONPATH 本身中添加当前目录,但这里有一个解决方法(从存储库的根目录执行):

python -m pytest tests/

It works because Python adds the current directory in the PYTHONPATH for you.它之所以有效,是因为 Python 会为您在 PYTHONPATH 中添加当前目录。

Recommended approach for pytest>=7 : use the pythonpath setting pytest>=7的推荐方法:使用pythonpath设置

Recently, pytest has added a new core plugin that supports sys.path modifications via the pythonpath configuration value .最近, pytest新增了一个核心插件,支持通过pythonpath配置值修改sys.path The solution is thus much simpler now and doesn't require any workarounds anymore:因此,该解决方案现在要简单得多,并且不再需要任何解决方法:

pyproject.toml example: pyproject.toml示例:

[tool.pytest.ini_options]
pythonpath = [
  "."
]

pytest.ini example: pytest.ini示例:

[pytest]
pythonpath = .

The path entries are calculated relative to the rootdir, thus .路径条目是相对于根目录计算的,因此. adds repo directory to sys.path in this case.在这种情况下,将repo目录添加到sys.path

Multiple path entries are also allowed: for a layout还允许多个路径条目:对于布局

repo/
├── src/
|   └── lib.py
├── app.py
└── tests
     ├── test_app.py
     └── test_lib.py

the configuration配置

[tool.pytest.ini_options]
pythonpath = [
  ".", "src",
]

or或者

[pytest]
pythonpath = . src

will add both app and lib modules to sys.path , soapplib模块都添加到sys.path ,所以

import app
import lib

will both work.两者都可以。

Original answer (not recommended for recent pytest versions; use for pytest<7 only): conftest solution原始答案(不推荐用于最近的 pytest 版本;仅用于pytest<7 ): conftest解决方案

The least invasive solution is adding an empty file named conftest.py in the repo/ directory:侵入性最小的解决方案是在repo/目录中添加一个名为conftest.py的空文件:

$ touch repo/conftest.py

That's it.而已。 No need to write custom code for mangling the sys.path or remember to drag PYTHONPATH along, or placing __init__.py into dirs where it doesn't belong (using python -m pytest as suggested in Apteryx 's answer is a good solution though!).无需编写自定义代码来修改sys.path或记住拖动PYTHONPATH或将__init__.py放入不属于它的目录中(使用python -m pytestApteryx答案中所建议的那样是一个很好的解决方案!)。

The project directory afterwards:之后的项目目录:

repo
├── conftest.py
├── app.py
├── settings.py
├── models.py
└── tests
     └── test_app.py

Explanation解释

pytest looks for the conftest modules on test collection to gather custom hooks and fixtures, and in order to import the custom objects from them, pytest adds the parent directory of the conftest.py to the sys.path (in this case the repo directory). pytest在测试集合上查找conftest模块以收集自定义钩子和固定装置,为了从中导入自定义对象, pytestconftest.py的父目录添加到sys.path (在本例中为repo目录) .

Other project structures其他项目结构

If you have other project structure, place the conftest.py in the package root dir (the one that contains packages but is not a package itself, so does not contain an __init__.py ), for example:如果您有其他项目结构,请将conftest.py放在包根目录中(包含包但本身不是包的目录,因此包含__init__.py ),例如:

repo
├── conftest.py
├── spam
│   ├── __init__.py
│   ├── bacon.py
│   └── egg.py
├── eggs
│   ├── __init__.py
│   └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

src layout src布局

Although this approach can be used with the src layout (place conftest.py in the src dir):虽然这种方法可以与src布局一起使用(将conftest.py放在src目录中):

repo
├── src
│   ├── conftest.py
│   ├── spam
│   │   ├── __init__.py
│   │   ├── bacon.py
│   │   └── egg.py
│   └── eggs 
│       ├── __init__.py
│       └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

beware that adding src to PYTHONPATH mitigates the meaning and benefits of the src layout!请注意,将src添加到PYTHONPATH会减轻src布局的意义和好处! You will end up with testing the code from repository and not the installed package.您最终将测试来自存储库的代码,而不是已安装的包。 If you need to do it, maybe you don't need the src dir at all.如果你需要这样做,也许你根本不需要src目录。

Where to go from here从这往哪儿走

Of course, conftest modules are not just some files to help the source code discovery;当然, conftest模块不仅仅是一些帮助源代码发现的文件; it's where all the project-specific enhancements of the pytest framework and the customization of your test suite happen.它是pytest框架的所有特定于项目的增强和测试套件的定制发生的地方。 pytest has a lot of information on conftest modules scattered throughout their docs ; pytest有很多关于conftest模块的信息,分散在他们的文档中; start with conftest.py : local per-directory pluginsconftest.py开始:本地每个目录插件

Also, SO has an excellent question on conftest modules: In py.test, what is the use of conftest.py files?此外,SO 对conftest模块有一个很好的问题:在 py.test 中,conftest.py 文件有什么用?

I had the same problem.我有同样的问题。 I fixed it by adding an empty __init__.py file to my tests directory.我通过在我的tests目录中添加一个空的__init__.py文件来修复它。

Yes, the source folder is not in Python's path if you cd to the tests directory.是的,如果您cd到测试目录,则源文件夹不在 Python 的路径中。

You have 2 choices:您有 2 个选择:

  1. Add the path manually to the test files, something like this:手动将路径添加到测试文件中,如下所示:

     import sys, os myPath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, myPath + '/../')
  2. Run the tests with the env var PYTHONPATH=../ .使用 env var PYTHONPATH=../运行测试。

pytest本身作为一个模块运行: python -m pytest tests

You can run with PYTHONPATH in project root您可以在项目根目录中使用 PYTHONPATH 运行

PYTHONPATH=. py.test

Or use pip install as editable import或者使用 pip install 作为可编辑的导入

pip install -e .   # install package using setup.py in editable mode

I had the same problem in Flask.我在 Flask 中遇到了同样的问题。

When I added:当我添加:

__init__.py

to tests folder, problem disappeared :)到测试文件夹,问题消失了:)

Probably application couldn't recognize folder tests as module可能应用程序无法将文件夹测试识别为模块

I created this as an answer to your question and my own confusion.我创建这个是为了回答你的问题和我自己的困惑。 I hope it helps.我希望它有所帮助。 Pay attention to PYTHONPATH in both the py.test command line and in the tox.ini.注意 py.test 命令行和 tox.ini 中的 PYTHONPATH。

https://github.com/jeffmacdonald/pytest_test https://github.com/jeffmacdonald/pytest_test

Specifically: You have to tell py.test and tox where to find the modules you are including.具体来说:您必须告诉 py.test 和 tox 在哪里可以找到您所包含的模块。

With py.test you can do this:使用 py.test 你可以这样做:

PYTHONPATH=. py.test

And with tox, add this to your tox.ini:使用 tox,将其添加到您的 tox.ini 中:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}

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

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

I was having the same problem when following the Flask tutorial and I found the answer on the official Pytest docs It's a little shift from the way I (and I think many others) are used to do things.我在学习 Flask 教程时遇到了同样的问题,我在 Pytest 官方文档中找到了答案。这与我(我认为许多其他人)习惯做事的方式有点不同。

You have to create a setup.py file in your project's root directory with at least the following two lines:您必须在项目的根目录中创建一个setup.py文件,其中至少包含以下两行:

from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())

where PACKAGENAME is your app's name.其中 PACKAGENAME 是您的应用程序的名称。 Then you have to install it with pip:然后你必须用 pip 安装它:

pip install -e .

The -e flag tells pip to intall the package in editable or "develop" mode. -e标志告诉 pip 以可编辑或“开发”模式安装包。 So the next time you run pytest it should find your app in the standard PYTHONPATH .因此,下次您运行pytest时,它应该会在标准PYTHONPATH中找到您的应用程序。

It is a bit of a shame that this is an issue in python... But just add this environment variable is the most comfortable way IMO:这是python中的一个问题有点遗憾......但只需添加这个环境变量是IMO最舒服的方式:

export PYTHONPATH=$PYTHONPATH:.

Just put this in you .zshrc/.bashrc.只需将其放入您的 .zshrc/.bashrc 中。

I had a similar issue.我有一个类似的问题。 pytest did not recognize a module installed in the environment I was working in. pytest无法识别安装在我工作环境中的模块。

I resolved it by also installing pytest into the same environment.我通过将pytest安装到同一环境中来解决它。

Also if you run pytest within your virtual environment make sure pytest module is installed within your virtual environment.此外,如果您在虚拟环境中运行pytest ,请确保在您的虚拟环境中安装pytest模块。 Activate your virtual env and run pip install pytest .激活您的虚拟环境并运行pip install pytest

For me the problem was tests.py generated by Django along with tests directory.对我来说,问题是 Django 生成的tests.py以及tests目录。 Removing tests.py solved the problem.删除tests.py解决了这个问题。

I got this error as I used relative imports incorrectly.我收到了这个错误,因为我错误地使用了相对导入。 In the OP example, test_app.py should import functions using eg在 OP 示例中,test_app.py 应该使用例如导入函数

from repo.app import *

However liberally __init__.py files are scattered around the file structure, this does not work and creates the kind of ImportError seen unless the files and test files are in the same directory.然而 __init__.py 文件散布在文件结构周围,这不起作用并创建了 ImportError 类型,除非文件和测试文件位于同一目录中。

from app import *

Here's an example of what I had to do with one of my projects:这是我对我的一个项目所做的一个例子:

Here's my project structure:这是我的项目结构:

microbit/
microbit/activity_indicator/activity_indicator.py
microbit/tests/test_activity_indicator.py

To be able to access activity_indicator.py from test_activity_indicator.py I needed to:为了能够从 test_activity_indicator.py 访问 activity_indicator.py,我需要:

  • start test_activity_indicatory.py with the correct relative import:使用正确的相对导入启动 test_activity_indicatory.py:
    from microbit.activity_indicator.activity_indicator import *
  • put __init__.py files throughout the project structure:将 __init__.py 文件放在整个项目结构中:
    microbit/
    microbit/__init__.py
    microbit/activity_indicator/__init__.py
    microbit/activity_indicator/activity_indicator.py
    microbit/tests/__init__.py
    microbit/tests/test_activity_indicator.py

I was getting this error due to something even simpler (you could even say trivial).由于更简单的事情(你甚至可以说微不足道),我得到了这个错误。 I hadn't installed the pytest module.我没有安装pytest模块。 So a simple apt install python-pytest fixed it for me.所以一个简单的apt install python-pytest为我修复了它。

'pytest' would have been listed in setup.py as a test dependency. 'pytest' 将作为测试依赖项列在 setup.py 中。 Make sure you install the test requirements as well.确保您也安装了测试要求。

Since no one has suggested it, you could also pass the path to the tests in your pytest.ini file:由于没有人建议,您也可以在pytest.ini文件中传递测试路径:

[pytest]
...
testpaths = repo/tests

see documentation: https://docs.pytest.org/en/6.2.x/customize.html#pytest-ini请参阅文档: https ://docs.pytest.org/en/6.2.x/customize.html#pytest-ini

Side effect for VScode: it should pick up the unit test in the UI. VScode 的副作用:它应该在 UI 中进行单元测试。

According to a post on Medium by Dirk Avery (and supported by my personal experience) if you're using a virtual environment for your project then you can't use a system-wide install of pytest;根据Dirk Avery 在 Medium 上的一篇文章(并得到我个人经验的支持),如果您在项目中使用虚拟环境,那么您不能使用系统范围的 pytest 安装; you have to install it in the virtual environment and use that install.您必须在虚拟环境中安装它并使用该安装。

In particular, if you have it installed in both places then simply running the pytest command won't work because it will be using the system install.特别是,如果您在两个地方都安装了它,那么简单地运行pytest命令将不起作用,因为它将使用系统安装。 As the other answers have described, one simple solution is to run python -m pytest instead of pytest ;正如其他答案所描述的,一个简单的解决方案是运行python -m pytest而不是pytest this works because it uses the environment's version of pytest.这是有效的,因为它使用环境的 pytest 版本。 Alternatively, you can just uninstall the system's version of pytest;或者,您可以只卸载系统版本的 pytest; after reactivating the virtual environment the pytest command should work.重新激活虚拟环境后, pytest命令应该可以工作。

As pointed out by Luiz Lezcano Arialdi , the correct solution is to install your package as an editable package.正如Luiz Lezcano Arialdi所指出的,正确的解决方案是将您的包安装为可编辑的包。

Since I am using pipenv, I thought about adding to his answer a step-by-step how to install the current path as an edible with pipenv, allowing to run pytest without the need of any mangling code or loose files.由于我使用的是 pipenv,我考虑在他的答案中逐步添加如何使用 pipenv 将当前路径安装为可食用的,从而允许运行 pytest 而无需任何修改代码或松散文件。

You will need to have the following minimal folder structure ( documentation ):您将需要具有以下最小文件夹结构(文档):

package/
    package/
        __init__.py
        module.py
    tests/
        module_test.py
    setup.py

setup.py most have the following minium code ( documentation ): setup.py 大多数具有以下最小代码( 文档):

import setuptools


setuptools.setup(name='package', # Change to your package name
                 packages=setuptools.find_packages())

Then you just need to run pipenv install --dev -e .然后你只需要运行pipenv install --dev -e . and pipenv will install the current path as an editable package (the --dev flag is optional) ( documentation ).并且 pipenv 会将当前路径安装为可编辑的包( --dev 标志是可选的)( 文档)。

Now you shoul be able to run pytest without problems.现在你应该可以毫无问题地运行pytest了。

我们通过添加以下环境变量解决了这个问题。

PYTHONPATH=${PYTHONPATH}:${PWD}/src:${PWD}/test

If this pytest error appears not for your own package, but for a git-installed package in your package's requirements.txt, the solution is to switch to editable installation mode.如果这个pytest错误出现的不是你自己的包,而是你包的requirements.txt中一个git安装的包,解决方法是切换到可编辑安装模式。

For example, suppose your package's requirements.txt had the following line:例如,假设您的包的 requirements.txt 有以下行:

git+https://github.com/foo/bar.git

You would instead replace it with the following:您可以将其替换为以下内容:

-e git+https://github.com/foo/bar.git#egg=bar

Very often the tests were interrupted due to module being unable to be imported,After research, I found out that the system is looking at the file in the wrong place and we can easily overcome the problem by copying the file, containing the module, in the same folder as stated, in order to be properly imported.很多时候由于模块无法导入而中断测试,经过研究,我发现系统在错误的位置查看文件,我们可以通过复制包含模块的文件轻松解决问题,在与所述相同的文件夹,以便正确导入。 Another solution proposal would be to change the declaration for the import and show MutPy the correct path of the unit.另一个解决方案建议是更改导入的声明并向 MutPy 显示单元的正确路径。 However, due to the fact that multiple units can have this dependency, meaning we need to commit changes also in their declarations, we prefer to simply move the unit to the folder.然而,由于多个单元可以具有这种依赖关系,这意味着我们还需要在它们的声明中提交更改,我们更喜欢简单地将单元移动到文件夹中。

My solution:我的解决方案:

create the conftest.py file in the test directory containing:test目录中创建conftest.py文件,其中包含:

import os
import sys
sys.path.insert(0,os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/code/")

This will add the folder of interest to the python path without modifying every test file , setting env variable or messing with absolute/relative paths.这会将感兴趣的文件夹添加到 python 路径中,而无需修改每个测试文件、设置环境变量或弄乱绝对/相对路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM