I am currently working on extending a third-party code base. This code base unfortunately tightly couples its get_args with every other function. get_args is basically just a getter for a global object _ARGS. Now, I'd like to modify the args for a single function call without actually modifying the global object itself.
To this end, I used unittest.mock.patch to patch the get_args function, and while it succeeds in patching it in my target function f, it does not translate to functions called by f if they are in other modules. The reason is, of course, that I only patch get_args in the module with the called function f.
Is it possible to mock every subsequent call to get_args within my with block?
My current approach might not be the best one to tackle this problem, so I'm also open to alternative solutions to this problem.
Minimum reproducible example:
My code main.py:
from argparse import Namespace
import unittest.mock
from mod0 import get_args
from mod1 import f1
def new_get_args():
return Namespace(**{
**get_args().__dict__,
'a': 'a',
})
def main():
with unittest.mock.patch('mod1.get_args', new=new_get_args):
f1()
main()
Module mod0:
from argparse import Namespace
_ARGS = None
def get_args():
global _ARGS
if _ARGS is None:
_ARGS = Namespace(a=1, b=2)
return _ARGS
Module mod1:
from mod0 import get_args
from mod2 import f2
def f1():
args = get_args()
args.c = 3
print(f"[f1] Args: {args}")
f2()
Module mod2:
from mod0 import get_args
def f2():
args = get_args()
print(f"[f2] Args: {args}")
Result:
[f1] Args: Namespace(a='a', b=2, c=3)
[f2] Args: Namespace(a=1, b=2)
What I need:
[f1] Args: Namespace(a='a', b=2, c=3)
[f2] Args: Namespace(a='a', b=2, c=3)