Does python's `unittest.mock.patch` mutate global state?

3k views Asked by At

I'm trying to determine if Python's mock.patch (unittest.mock.patch in Py3) context manager mutates global state, i.e., if it is thread-safe.

For instance: let's imagine one thread patches function bar within function foo with a context manager, and then inside the context manager the interpreter pauses that thread (because of the GIL etc.) and resumes another thread, which runs foo outside of said context manager. If patch is thread-safe I would expect that the global state of the functions foo and bar are unmodified, and so the second thread will get the normal behavior of foo. But if patch modifies global state, the second thread will get the modified behavior of foo even though it's not inside the context manager.

I referred to the source code but wasn't able to clearly tell just by looking at it.

2

There are 2 answers

0
Ned Batchelder On BEST ANSWER

mock.patch isn't inherently thread-safe or not thread-safe. It modifies an object. It's really nothing more than an assignment statement at the beginning, and then an undo-ing assignment statement at the end.

If the object being patched is accessed by multiple threads, then all the threads will see the change. Typically, it's used to modify attributes of modules, which are global state. When used this way, it is not thread safe.

0
Andrew Gorcester On

I went ahead and ran a crude experiment using multiprocessing.dummy.Pool on Python 3.4. The experiment mapped a function against range(100) input using the thread pool, and if the input of the function was exactly 10, it patched an inner function to call time.sleep(). If the patch was threadsafe, the results would all show up immediately except for the result for 10, which would show up late; if it was not threadsafe, a few results would show up immediately and many others would show up late.

The results demonstrated that unittest.mock.patch does mutate global state. Good to know!