Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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 
like image 245
rgargente Avatar asked Feb 16 '16 11:02

rgargente


People also ask

Why is it called monkey patching?

The term monkey patch seems to have come from an earlier term, guerrilla patch, which referred to changing code sneakily – and possibly incompatibly with other such patches – at runtime. The word guerrilla, nearly homophonous with gorilla, became monkey, possibly to make the patch sound less intimidating.

What is monkey patching and is it ever a good idea?

Monkey patching is good for testing or mocking out behavior. They can be localized in factory/class decorators/metaclasses where they create a patched new class/object from another object to help with "cross-cutting concerns" in between ALL methods like logging/memoization/caching/database/persistance/unit conversion.

What is monkey patching in Python and is it ever a good idea?

In Python, the term monkey patch refers to dynamic (or run-time) modifications of a class or module. In Python, we can actually change the behavior of code at run-time. We use above module (monk) in below code and change behavior of func() at run-time by assigning different value.


2 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().

like image 66
Michele d'Amico Avatar answered Dec 28 '22 04:12

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) 
like image 36
rgargente Avatar answered Dec 28 '22 04:12

rgargente