首页 > 解决方案 > pytest 与 pip install 中断

问题描述

我正在一个名为testhttps://github.com/covid-projections/covid-data-model/tree/main/test)的目录中包含测试和一些测试帮助程序库的存储库中工作。神秘pip install dash地似乎打破了我们的测试。我在 debian 笔记本电脑上的 pyenv 中使用 python 3.7.9。我用一个非常简单的例子重现了这个问题:

激活一个新的 pyenv virtualenv 并使用pip install git+https://github.com/pytest-dev/pytest. 创建一个空./test/__init__.py的和以下两个文件:

$ cat ./test/real_test.py
from test import test_helpers

def test_one():
  assert "foobar" == test_helpers.SOME_CONSTANT
$ cat ./test/test_helpers.py
SOME_CONSTANT = "foo"

运行 test/real_test.py 会按预期进行,但未通过测试。现在pip install dash==1.19.0,测试无法运行

_____________________________________________________________________________ ERROR collecting test/real_test.py _____________________________________________________________________________
ImportError while importing test module '/home/thecap/tmp/nomodule/test/real_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
../../.pyenv/versions/3.7.9/lib/python3.7/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
E   ModuleNotFoundError: No module named 'test.real_test'

运行pytest --import-mode=importlib test/real_test.py(在https://github.com/pytest-dev/pytest/issues/7408的评论中找到)给了我一点提示,它不包括用于搜索库的路径中的 cwd,因为它正在寻找在testpyenv 中,而不是在 cwd 中。

ImportError while importing test module '/home/thecap/tmp/nomodule/test/real_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test/real_test.py:1: in <module>
    from test import test_helpers
E   ImportError: cannot import name 'test_helpers' from 'test' (/home/thecap/.pyenv/versions/3.7.9/lib/python3.7/test/__init__.py)

pip uninstall dash在按预期运行测试后对我来说神秘的是,pytest test/real_test.py但仍然被pytest --import-mode=importlib test/real_test.py.

我怀疑将我们的测试从 移动test/tests/将解决这个问题,但我想了解为什么安装破折号会破坏事情,如果我们当前的设置有问题,请帮助其他人避免它。

(我也在https://github.com/pytest-dev/pytest/discussions/8270上发布了这个,希望对堆栈溢出有更多的响应。)

标签: pythonpippytest

解决方案


这里的问题是您的本地test包隐藏test了标准库中的模块。一般来说,对任何 stdlib 模块进行命名是一种不好的做法,应该避免;然而,由于

test包仅供 Python 内部使用。它的文档是为了 Python 的核心开发人员的利益。不鼓励在 Python 标准库之外使用此包,因为此处提到的代码可能会在 Python 版本之间更改或删除,恕不另行通知。

test包包含 Python 的所有回归测试以及模块test.supporttest.regrtest. test.support用于在test.regrtest驱动测试套件时增强您的测试。

一种暗示test不会在回归测试运行之外使用。但是,这不是真的future-它在安装 aliases 时导入test.support,导致 stdlib在开始测试收集之前test出现。您与 一起安装,因为它是直接依赖项。现在,当您开始运行时,它会加载导入的插件,然后在尝试收集本地包时,导入失败,因为已经导入了另一个包!sys.modulespytestfuturesdashpytestdashfuturetesttestpytesttest

解决方案

我建议将本地test包重命名为 eg tests。这将停止 stdlib 模块的名称隐藏。

如果您无法重命名测试包,可以想象几种解决方法来规避 stdlib 的导入test

清理导入

conftest.py在您的项目根目录(不在test目录中,否则它将不起作用)中创建一个文件,其中包含以下内容:

import sys

sys.modules.pop("test", None)

这将“取消导入”标准库test,使您的本地test包可在测试集合中导入。

改变sys.path以使本地test包在 stdlib 之前可选择

只需运行python -m pytest ...PYTHONPATH=. pytest ...确保在站点之前插入项目的根目录sys.path,因此import test将始终以导入本地包结束。


推荐阅读