pythonpython-modulemonkeypatching

Python: monkey patch a function used by classes in the same module


I want to modify a function (not a method) in a module, such that the classes within the same module that use that function behave differently.

For the sake of simplicity assume I have a file called _module.py and a file __init__.py that sit in a directory called my_library.

# file _module.py
def _do_something():
    print('hello')

class foo():
    def bar(self):
        _do_something()
# file __init__.py
from ._module import foo

I have tried monkey patching the function _do_something like this

import my_library
my_library._do_something = lambda: print('goodbye')
a = my_library.foo()
a.bar()

but it still outputs hello. I also have tried the following

from my_library import foo, _do_something
_do_something = lambda: print('goodbye')
a = foo()
a.bar()

but it throws a cannot import name '_do_something' from 'my_library' error.


How can I modify _do_something such that the change is reflected when I call foo.bar?


PS: Actually I want to change the function _estimate_gaussian_parameters used by sklearn.mixture.GaussianMixture and both are located in the same file. But I don't think this is relevant to the question.


Solution

  • You should patch the function of _module and not the one imported in my_library:

    import my_library
    my_library._module._do_something = lambda: print('goodbye')
    a = my_library.foo()
    a.bar()
    

    Also I recommend using unittest.mock (see doc for patch):

    import my_library
    from unittest.mock import patch
    
    with patch.object(my_library._module, '_do_something', lambda: print('goodbye')):
        a = my_library.foo()
        a.bar()