Jac*_*ang 8 python import pytest
我是 pytest 和 python 的新手。我的项目结构是:
projroot/
|-src/
|-a.py
|-test/
|-test_a.py
Run Code Online (Sandbox Code Playgroud)
而 test_a.py 是:
projroot/
|-src/
|-a.py
|-test/
|-test_a.py
Run Code Online (Sandbox Code Playgroud)
然后在pytest以下运行projroot:
projroot>pytest
Run Code Online (Sandbox Code Playgroud)
并且总是有错误信息:E ImportError: attempted relative import with no known parent package。Python 版本:Windows 10 x64 上的 3.8。我阅读了很多文章和博客以及官方建议,但仍然没有弄清楚。请帮帮我!
添加__init__.py到项目根目录实际上弄乱了我的 pytest 发现以及 pylint (导致Unable to import \'angles\' pylint(import-error))。我必须将其从项目根目录中删除,然后仅将其添加到我的测试文件夹中,这解决了我的 pytest 发现和 pylint 警告。
在项目根目录中__init__.py,我将拥有ModuleNotFoundError: No module named \'angles\'
下面是我的文件夹结构,其中 pytest discovery 和 pylint (没有警告)都可以工作:
\npowerfulpython\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 angles.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 tests\n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test_angles.py\nRun Code Online (Sandbox Code Playgroud)\n在 Angles.py 中,我Class Angle尝试使用from angles import Angleinside进行绝对导入test_angles.py。
在我发现问题是__init__.py在项目根目录中存在不必要的问题之前。我也尝试过
python.testing.cwd他们都没有工作。
\n在我删除__init__.py项目根目录之前,在测试 pytest 时,所做的python -m pytest工作是有效的,因为项目根目录会自动添加到 sys.path 之前,因此绝对导入可以从根目录正常工作,并且导入语句可以angles在根目录下找到。执行pytest(不使用 python -m)会失败,因为项目根目录未添加到 sys.path 之前。后者可以通过手动将根目录添加到$PYTHONPATH来临时解决。然而,这是一个不可持续的解决方案,因为我不想将我想要测试的每个新项目作为 PYTHONPATH 编辑添加到我的 ~/.zshrc 中。
我尝试过的另一个修复了这两个问题pytest并测试发现的方法是在代码中插入sys.path.insert(0,\'/Users/hanqi/Documents/Python/powerfulpython\') ,但这太丑陋了。我不想只是为了测试而向代码添加行,然后必须稍后删除它们。
在完成所有这些之后,我删除了__init__.py根目录,一切都很好。\n不需要上面列出的 3 项中的任何一项。
我经历过的许多解决方案都涉及查找测试文件夹,但这不是我的问题。我的测试在其文件夹中正确找到,只是正在from angles import Angle破坏导致测试发现失败。
__init__.py研究项目根目录如何破坏事物:
我打印了 sys.path 并用它实现,~/Documents/Python将其添加到 sys.path 的前面,如果没有它,~/Documents/Python/powerfulpython则将其添加到前面。后面的路径正是我的项目根目录。\n我猜这与https://docs.pytest.org/en/6.2.x/pythonpath.html( (默认))
有关。\n我希望看到内部导致被预先考虑和项目中的根本原因要预先考虑,但奇怪的是,当我把两者都留在里面时,我才看到后者 。--import-mode=prepend__init__.pytests~/Documents/Python/powerfulpython__init__.py~/Documents/Python__init__.py
我还尝试删除__init__.py内部tests(但让__init__.pyroot 保留),并查看~Documents/Python/powerfulpython/testssys.path 前面的内容。如果我在根目录和测试中都删除,也会在前面添加同一行__init__.py,不知道为什么。
编辑: \n上述行为在https://docs.pytest.org/en/6.2.x/pythonpath.html中进行了解释
\n然后它会向上搜索,直到找到最后一个仍包含__init__.py文件的文件夹,以便找到包根目录
在使用python -m pytest -s(-s 所以成功的测试运行不会吞掉我的print(sys.path)) 而不是仅仅重复我的上述实验之后pytest,我确认有 2 个参与者在 sys.path 前面。
python -m(它前面的内容取决于命令运行的目录)pytest(它前面的内容取决于__init__.py插入的位置(在上面链接的 pytest 文档中进行了解释)两者都具有编辑 sys.path 的效果,有助于避免导入失败
\n上面的 Jacques Yang 需要 2__init__.py将其 projroot 的包含文件夹放入 sys.path 中,因此在他的projroot.test值中显示为,并且该模块名称中的 2 个点 ( ) 允许两个点相对导入。他也可以使用绝对导入的.__package__test_a.py__name__projroot.test.test_a__name__from ..src import afrom projroot.src import a
如果他没有__init__.py在 projroot 中添加 ,则__package__将会变为 just ,test并且__name__将是test.test_a,这将只允许最多 1 步的向上相对步长。(这个步进概念也被 BrenBarn 在《相对导入》中第十亿次解释过)。
当存在但不存在__init__.py时,那就是,因为是并且是testprojrootValueError: attempted relative import beyond top-level package__package__test__name__test.test_a允许后退 1 步,但编码后退 2 步。\n标题中的问题出现在 甚至不存在 时__init__.py,test因此__package__完全空白,并且__name__只是test_a文件本身)
我在想为什么OP需要2__init__.py而我只需要 1,而 2 实际上损害了我的尝试。然后我意识到 OP 正在执行相对导入,而我正在使用 进行绝对导入from angles import Angle。如果我遵循OP的模式并进行相对导入from ..angles import Angle,那么我还需要添加__init__.pyunder powerfulpython,否则我会得到相同的错误。
那么为什么绝对导入会与 extra __init__.pyin发生冲突呢~/Documents/Python/powerfulpython?因为这__init__.py会导致 pytest 在层次结构中上升到更高的位置并前置~/Documents/Python到 sys.path,但我需要绝对导入~/Documents/Python/powerfulpython(这可以通过运行 using 来解决python -m pytest,如上面前置部分的 2 个角色中所述,但感觉有点不自然)简单地pytest)
我有一个关于导入概念的 30 分钟演示视频:https://towardsdatascience.com/taming-the-python-import-system-fbee2bf0a1e4,可以帮助人们理解__package__和__name__.
通过在根目录中包含 setup.py 文件并在每个对我有用的文件夹中包含 init.py ,并且要在任何文件中导入包,只需从父目录中给出该包位置
安装程序.py
from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())
Run Code Online (Sandbox Code Playgroud)
projroot/
|-__init__.py
|-setup.py
|-src/
|-a.py
|-__init__.py
|-test/
|-test_a.py
|-__init__.py
Run Code Online (Sandbox Code Playgroud)
from src import a
def test_a():
pass
Run Code Online (Sandbox Code Playgroud)
参考 https://docs.pytest.org/en/6.2.x/goodpractices.html
我发现我必须补充__init__.py的test和projroot。__init__.pyinsrc是没有必要的。并且pytest可以在 3 个文件夹中正确运行:
# parent folder of project root
C:\>pytest projroot
# project root
C:\>cd projroot
C:\projroot>pytest
# test folder
C:\projroot>cd test
C:\projroot\test>pytest
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2124 次 |
| 最近记录: |