EmpireJones
EmpireJones

Reputation: 3086

py.test's monkeypatch.setattr(...) not working in some cases

In conftest (in an autouse fixture):

monkeypatch.setattr('collector.util.download_data', lambda url:"Winning" )

In collector/util.py:

def download_data(url):
    assert False

In the_caller.py:

from collector.util import download_data
def some_function():
    download_data("blah")

When I call some_function(), I get the assert. However, if I change the_caller.py to:

import collector
def some_function():
    collector.util.download_data("blah")

then I get "Winning".

Why is this behaving differently, and how can I make the monkeypatch work for both scenarios?

Upvotes: 15

Views: 11448

Answers (1)

EmpireJones
EmpireJones

Reputation: 3086

In general, it seems that the issue relates to how imports work in python. I'm not sure that there is a good solution.

The best work-around that I have found so far is the following:

monkeypatch.setattr('collector.util.download_data.__code__', replacement_function.__code__)

This works with both import types. One limitation is that this doesn't work with closures.


This functionality can be added to the framework via:

from _pytest.monkeypatch import monkeypatch

monkeypatch.setcode = lambda self, func_str, replacement_func: \
    monkeypatch.setattr(self, func_str + ".__code__", replacement_func.__code__)

Reference: https://mail.python.org/pipermail/pytest-dev/2013-October/002386.html

Upvotes: 17

Related Questions