Author Sergio Pascual
Recipients Sergio Pascual
Date 2015-03-03.12:17:08
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1425385029.2.0.304023107943.issue23572@psf.upfronthosting.co.za>
In-reply-to
Content
I admit this case is rather convoluted, but I have been debugging a few hours so I think I should share my findings.

I have a metaclass MetaA that provides to the classes constructed with it have a dictionary interface. Of all the functions only __len__ is important. In some cases, the result of __len__ is 0 and that is what triggers the error

class MetaA(type):
    def __len__(self):
        return 0

class A(metaclass=MetaA):
    pass

class AA(A):
    pass

Now, I construct a function with single dispatch and register the case of class A but not the class AA

@singledispatch
def fun(a):
    print('base case')

@fun.register(A)
def _(a):
    print('fun A')

And then, call fun with an object of class AA

fun(AA())

This should call the function for the class up in the hierarchy, A
Instead it raises an exception 

RuntimeError: Inconsistent hierarchy

in function functools._c3_merge
because in the line

if not candidate:
    raise RuntimeError("Inconsistent hierarchy")

"not candidate" evaluates to True due to __len__ returning 0


This can be avoided by:

* adding __nonzero__ to MetaA

* not adding the map interface to a class in the first place

* changing the code in _c3_merge 

I'm not really sure, but instead of:

if not candidate:
    raise RuntimeError("Inconsistent hierarchy")

would this work?

if candidate is None:
    raise RuntimeError("Inconsistent hierarchy")


I attach a test case
History
Date User Action Args
2015-03-03 12:17:09Sergio Pascualsetrecipients: + Sergio Pascual
2015-03-03 12:17:09Sergio Pascualsetmessageid: <1425385029.2.0.304023107943.issue23572@psf.upfronthosting.co.za>
2015-03-03 12:17:09Sergio Pascuallinkissue23572 messages
2015-03-03 12:17:08Sergio Pascualcreate