名称空间被覆盖的模块中的Monkeypatch函数

时间:2018-09-19 20:12:17

标签: python mocking pytest biopython monkeypatching

我正在尝试在我使用的外部模块中对函数进行monkeypatch,但是monkeypatch似乎无法访问该函数,因为模块的名称空间在导入时会被覆盖。

具体来说,我在代码中使用了Bio.PDB.PDBList.PDBList对象(biopython模块),并且试图在Bio.PDB.PDBList中修补_urlretrieve,以防止拨打互联网和而是从本地目录获取文件,而不必模拟PDBList的实例方法,这将需要更多工作。但是当我尝试天真时:

m.setattr("Bio.PDB.PDBList._urlretrieve", mock_retrieve)

pytest抱怨:

AttributeError: 'type' object at Bio.PDB.PDBList has no attribute '_urlretrieve'

进一步检查Bio.PDB时,我发现模块名称空间.PDBList似乎被类.PDBList.PDBList覆盖:

# Download from the PDB
from .PDBList import PDBList

所以这可以解释为什么pytest将Bio.PDB.PDBList视为没有属性type的{​​{1}}对象。我的问题是,有没有办法让Monkeypatch修补此“隐藏”功能?


_urlretrieve类用法的具体示例:

PDBList

1 个答案:

答案 0 :(得分:2)

您是对的-由于PDBList类与模块Bio.PDB.PDBList的名称相同,因此在import Bio.PDB.PDBList之后,您将无法通过其名称访问该模块(影子问题)。但是,您仍然可以从已加载的模块缓存中获取导入的模块对象,然后进行以下操作的猴子补丁:

import sys
from unittest.mock import Mock
import Bio.PDB.PDBList

def test_spam(monkeypatch):
    assert isinstance(Bio.PDB.PDBList, type)
    with monkeypatch.context() as m:
        m.setattr(sys.modules['Bio.PDB.PDBList'], '_urlretrieve', Mock())
        ...