Let's say we have two files:
to_patch.py
from unittest.mock import patch
def patch_a_function():
print("Patching!")
patcher = patch("to_be_patched.function")
patcher.start()
print("Done patching!")
to_be_patched.py
from to_patch import patch_a_function
def function():
pass
patch_a_function()
function()
And we run python -m to_be_patched. This will output:
Patching!
Patching!
- Why isn't
Done patching!ever printed? - Why is
Patching!printed twice?
I've narrowed the answer to (2) down; the call to patch.start seems to trigger patch_a_function again. I suspect this is because it's imported in to_be_patched.py, but am not sure why the function itself would run for a second time. Similarly, I'm not sure why the Done patching! line is not reached in either of the calls to patch_a_function. patcher.start() can't be blocking, because the program exits nicely instead of hanging there... right?
Edit: Huh. It looks like no one can reproduce Done patching! not being printed (which was honestly the main difficulty)—so I guess that's just a my-side problem
Can not reproduce.
Your module gets imported twice. If you add
print(__name__)into the fileto_be_patched.pyit will be clear:Result:
When you use
python -m to_be_patchedyour moduleto_be_patchedwill be loaded as top-level code, i.e. the module__name__will be"__main__".When
mock.patchis used, mock will first import the patch target. When given a patch target as a string like"to_be_patched.function"mock will useimportlib, viapkgutil.resolve_name, to find the correct namespace in which to patch. This method loads the target module with__name__as"to_be_patched", it's not the top-level code environment. Although it's the same underlying .py file being loaded, there is a cache miss insys.modules, because of the name mismatch:"__main__" != "to_be_patched".The function
patch_a_functionnow has dual identities and exists in the module__main__as well as the moduleto_be_patched, so what you're seeing is each one getting called. The first call triggers the second call, by the double-import mechanism described.