[英]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 中添加当前目录。
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
, so将app
和lib
模块都添加到sys.path
,所以
import app
import lib
will both work.两者都可以。
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 pytest
如Apteryx的答案中所建议的那样是一个很好的解决方案!)。
The project directory afterwards:之后的项目目录:
repo
├── conftest.py
├── app.py
├── settings.py
├── models.py
└── tests
└── test_app.py
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
模块以收集自定义钩子和固定装置,为了从中导入自定义对象, pytest
将conftest.py
的父目录添加到sys.path
(在本例中为repo
目录) .
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
目录。
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 plugins从conftest.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 个选择:
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 + '/../')
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,我需要:
from microbit.activity_indicator.activity_indicator import *
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.