pytest的PATH问题“ ImportError:没有名为YadaYadaYada的模块”

问题:pytest的PATH问题“ ImportError:没有名为YadaYadaYada的模块”

我使用easy_install在Mac上安装pytest,并开始为文件结构像这样的项目编写测试:

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

py.test在repo目录中运行时,所有行为均符合您的预期

但是,当我在linux或Windows上尝试相同的操作时(两者上都装有pytest 2.2.3),只要它从我的应用程序路径中首次导入某些内容,它就会发出吠声。举例来说from app import some_def_in_app

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

I used easy_install to install pytest on a mac and started writing tests for a project with a file structure likes so:

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

run py.test while in the repo directory, everything behaves as you would expect

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. Say for instance from app import some_def_in_app

Do I need to be editing my PATH to run py.test on these systems? Has Anyone experienced this?


回答 0

是的,如果您cd转到tests目录,则源文件夹不在Python的路径中。

您有2个选择:

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

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

Yes, the source folder is not in Python’s path if you cd to the tests directory.

You have 2 choices:

  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=../.


回答 1

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

python -m pytest tests/

之所以有效,是因为Python为您添加了当前目录到PYTHONPATH中。

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):

python -m pytest tests/

It works because Python adds the current directory in the PYTHONPATH for you.


回答 2

conftest

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

$ touch repo/conftest.py

而已。无需编写自定义代码来处理,sys.path也无需记住拖动PYTHONPATH或放入__init__.py不属于它的目录中。

之后的项目目录:

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

说明

pytestconftest在测试集合中寻找模块以收集自定义的钩子和固定装置,然后为了从中导入自定义的对象,请将pytest的父目录添加conftest.py到中sys.path(在本例中为repo目录)。

其他项目结构

如果你有其他的项目结构,将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 布局

尽管此方法可用于src布局(放置conftest.pysrc目录中):

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

请注意,添加srcPYTHONPATH减轻src布局的含义和好处!您将最终从存储库而不是已安装的软件包中测试代码。如果需要执行此操作,则可能根本不需要src目录。

从这往哪儿走

当然,conftest模块不仅仅是一些文件,可以帮助发现源代码。这是pytest框架的所有特定于项目的增强和测试套件的自定义的地方。pytestconftest整个文档中分散的模块上有很多信息; 开始于conftest.py:本地按目录插件

同样,SO在conftest模块上也有一个很好的问题:在py.test中,conftest.py文件的用途是什么?

conftest solution

The least invasive solution is adding an empty file named conftest.py in the repo/ directory:

$ 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.

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).

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:

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

src layout

Although this approach can be used with the src layout (place conftest.py in the src dir):

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! 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.

Where to go from here

Of course, conftest modules are not just some files to help the source code discovery; it’s where all the project-specific enhancements of the pytest framework and the customization of your test suite happen. pytest has a lot of information on conftest modules scattered throughout their docs; start with conftest.py: local per-directory plugins

Also, SO has an excellent question on conftest modules: In py.test, what is the use of conftest.py files?


回答 3

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

I had the same problem. I fixed it by adding an empty __init__.py file to my tests directory.


回答 4

pytest使用以下模块作为模块运行: python -m pytest tests

Run pytest itself as a module with: python -m pytest tests


回答 5

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

PYTHONPATH=. py.test

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

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

You can run with PYTHONPATH in project root

PYTHONPATH=. py.test

Or use pip install as editable import

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

回答 6

我创建此文件是为了回答您的问题和我自己的困惑。希望对您有所帮助。注意py.test命令行和tox.ini中的PYTHONPATH。

https://github.com/jeffmacdonald/pytest_test

具体来说:您必须告诉py.test和tox在哪里可以找到要包含的模块。

使用py.test可以做到这一点:

PYTHONPATH=. py.test

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

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

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.

https://github.com/jeffmacdonald/pytest_test

Specifically: You have to tell py.test and tox where to find the modules you are including.

With py.test you can do this:

PYTHONPATH=. py.test

And with tox, add this to your tox.ini:

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

回答 7

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

当我添加时:

__init__.py

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

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

I had the same problem in Flask.

When I added:

__init__.py

to tests folder, problem disappeared :)

Probably application couldn’t recognize folder tests as module


回答 8

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

I fixed it by removing the top-level __init__.py in the parent folder of my sources.


回答 9

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

I started getting weird ConftestImportFailure: ImportError('No module named ... errors when I had accidentally added __init__.py file to my src directory (which was not supposed to be a Python package, just a container of all source).


回答 10

由于出现了一些更简单的事情(您甚至可以说微不足道),我遇到了此错误。我没有安装pytest模块。因此apt install python-pytest,为我修复了一个简单的问题。

“ pytest”将在setup.py中列为测试依赖项。确保同时安装测试要求。

I was getting this error due to something even simpler (you could even say trivial). I hadn’t installed the pytest module. So a simple apt install python-pytest fixed it for me.

‘pytest’ would have been listed in setup.py as a test dependency. Make sure you install the test requirements as well.


回答 11

我有一个类似的问题。pytest无法识别我在工作环境中安装的模块。

我也通过安装pytest到同一环境中来解决它。

I had a similar issue. pytest did not recognize a module installed in the environment I was working in.

I resolved it by also installing pytest into the same environment.


回答 12

对我来说,这个问题是tests.py由Django和tests目录生成的。删除tests.py解决了问题。

For me the problem was tests.py generated by Django along with tests directory. Removing tests.py solved the problem.


回答 13

我错误地使用了相对导入,因此出现了此错误。在OP示例中,test_app.py应该使用例如

from repo.app import *

但是,__ init__.py文件通常分散在文件结构中,除非文件和测试文件位于同一目录中,否则这将无法正常工作,并会产生类似ImportError的错误。

from app import *

这是我与一个项目有关的示例:

这是我的项目结构:

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

为了能够从test_activity_indicator.py访问activity_indicator.py,我需要:

  • 使用正确的相对导入启动test_activity_indicatory.py:
    from microbit.activity_indicator.activity_indicator import *
  • 在整个项目结构中放置__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 got this error as I used relative imports incorrectly. In the OP example, test_app.py should import functions using e.g.

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.

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:

  • start test_activity_indicatory.py with the correct relative import:
    from microbit.activity_indicator.activity_indicator import *
  • put __init__.py files throughout the project structure:
    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

回答 14

通常,由于无法导入模块而导致测试中断。经过研究,我发现系统在错误的位置查看文件,我们可以通过在其中复制包含模块的文件来轻松解决问题。与所述文件夹相同,以便正确导入。另一个解决方案建议是更改导入的声明,并向MutPy显示单元的正确路径。但是,由于多个单元可以具有此依赖性,这意味着我们还需要在其声明中提交更改,因此,我们宁愿将单元简单地移动到文件夹中。

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. 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.


回答 15

根据Dirk Avery在Medium上发表的一篇文章(并得到我的个人经验的支持),如果您在项目中使用虚拟环境,则无法在系统范围内安装pytest;您必须将其安装在虚拟环境中并使用该安装。

特别是,如果在两个地方都安装了该pytest命令,则仅运行该命令将不起作用,因为它将使用系统安装程序。正如其他答案所描述的,一个简单的解决方案是运行python -m pytest而不是pytest; 之所以有效,是因为它使用了环境版本的pytest。或者,您可以只卸载系统的pytest版本。重新激活虚拟环境后,该pytest命令应起作用。

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; 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. As the other answers have described, one simple solution is to run python -m pytest instead of pytest; this works because it uses the environment’s version of pytest. Alternatively, you can just uninstall the system’s version of pytest; after reactivating the virtual environment the pytest command should work.


回答 16

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

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

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

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

pip install -e .

-e标志告诉pip以可编辑或“开发”模式安装软件包。因此,下次运行pytest该程序时,它将在标准版本中找到您的应用程序PYTHONPATH

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.

You have to create a setup.py file in your project’s root directory with at least the following two lines:

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

where PACKAGENAME is your app’s name. Then you have to install it with pip:

pip install -e .

The -e flag tells pip to intall the package in editable or “develop” mode. So the next time you run pytest it should find your app in the standard PYTHONPATH.


回答 17

我的解决方案:

conftest.pytest包含以下内容的目录中创建文件:

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

这会将感兴趣的文件夹添加到python路径,而无需修改每个测试文件,设置env变量或弄乱绝对/相对路径。

My solution:

create the conftest.py file in the test directory containing:

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.