PyCallExpression#multiResolveCallee giving wrong results.

Answered

Example:

class Z:
def __init__(self):
self.z = 'from Zs constructor'
print('from Zs constructor')


class A(Z):
def __init__(self):
super().__init__()
self.a = 'from As constructor'
print('from As constructor')


class B:
def __init__(self):
self.b = 'from Bs constructor'
print('from Bs constructor')


class C(A, B):
def __init__(self):
super(C, self).__init__() # Calls A's constructor
self.c = 'from Cs constructor'
print('from Cs constructor')


def driver(a):
a.b = C()

 

super(C, self).__init__() resolves to 2 methods:

- A::__init__

- B::__init__

 

But it should only resolve to A::__init__ only. Is this a bug?

 

Follow-up question:

Is the resolved method will always be in the same order? Means if I get resolved callee in the following order: A::__init__ and B::__init__, can it be B::__init__ and A__init__ in another call to multiResolveCallee?

3 comments
Comment actions Permalink

It's a subtle bug caused by the way the resolve for references on "super" works at the moment. In order to resolve any qualified name, we first resolve the type of its qualifier. For most kinds of expressions, it's a straightforward process, but "super" is different because its own result in a particular expression depends on which attribute you're accessing. In your case, when you're calling "__init__", it's indeed "A". However, if you modify the example slightly by accessing an attribute defined only in "B":

class Z:
def __init__(self):
pass


class A(Z):
def __init__(self):
super().__init__()


class B:
def __init__(self):
pass

def method(self):
pass


class C(A, B):
def __init__(self):
super(C, self).__init__() # super(C, self) should resolve to A
super(C, self).method() # super(C, self) should resolve to B

it turns out that just taking the first class in MRO order of C is not enough.

In order not to special case "super()" we infer its type as a union of the corresponding class' base classes. It's not entirely correct, and I've filed a couple of tickets about it (PY-53713, PY-53714). However, in most cases, the first item of `multiResolve` should still give what you're looking for. Where did you face this problem?

0
Comment actions Permalink

BTW, the cause of the current behavior can be pinpointed by invoking "Type Info" action on "super()" call.

0
Comment actions Permalink

Thank you for your response. Hope to see this bug fixed in the next release. 

0

Please sign in to leave a comment.