如果我的库中有一个...
Time elapsed: 00:01:02 secs
...
Time elapsed: 22:10:53 secs
...
附加项(例如contrib
),我希望用户必须安装该附加项才能访问CLI API,但是我在安装过程中安装了contrib extra我在CI中的测试如何在测试过程中使用pytest
's MonkeyPatch
删除依赖项以确保检测正确?
例如,如果requests
附加项将另外安装contrib
,那么我希望用户必须这样做
requests
然后可以在命令行中使用看起来像这样的CLI API
$ python -m pip install mylib[contrib]
其中$ mylib contrib myfunction
使用myfunction
依赖项
requests
我如何在# mylib/src/mylib/cli/contrib.py
import click
try:
import requests
except ModuleNotFoundError:
pass # should probably warn though, but this is just an example
# ...
@click.group(name="contrib")
def cli():
"""
Contrib experimental operations.
"""
@cli.command()
@click.argument("example", default="-")
def myfunction(example):
requests.get(example)
# ...
测试中模拟或猴子跳出 out requests
,以便确保用户可以与{{1 }},如果他们这样做
pytest
?在阅读了pytest标签上的其他一些问题之后,我仍然认为我不知道该怎么做,所以我在这里问。
答案 0 :(得分:0)
我最终所做的工作奏效了,并且我确认是一种合理的方法thanks to Anthony Sottile,是通过将其设置为{{来嘲笑额外的依赖项(这里requests
)不存在。 1}},然后重新加载需要使用None
的模块。
我测试是否存在实际的抱怨,即不存在使用sys.modules
来导入requests
的问题。
这是我目前正在使用的测试(名称更改为与上述问题中的玩具示例问题相匹配)
requests
我应该注意到,{hoefling}实际上是在@Abhyudai's answer to "Test for import of optional dependencies in init.py with pytest: Python 3.5 /3.6 differs in behaviour"中提倡的(上面我已经解决了这个问题,但是在我发表之前就发布了)。
如果人们有兴趣在实际的图书馆中看到这些,请参见c.f.以下两个PR:
注意: 安东尼·索提(Anthony Sottile)警告过
caplog
可能有点麻烦-我会小心一点(具有对旧模块的旧引用的内容将继续存在,有时会引入单例的新副本(doubleton或Tripletons?)) -我已将许多测试污染问题归结为import mylib import sys import logging import pytest from unittest import mock from importlib import reload from importlib import import_module # ... def test_missing_contrib_extra(caplog): with mock.patch.dict(sys.modules): sys.modules["requests"] = None if "mylib.contrib.utils" in sys.modules: reload(sys.modules["mylib.contrib.utils"]) else: import_module("mylib.cli") with caplog.at_level(logging.ERROR): # The 2nd and 3rd lines check for an error message that mylib throws for line in [ "import of requests halted; None in sys.modules", "Installation of the contrib extra is required to use mylib.contrib.utils.download", "Please install with: python -m pip install mylib[contrib]", ]: assert line in caplog.text caplog.clear()
因此,如果我采用更安全的替代方法,我将修改此答案。