TAGS :Viewed: 7 - Published at: a few seconds ago

[ How to mock an instance variable in nested class ]

Simplified Example:

def bind_method(**config):
    class InstagramAPIMethod(object):
        def __init__(self, *args, **kwargs):
            self.return_json = kwargs.pop("return_json", False)
    def _call(*args, **kwargs):
        method = InstagramAPIMethod(*args, **kwargs)
        return method.__dict__

    return _call

class InstAPI():
  result = bind_method(foo='bar')

api = InstAPI()
print api.result()

# {'return_json': False}

From the above example are there any ways to "monkey patch" an "InstAPI" instance or use "partial" function to hardcode the value to "_call" function in such a way so that it would return {'return_json': True} ?

Reallife Example:

https://github.com/Instagram/python-instagram.git

If you look at the https://github.com/Instagram/python-instagram/blob/master/instagram/bind.py#L42-L69

You will see bind_method function that looks like this:

def bind_method(**config):
  class InstagramAPIMethod(object):
    path = config['path']
    method = config.get('method', 'GET')

In https://github.com/Instagram/python-instagram/blob/master/instagram/bind.py#L64 line there is a parameter. I can't find a clear way how to change it to True.

Answer 1


mock give to you some way to do it. The case is little bit tricky because

  1. InstagramAPIMethod is defined in bind_method function
  2. InstAPI store bind_method definition at load time

So patch bind_method or InstagramAPIMethod class have no effect. You have just a chance: patch InstAPI.result. I've take in account of 2 case:

  1. I don't care of the work in bind_method and I need just that api.result() return a dictionary like {'return_json': True}
  2. I would like that result() return exactly what bind_method return except changing some values

Following the code for the toy example that should work also in the real life.

def bind_method(**config):
    class InstagramAPIMethod(object):
        def __init__(self, *args, **kwargs):
            self.return_json = kwargs.pop("return_json", False)
    def _call(*args, **kwargs):
        method = InstagramAPIMethod(*args, **kwargs)
        return method.__dict__
    return _call

class InstAPI():
  result = bind_method(foo='bar')

api = InstAPI()
print api.result()


from mock import patch
#Patch directly InstAPI.result
with patch("__main__.InstAPI.result",return_value={'return_json': True}):
    api = InstAPI()
    print api.result()

#The wrapper of bind_method
def new_instapi_result(**kwargs):
    def functor(**config):
        d = bind_method(**config)()
        d.update(kwargs)
        return d
    return functor

#Patch and wrap bind_method
with patch("__main__.InstAPI.result",side_effect=new_instapi_result(return_json = True)):
    api = InstAPI()
    print api.result()