Question

Running this file foo.py

import inspect

class Parent(object):
    def source1(self):
        class A(object):
            def foo(self):
                pass
        print inspect.getsource(A)
    def source2(self):
        class A(object):
            def bar(self, a, b, c):
                pass
        print inspect.getsource(A)


parent = Parent()
parent.source1()
parent.source2()

produces this output:

    class A(object):
        def foo(self):
            pass

    class A(object):
        def foo(self):
            pass

when I expect it to produce this output:

    class A(object):
        def foo(self):
            pass

    class A(object):
        def bar(self, a, b, c):
            pass

I am encountering this problem in my tests. I reuse the names A and B for class names within the body of the test method. I'm testing a function that relies on inspect.getsource and, well... it doesn't work because later tests are given the source from earlier-named A and B classes.

Was it helpful?

Solution

The inspect.getsource call actually parses the source file, looking for the class definition, and returns the first one it finds at the lowest level of indentation with the name it's looking for. In other words, it won't do what you're asking it to do.

Here's a slightly different approach that results in the output you're looking for, and perhaps will do what you need:

import inspect

class Parent(object):
    def source1(self):
        class A1(object):
            def foo(self):
                pass
        A = A1
        print inspect.getsource(A)
    def source2(self):
        class A2(object):
            def bar(self, a, b, c):
                pass
        A = A2
        print inspect.getsource(A)


parent = Parent()
parent.source1()
parent.source2()

The class definitions can still be referenced by the names you want (e.g. "A"), but the actual definition in the source code uses a different name, so getsource can find it.

OTHER TIPS

This is because inspect.getsource finds the first matched class A in the source file. According to 545 line in inspect.py of Python 2.7.6, this pattern is used to find the source.

pat = re.compile(r'^(\s*)class\s*' + name + r'\b')

So if you defined class A in front of code at first as

import inspect

class A(object):
    pass

class Parent(object):
    def source1(self):
        class A(object):
            def foo(self):
                pass
        print 'id of A in source1 :', id(A)
        print inspect.getsource(A)
    def source2(self):
        class A(object):
            def bar(self, a, b, c):
                pass
        print 'id of A in source2 :', id(A)
        print inspect.getsource(A)

print 'id of A in global :', id(A)
parent = Parent()
parent.source1()
parent.source2()

The result will be

id of A in global : 12512848
id of A in source1 : 12415088
class A(object):
    pass

id of A in source2 : 12356672
class A(object):
    pass

Even though their object id are different.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top