Adventures in Meta programming in Python: im_class, __import__, __getattribute__


With my recent work in Python win32 programming I’ve had a real need for AAA style mocking framework. Unable to find anything that I’ve been completely happy with I started my own simple mocking framework and got to learn some Python style meta programming  in the process. I’ve found out a lot about the depth of the Python 2.x object model over the last 2 weeks and here are some of the nicer things I’ve found (updated as per Chris Taveres below):

function_class = MyClass.foo.im_class

This is useful if you pass in an instance method  somewhere and you want to be able to access its attached class.  Decorators on instance methods normally use this, but I needed it to get a nicer syntax on my asserts, I wanted this:

 

assertCalled(FakeRepo.get)

 

So now when I want to track what class is passed in I just have to start with the following:

def assertCalled(method):
    classdef = method.im_class #I get the method and the class in one parameter!

module = __import__(“foomodule”)

this creates a module import by string. This becomes super powerful say if you wanted to replace functionality on a module, but didn’t know its name before hand.  In my case I wanted to be able to patch in a replacement method for mocking and then put it back when I was done, and I didn’t want to have to keep passing in the module name on resets. The only downside to it so far is it behaves a little quirky with packages and you have walk your module hierarchy to get it to do what you want

example of patching originals back into the module:

for mod, original in _originals.items():  #key is a combination of module name and methodname, value is the original function itself
    modulename = mod[]
    methodname = mod[1]
    module = __import__(modulename)  #this is the magic. if module name has no package aka : “barmod” this will work. if its “foopackage.barmod” it’ll import the “foopackage” 
    for i in modulename.split(“.”)[1:]: #works down the chain 
        module = getattr(module, i) #resets the module variable with the lower hierarchy module 
    setattr(module, methodname, original) #actually pass the original function object back onto the module.

###

 

MyClass.__getattribute__ = interception

__getattribute__ is called when any attribute is accessed on a class including __getattribute__ itself which is a bit silly.  This was the primary engine of my mocking framework as it allowed me to record all calls to the methods on a mocked class.  Just remember when you use this to have it not call itself or you’ll be in endless recursion!

example:

class MyClass(object):</p>

    def stuff(self):
        pass

def interceptor(self, name):
    if name == “__getattribute__”: #guard condition against calling itself
        return object.__getattribute__(self, name)
        #whatever interception logic you need here

MyClass.__getattribute__ = interceptor
= MyClass()
m.stuff() #interception logic will be called here </div> </div>

 

I’m just starting to dip into the Python object model now and I’ll try and share what I find over the next few weeks.

Take 3: Python, ISP, IoC, and OCP need a fundamental rethink.