Why python's monkeypatch doesn't work when importing a class instead of a module?

Question:

I was having issues while using the code of the accepted answer here.

The code works depending on how I do the import of datetime. Why is that? Is it possible to mock it so it works both ways?

I am using Python 3.4. The following code illustrates the problem:

import pytest
from datetime import datetime

mockdate = datetime(2000, 1, 1, 0, 0, 0)

@pytest.fixture(autouse=True)
def patch_datetime_now(monkeypatch):
    class mydatetime:
        @classmethod
        def now(cls):
            return mockdate

    monkeypatch.setattr('datetime.datetime', mydatetime)

def test_doesnt_work():
    assert datetime.now() == mockdate

def test_works():
    import datetime
    assert datetime.datetime.now() == mockdate
Asked By: rgargente

||

Answers:

Even if you aren’t using mock framework you should take a look to where to patch chapter. By writing

from datetime import datetime

You are creating a new reference to datetime.datetime in your test module and call it datetime. That is the reference that you use in test_doesnt_work() test.

By writing

monkeypatch.setattr('datetime.datetime', mydatetime)

You are patching datetime‘s absolute reference in datetime module: the one used in test_works().

Answered By: Michele d'Amico

@Michele d’Amico’s answer explains why it doesn’t work. This is how to make it work if you want to use “from datetime import datetime” instead of just “import datetime”

monkeypatch.setattr(__name__ + '.datetime', mydatetime)
Answered By: rgargente