classification
Title: functools.singledispatch fails when "not BaseClass" is True
Type: Stage: patch review
Components: Library (Lib) Versions: Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: lukasz.langa Nosy List: Drekin, Sergio Pascual, lukasz.langa, paul.moore, python-dev, serhiy.storchaka, yselivanov
Priority: normal Keywords: patch

Created on 2015-03-03 12:17 by Sergio Pascual, last changed 2015-09-04 17:23 by lukasz.langa. This issue is now closed.

Files
File name Uploaded Description Edit
singledispatch-test.py Sergio Pascual, 2015-03-03 12:17 A class that breaks singledispatch
issue23572.stoneleaf.01.patch ethan.furman, 2015-05-16 22:38 review
Messages (9)
msg237126 - (view) Author: Sergio Pascual (Sergio Pascual) * Date: 2015-03-03 12:17
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
msg242291 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2015-04-30 23:13
Yes, this needs addressing.
msg242381 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-05-02 06:19
An example is Enum.
msg243374 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2015-05-16 22:38
Attached is patch and test case.
msg248685 - (view) Author: Adam Bartoš (Drekin) * Date: 2015-08-16 17:46
I was also bitten by this via Enum. Is there any chance this will be fixed in Python 3.5?
msg248782 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-08-18 18:23
New changeset 73984e665bf5 by Yury Selivanov in branch '3.5':
Issue #23572: Fixed functools.singledispatch on classes with falsy metaclasses.
https://hg.python.org/cpython/rev/73984e665bf5

New changeset 94d0c219d46f by Yury Selivanov in branch 'default':
Merge 3.5 (issue #23572)
https://hg.python.org/cpython/rev/94d0c219d46f
msg248783 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2015-08-18 18:24
> I was also bitten by this via Enum. Is there any chance this will be fixed in Python 3.5?

It will be fixed in 3.5.1.

Thanks for the patch, Ethan!
msg248784 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2015-08-18 18:41
New changeset 586195685aaf by Yury Selivanov in branch '3.4':
Issue #23572: Fixed functools.singledispatch on classes with falsy metaclasses.
https://hg.python.org/cpython/rev/586195685aaf
msg249792 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2015-09-04 17:23
Thank you for fixing this and sorry for not being responsive sooner!
History
Date User Action Args
2015-09-04 17:23:56lukasz.langasetmessages: + msg249792
2015-08-18 18:41:00python-devsetmessages: + msg248784
2015-08-18 18:38:46yselivanovsetversions: + Python 3.6
2015-08-18 18:24:22yselivanovsetstatus: open -> closed

nosy: + yselivanov
messages: + msg248783

resolution: fixed
2015-08-18 18:23:23python-devsetnosy: + python-dev
messages: + msg248782
2015-08-16 17:46:10Drekinsetnosy: + Drekin
messages: + msg248685
2015-07-21 07:11:45ethan.furmansetnosy: - ethan.furman
2015-05-16 22:38:14ethan.furmansetfiles: + issue23572.stoneleaf.01.patch
keywords: + patch
messages: + msg243374

stage: patch review
2015-05-02 06:19:35serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg242381
2015-05-01 07:19:24paul.mooresetnosy: + paul.moore
2015-05-01 03:45:48serhiy.storchakasetnosy: + ethan.furman
2015-04-30 23:13:29lukasz.langasetassignee: lukasz.langa
messages: + msg242291
versions: + Python 3.5
2015-03-04 02:58:42berker.peksagsetnosy: + lukasz.langa
2015-03-03 12:17:09Sergio Pascualcreate