我正在使用 Python 开发一个包。我使用虚拟环境。我在 virtualenv 中的 .pth 路径中将路径设置为模块的根目录,这样我就可以在开发代码并进行测试时导入包的模块(问题 1:这是一个好方法吗?)。这很好用(这是一个例子,这是我想要的行为):
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ python
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from rc import ns
>>> exit()
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ python tests/test_ns.py
issued command: echo hello
command output: hello
但是,如果我尝试使用 PyTest,我会收到一些导入错误消息:
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ pytest
=========================================== test session starts ============================================
platform linux2 -- Python 2.7.12, pytest-3.0.5, py-1.4.31, pluggy-0.4.0
rootdir: /home/zz/Desktop/GitFolders/rc, inifile:
collected 0 items / 1 errors
================================================== ERRORS ==================================================
________________________________ ERROR collecting tests/test_ns.py ________________________________
ImportError while importing test module '/home/zz/Desktop/GitFolders/rc/tests/test_ns.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_ns.py:2: in <module>
from rc import ns
E ImportError: cannot import name ns
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================= 1 error in 0.09 seconds ==========================================
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ which pytest
/home/zz/Desktop/VirtualEnvs/VEnvTestRc/bin/pytest
我有点疑惑,看起来这表示导入错误,但 Python 做得很好,为什么 PyTest 会出现问题?对原因/补救措施有什么建议(问题 2)?我用谷歌搜索并堆栈溢出 PyTest 的“ImportError:无法导入”错误,但我得到的命中与缺少 python 路径和对此的补救措施有关,这似乎不是这里的问题。有什么建议么?
找到了答案:
如果您打算使用 pytest,请勿将 __init__.py
文件放在包含 TESTS 的文件夹中。我有一个这样的文件,删除它解决了这个问题。
这实际上隐藏在 PATH issue with pytest 'ImportError: No module named YadaYadaYada' 的第二个答案的评论中,所以我没有看到它,希望它在这里得到更多的可见性。
我不能说我理解为什么会这样,但我遇到了同样的问题,如果我运行 python -m pytest
,测试工作正常。
我在一个 virtualenv 中,pytest 也可以在全球范围内使用:
(proj)tom@neon ~/dev/proj$ type -a python
python is /home/tom/.virtualenvs/proj/bin/python
python is /usr/bin/python
(proj)tom@neon ~/dev/proj$ python -V
Python 3.5.2
(proj)tom@neon ~/dev/proj$ type -a pytest
pytest is /home/tom/.virtualenvs/proj/bin/pytest
pytest is /usr/bin/pytest
(proj)tom@neon ~/dev/proj$ pytest --version
This is pytest version 3.5.0, imported from /home/tom/.virtualenvs/proj/lib/python3.5/site-packages/pytest.py
python -m pytest [...]
“也会将当前目录添加到 sys.path
。”
python3 -m pytest
的虚拟环境中也适用
PYTHONPATH=.:./src pytest
作为制作目标。
我刚刚通过删除项目根目录中的 __init__.py
解决了这个问题:
.
├── __init__.py <--- removed
├── models
│ ├── __init__.py
│ ├── address.py
│ ├── appointment.py
│ └── client.py
├── requirements.txt
├── setup.cfg
├── tests
│ ├── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── appointment_test.py
│ │ └── client_test.py
│ └── other_test.py
└── script.py
__init__.py file in a folder containing TESTS
没有解决我的问题。这个有效。我想这是因为文件层次结构。
__init__.py
文件。我仍然面临问题。将 conftest.py 文件添加到根目录对我有用。
我有同样的问题,但除了提到的原因之外还有另一个原因:
我全局安装了 py.test,而软件包安装在虚拟环境中。
解决方案是在虚拟环境中安装 pytest
。 (如果您的 shell 像 Bash 那样对可执行文件进行哈希处理,请使用 hash -r
,或使用 py.test
的完整路径)
conda
创建的 virtualenv 中添加 pytest
,但 pytest
它在 anaconda 的根环境中可用。因此 pytest 可以被找到,但没有安装在环境中的任何包。
pip3 install pytest
解决了这个问题。
which pytest
显示了错误的版本)停用并重新激活 venv 修复了所有问题。
有一个类似的问题,当我在测试目录下添加 __init__.py
文件时它起作用了。
conftest.py
也是如此。
只需在项目根目录中放置一个空的 conftest.py
文件,因为当 pytest
发现 conftest.py
时,它会修改 sys.path
以便它可以从 conftest
模块导入内容。一般的目录结构可以是:
Root
├── conftest.py
├── module1
│ ├── __init__.py
│ └── sample.py
└── tests
└── test_sample.py
__init__.py
的疯狂。
python -m pytest
但又不想每次都添加额外措辞的人来说,这是一个长期的解决方案
在我的情况下,我在一个容器中工作,不幸的是 pytest 倾向于使用 python2.7 而不是我选择的 python3 解释器。
就我而言,这有效:
python3 -m pytest
我的文件夹结构
/
app/
-module1.py
-module2.py
-tests/
--test_module1.py
--test_module2.py
requirements.txt
README.md
如果您有一个 tests.py
文件和一个带有 tests/__init__.py
的测试文件夹,则会发生此问题。
在收集过程中 pytest 找到了该文件夹,但是当它尝试从该文件夹中导入测试文件时,tests.py
文件将导致导入问题。
要解决此问题,只需删除 tests.py
文件并将所有测试放在 tests/
文件夹中。
对于您的具体情况,修复将是准确的:
删除文件 /home/zz/Desktop/GitFolders/rc/tests.py
确保 /home/zz/Desktop/GitFolders/rc/tests/__init__.py 存在
另一个建议
我在 SO 和其他地方探索了这个问题和其他各种问题......关于在项目目录结构的各个部分中和/或 conftest.py 中添加(或删除)一个空 __init__.py
的所有内容,关于 PYTHONPATH 的所有内容,等等,等等:这些解决方案都不适合我,实际上是一个非常简单的情况,不应该引起任何悲伤。
我认为这是 pytest 当前设置中的一个缺陷。事实上,我最近从 SO 上的某个人那里收到了一条消息,他清楚地知道他的东西。他说 pytest 不是为(根据 Java/Groovy/Gradle )单独的“src”和“test”目录结构而设计的,并且测试文件应该混合在应用程序目录和文件中。这可能在某种程度上提供了解释......但是,测试,特别是集成/功能测试,并不总是必须整齐地对应于特定的目录,我认为 pytest 应该在这方面给用户更多的选择。
我的项目结构:
project_root
src
core
__init__.py
__main__.py
my_other_file.py
tests
basic_tests
test_first_tests.py
提出的导入问题:很简单,__main__.py
有一行 import my_other_file
。当我刚刚运行应用程序时,这(毫不奇怪)工作正常,即从根目录运行 python src/core
。
但是,当我使用导入 __main__.py
的测试运行 pytest
时,我得到
ModuleNotFoundError: No module named 'my_other_file'
在 __main__.py
中尝试导入“my_other_file”的行上。请注意,就我而言,这里的问题是,在 pytest 测试过程中,一个应用程序文件无法在同一个包中找到另一个应用程序文件。
使用 PYTHONPATH
经过大量实验,在我能找到的几乎每个目录中都放置了一个 __init__.py
文件和一个 confest.py 文件(我认为关键文件被 __init__.py
添加到“tests”和“basic_tests”,参见上面的目录结构),然后将 PYTHONPATH 设置为如下
PYTHONPATH=D:\My Documents\software projects\EclipseWorkspace\my_project\src\core
...我发现它有效。测试文件中的导入必须稍作调整,一般模式是 from core import app, project
,但测试文件能够“看到”core
,关键是没有必要乱用 import
命令应用程序文件。
但是...由于某种原因,现在使用这种方法运行测试慢得多!与我下面的解决方案相比,可以看到 core
包只加载一次,我怀疑 PYTHONPATH 解决方案可能会导致大量代码一次又一次地重新加载。我还不能证实这一点,但我看不到任何其他解释。
替代方案我的替代相当简单的解决方案是:
1 - 在该应用程序包(即目录“core”)的 __init__.py
中,放入以下两行:
import pathlib, sys
sys.path.append(str(pathlib.Path(__file__).parent))
请注意,通常 __init__.py
中当然没有任何内容。事实证明,正如我通过实验所证实的那样,pytest 通常(请参阅下面的更新)在这种情况下执行 __init__.py
,在pytest 完成了它所做的任何事情之后增加 sys.path
个条目。
2 - 更新 2022-01:我发现的原始解决方案涉及将 conftest.py 文件放在应用程序目录中 - 没有它,事情就不起作用。这显然是不可取的。我发现另一种解决方案是将此代码放在根目录下的 conftest.py 文件中:
def pytest_configure(config):
import src.core # NB this causes `src/core/__init__.py` to run
# set up any "aliases" (optional...)
import sys
sys.modules['core'] = sys.modules['src.core']
...确实,从我的实验来看,将 conftest.py 放在应用程序目录中的效果似乎是 pytest 然后在该目录中运行 __init__.py
。这似乎意味着正在导入模块...
(之前的建议:)
是的,您还 HAVE 在目录“core”中包含一个空的 "conftest.py" 文件.希望这应该是您需要的唯一 conftest.py:我对所有这些进行了试验,没有必要将其放入根目录(如果没有 __init__.py
中的建议代码,它也不能解决问题)。
3 - 最后,在我的测试函数中,在我的示例中调用 core.__main__
之前,我必须导入我知道即将导入的文件:
import core.my_other_file
import core.__main__
如果您在文件的第一个测试中执行此操作,您会发现 sys.modules 已为该文件中的所有其他测试设置。更好的是,将 import core.my_other_file
放在文件的最开头,在第一次测试之前。不幸的是,from core import *
似乎不起作用。
稍后:这种方法有一些特殊性和局限性。例如,虽然 -k
开关可以正常过滤输入/输出测试或整个文件,但如果您执行 pytest tests/tests_concerning_module_x
之类的操作,core.__init__.py
似乎不会运行......所以核心模块中的文件在测试期间再次相互不重要。其他限制可能会暴露出来......
正如我所说,我认为这是 pytest 设置中的一个缺陷。我完全不知道 pytest 为 sys.path
建立常识设置做了什么,但它显然弄错了。不需要依赖 PYTHONPATH 或其他任何东西,如果这确实是“官方”解决方案,那么关于这个主题的文档非常缺乏。
注意我的这个建议有一个问题:每次 pytest 在模块中运行 __init__.py
时都添加到 sys.path
,这意味着此后这条新路径在 sys.path
中变为 permanent,无论是在测试期间而且,更令人担忧的是,在应用程序本身运行期间,是否有任何实际调用 __init__.py
的东西。 (顺便说一句,仅执行 python src/core
(如我的示例)不会导致这种情况发生。但其他事情可能会发生。)
为了解决这个问题,我有一个笨重但有效的解决方案:
import pathlib, sys, traceback
frame_list = traceback.extract_stack()
if len(frame_list) > 2:
path_parts = pathlib.Path(frame_list[2].filename).parts
sys_platform = sys.platform
if sys_platform.startswith('win'):
if len(path_parts) > 2 and path_parts[-3:-1] == ('Scripts', 'pytest.exe'):
sys.testing_context = True
sys.path.append(str(pathlib.Path(__file__).parent))
elif sys_platform.startswith('lin'):
if len(path_parts) > 2 and path_parts[-3:-1] == ('_pytest', 'config'):
sys.testing_context = True
sys.path.append(str(pathlib.Path(__file__).parent))
这是基于我在 pytest 在 W10 上下文和 Linux Mint 20 上下文中运行某些东西时对堆栈跟踪的检查。这意味着在应用程序运行中不会出现 sys.path
的混乱。
当然,这可能会与 pytest 的未来版本中断。我的版本是 6.2.5。
我通过在环境变量中为我运行测试的特定配置设置 PYTHONPATH
解决了我的问题。
在 PyCharm 上查看测试文件时:
Ctrl + Shift + A 类型 Edit Configurations 在 Environment > Environment variables 下设置您的 PYTHONPATH。
更新
移动到项目的根目录 创建虚拟环境 激活新创建的虚拟环境 将变量 $PYTHONPATH 设置为项目的根目录并将其导出:
export PYTHONPATH=$(pwd)
不要从 tests/ 目录或 src/ 目录中删除 __init__.py。
另请注意:
您的目录的根不是 python 模块,所以不要添加 __init__.py
conftest.py 在项目的根目录中不是必需的。
$PYTHONPATH 变量仅在当前终端/控制台会话期间可用;所以你每次都需要设置这个。 (如果您在 pycharm 中工作,您可以按照本次更新之前的步骤进行操作)。
Environment variables:
字段设置为 PYTHONPATH=/my_projects_root_dir:$PYTHONPATH
。
pythonpath
配置选项不起作用[1]。另外,就我而言,我的测试文件夹中没有 init.py 。 [1]:docs.pytest.org/en/7.1.x/reference/…
我有一个类似的问题,完全相同的错误,但不同的原因。我运行测试代码很好,但是针对的是旧版本的模块。在我的代码的先前版本中,存在一个类,而另一个则不存在。更新我的代码后,我应该运行以下命令来安装它。
sudo pip install ./ --upgrade
安装更新的模块后,运行 pytest 产生了正确的结果(因为我使用了正确的代码库)。
pip install ./ --upgrade
使用最新代码更新了已安装的 lib 版本,并使 pytest 也能找到这个最新版本。
conda update --all
解决了问题
请在此处查看:https://docs.pytest.org/en/documentation-restructure/background/pythonpath.html
我对 pytest 有疑问(已使用 python -m pytest
解决);错误是
FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/lib/python3.9/site-packages/...
我发现问题在 tests/
和 tests/subfolders
中缺少 __init__.py
。
在我的情况下,发生导入错误是因为包指向另一个同名的包/目录,并且它的路径比我实际想要的文件夹高一级。我认为这也解释了为什么有些人需要删除 _init _.py 而其他人需要添加回来。
我只是将 print(the_root_package.__path__)
(在 import the_root_package
之后)放在 python
控制台和 pytest
脚本中以比较 差异
底线:当您执行 python
时,您导入的包可能与您运行 pytest
时的包不同。
将软件包安装到您的虚拟环境中。然后启动一个新的 shell 并再次获取您的虚拟环境。
我将所有测试都放在了测试文件夹中,并且遇到了同样的错误。我通过在该文件夹中添加 __init__.py
解决了这个问题,如下所示:
.
|-- Pipfile
|-- Pipfile.lock
|-- README.md
|-- api
|-- app.py
|-- config.py
|-- migrations
|-- pull_request_template.md
|-- settings.py
`-- tests
|-- __init__.py <------
|-- conftest.py
`-- test_sample.py
这是a medium article!描述问题!
问题是您使用的是哪个 pytest 以及您对虚拟环境的使用。如果你已经在系统范围内安装了 pytest,换句话说,在虚拟环境之外,pytest 有一个讨厌的习惯,就是只在你的虚拟环境之外寻找模块!如果您的项目使用的模块仅安装在您的虚拟环境中,并且您使用的是系统范围的 pytest,那么即使您已激活虚拟环境,它也不会找到该模块。1
以下是分步说明:1
退出任何虚拟环境 使用 Pip 卸载 pytest 激活项目的虚拟环境 在虚拟环境中安装 pytest pytest 现在将找到您的仅虚拟环境包!
我正在使用 VSCode 得到这个。我有一个 conda 环境。我不认为 VScode python 扩展可以看到我所做的更新。
python c:\Users\brig\.vscode\extensions\ms-python.python-2019.9.34911\pythonFiles\testing_tools\run_adapter.py discover pytest -- -s --cache-clear test
Test Discovery failed:
我必须运行 pip install ./ --upgrade
Directory './' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.
我今天遇到了这个问题,并通过从我的项目目录的根目录调用 python -m pytest
解决了它。
从同一位置调用 pytest
仍然会导致问题。
我的项目目录组织为:
api/
- server/
- tests/
- test_routes.py
- routes/
- routes.py
- app.py
模块 routes
在我的 test_routes.py
中导入为:from server.routes.routes import Routes
希望有帮助!
我不同意您必须删除任何 __init__.py
文件的帖子。相反,您必须做的是更改 sys.path
。
运行正常运行代码时打印 sys.path
的实验。然后在通过 pytest 运行代码时打印 sys.path
。我想您会发现这两条路径之间存在差异,因此 pytest 会中断。
要解决此问题,请在第二个实验的第 0 个索引处插入第一个实验的路径。
让 '/usr/exampleUser/Documents/foo'
成为实验 1 的 print(sys.path)
的第一个元素。
以下是应该解决您的问题的代码:
import sys sys.path[0] = '/usr/exampleUser/Documents/foo'
将其放在文件顶部,在实际导入语句之前。
资料来源:我自己正在处理这个问题,上面的过程解决了它。
另一个特殊情况:
我在使用 tox 时遇到了问题。所以我的程序运行良好,但通过 tox 的单元测试一直在抱怨。安装包(程序所需)后,您需要在 tox.ini 中额外指定单元测试中使用的包
[testenv]
deps =
package1
package2
...
上面的答案对我不起作用。我只是通过将未找到的模块的绝对路径附加到 test_xxx.py
(您的测试模块)顶部的 sys.path
来解决它,例如:
import sys
sys.path.append('path')
test_main.py
的顶部,而是将它放在我的测试目录的 conftest.py
中,并且它起作用了。感谢您提供程序化解决方案,而不是文件垃圾。
如果它与最初在 python 2.7 中开发并现在迁移到 python 3.x 中的 python 代码有关,那么问题可能与导入问题有关。
例如,当从文件中导入对象时:base
位于同一目录中,这将在 python 2.x 中工作:
from base import MyClass
在 python 3.x 中,您应该替换为 base
完整路径,否则 .base
不这样做会导致上述问题。所以试试:
from .base import MyClass
Python 的导入系统又一次取得了巨大的胜利。我认为没有达成共识的原因是什么工作可能取决于你的环境和你在它之上使用的工具。
我在 VS Code 中使用它,在 conda 环境 Python 3.8 中的 Windows 下的测试资源管理器中使用它。
我必须工作的设置是:
mypkg/
__init__.py
app.py
view.py
tests/
test_app.py
test_view.py
在此设置下,智能感知有效,测试发现也有效。
请注意,我最初按照推荐的 here 尝试了以下操作。
src/
mypkg/
__init__.py
app.py
view.py
tests/
test_app.py
test_view.py
我无法从 VS Code 中得到它,因为 src
文件夹只是让导入系统大吃一惊。我可以想象有一种方法可以让它从命令行工作。作为一个相对较新的 Python 编程转换者,它让我有一种使用 COM 工作的怀旧感觉,但乐趣略逊一筹。
更新 PYTHONPATH 直到 src 文件夹
export PYTHONPATH=/tmp/pycharm_project_968/src
对于尝试了所有方法但仍然出错的人,我有一个解决方法。
在安装 pytest 的文件夹中,转到 pytest-env 文件夹。
打开 pyvenv.cfg 文件。
在文件中将 include-system-site-packages 从 false 更改为 true。
home = /usr/bin
include-system-site-packages = true
version = 3.6.6
希望它有效。不要忘记投票。
我的 2 美分:如果您不使用虚拟环境,pytest 会偶然失败。有时它会起作用,有时不会。
因此,解决方案是:
使用 pip uninstall 删除 pytest
创建你的venv
激活你的venv
pip 以可编辑模式安装您的项目路径,因此 pytest 会将其视为模块(否则,pytest 不会找到您的内部导入)。您将需要一个 setup.py 文件
安装你的包,包括 pytest
最后,运行你的测试
使用 Windows PowerShell 的代码:
pip uninstall pytest
python.exe -m venv my_env
.\my_env\Scripts\activate
(my_env) pip install -e .
(my_env) pip install pytest pytest-html pandas numpy
然后终于
(my_env) pytest --html="my_testing_report.html"
setup.py 的示例,用于 pip install -e:
import setuptools
setuptools.setup(
name='my_package',
version='devel',
author='erickfis',
author_email='erickfis@gmail.com',
description='My package',
long_description='My gooood package',
packages=setuptools.find_packages(),
classifiers=[
'Programming Language :: Python :: 3',
'Operating System :: OS Independent',
],
include_package_data=True
)
如果您从终端运行 Pytest:
使用 --import-mode=append
命令行标志运行 pytest。
官方文档中的参数说明:https://docs.pytest.org/en/stable/pythonpath.html
UPD:之前我还写了如果您使用 PyCharm 时如何做同样的事情,但是社区不喜欢扩展答案,所以我删除了可能对遇到类似问题的人有帮助的其他信息。
就我而言,问题在于文件名和类名完全相同:分别为 FrameAnalyzer.py
和 FrameAnalyzer
。将文件名更改为 frame_analyzer.py
后,一切正常。
保持一切不变,只是在根文件夹中添加了一个空白测试文件..解决了
这是调查结果,这个问题确实困扰了我一段时间。我的文件夹结构是
mathapp/
- server.py
- configuration.py
- __init__.py
- static/
- home.html
tests/
- functional
- test_errors.py
- unit
- test_add.py
pytest 会抱怨 ModuleNotFoundError
并给出提示:
确保您的测试模块/包具有有效的 Python 名称。
我在 mathsapp 和 tests 目录中引入了一个模拟测试文件。该文件不包含任何内容。现在 pytest 没有抱怨。
没有文件的结果
$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 1 item / 1 error
=================================== ERRORS ====================================
_______________ ERROR collecting tests/functional/test_func.py ________________
ImportError while importing test module 'C:\mainak\workspace\0github\python-rest-app-cont\tests\functional\test_func.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests\functional\test_func.py:4: in <module>
from mathapp.service import sum
E ModuleNotFoundError: No module named 'mathapp'
=========================== short test summary info ===========================
ERROR tests/functional/test_func.py
!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
============================== 1 error in 0.24s ===============================
文件结果
$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 2 items
tests\functional\test_func.py . [ 50%]
tests\unit\test_unit.py . [100%]
============================== 2 passed in 0.11s ==============================
不定期副业成功案例分享
project_root/tests/
中,源代码位于project_root/myapp/
中,我在project_root/tests/__init__.py
中放置了一个 init 文件,以便能够在project_root/tests/test_foo.py
中导入帮助程序模块project_root/tests/helper.py
。在project_root/
中,我可以使用python -m pytest -vv tests/
运行测试。