I am trying to monkeypatch a function in an external module I use, but monkeypatch can't seem to access the function because the namespace of the module gets overwritten on import.
Concretely, I use a Bio.PDB.PDBList.PDBList
object (biopython
module) in my code, and I am trying to patch _urlretrieve
in Bio.PDB.PDBList
to prevent calls to the internet and instead get files from a local directory, without having to mock the instance methods of PDBList
which would be substantially more work. But when I try the naïve:
m.setattr("Bio.PDB.PDBList._urlretrieve", mock_retrieve)
pytest complains:
AttributeError: 'type' object at Bio.PDB.PDBList has no attribute '_urlretrieve'
On further inspection of Bio.PDB
, I can see that the module namespace .PDBList
seems to be overwritten by the class .PDBList.PDBList
:
# Download from the PDB
from .PDBList import PDBList
So that would explain why pytest sees Bio.PDB.PDBList
as a type
object with no attribute _urlretrieve
. My question is, is there any way to get monkeypatch to patch this 'hidden' function?
Concrete example of usage of PDBList
class:
from Bio.PDB.PDBList import PDBList
_pdblist = PDBList()
downloaded_file = _pdblist.retrieve_pdb_file('2O8B', pdir='./temp', file_format='pdb')
You are right - since the PDBList
class has the same name as the module Bio.PDB.PDBList
, after import Bio.PDB.PDBList
you won't be able to access the module by its name (shadowing problem). However, you can still grab the imported module object from the loaded modules cache and monkeypatch that:
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())
...