Search code examples
pythonpython-2.7inspectpython-mock

Mocking function argument names to work with inspect.getargspec


I'm trying to mock a function for a test that eventually passes the mock through the inspect.getargspec function. I'd like to use some specific names as argument names of the mocked function.

As far as I know, there's no specific way to mock argument names, so I'm trying to use Mock's spec= argument:

In [1]: import mock, inspect

In [2]: inspect.getargspec(mock.Mock(spec=lambda a,b:None))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-de358c5a968d> in <module>()
----> 1 inspect.getargspec(mock.Mock(spec=lambda a,b:None))

/usr/lib/python2.7/inspect.pyc in getargspec(func)
    815     if not isfunction(func):
    816         raise TypeError('{!r} is not a Python function'.format(func))
--> 817     args, varargs, varkw = getargs(func.func_code)
    818     return ArgSpec(args, varargs, varkw, func.func_defaults)
    819 

/usr/lib/python2.7/inspect.pyc in getargs(co)
    750 
    751     if not iscode(co):
--> 752         raise TypeError('{!r} is not a code object'.format(co))
    753 
    754     nargs = co.co_argcount

TypeError: <Mock name='mock.func_code' id='140395908951120'> is not a code object

So, yes, indeed, Mock is not a code object. How do I mock argument names so that inspect.getargspec returns these names?


Solution

  • Managed to find a workaround that almost doesn't hurt. So, following the example from the question text:

    In [1]: import mock, inspect
    

    Define the spec function (assigned to an identifier because I'll need it twice later):

    In [2]: specfun = lambda a,b: None
    

    Define the mock. After doing some experiments I noticed that inspect.getargspec simply needs a func_code object:

    In [3]: mockfun = mock.Mock(spec=specfun, func_code=specfun.func_code)
    

    Does it work with inspect.getargspec? Yes!

    In [4]: inspect.getargspec(mockfun)
    Out[4]: ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=<Mock name='mock.func_defaults' id='140160757665168'>)
    

    Does it work like a normal callable Mock? Yes!

    In [5]: mockfun('hello', 42)
    Out[5]: <Mock name='mock()' id='140160757483984'>
    
    In [6]: mockfun.call_args_list
    Out[6]: [call('hello', 42)]