Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError when combining ABCMeta with __init_subclass__ in Python 3.6

I'm trying to use python 3.6's new __init_subclass__ feature (PEP 487) with the abc module. It doesn't seem to be working. The following code:

from abc import ABCMeta
class Initifier:
    def __init_subclass__(cls, x=None, **kwargs):
        super().__init_subclass__(**kwargs)
        print('got x', x)

class Abstracted(metaclass=ABCMeta):
    pass

class Thingy(Abstracted, Initifier, x=1):
    pass

thingy = Thingy()

yields the following when run:

Traceback (most recent call last):
  File "<filename>", line 10, in <module>
    class Thingy(Abstracted, Initifier, x=1):
TypeError: __new__() got an unexpected keyword argument 'x'

Everything works fine if Abstracted doesn't use the ABCMeta metaclass.

This error is fairly resilient, for example, the following code still fails with a similar type error (presumably because a metaclass' __new__ runs at class instantiation time, whereas the parent class' __new__ doesn't run until object instantiation).

from abc import ABCMeta

class Initifier:
    def __new__(cls, name, bases, dct, x=None, **kwargs):
        return super().__new__(cls, name, bases, dct, **kwargs)

    def __init_subclass__(cls, x=None, **kwargs):
        super().__init_subclass__(**kwargs)
        print('got x', x)

class Abstracted(metaclass=ABCMeta):
    pass

class Thingy(Initifier, Abstracted, x=1):
    pass

thingy = Thingy()

Can anyone confirm that this is a bug in the Python 3.6 abc module and/or __init_subclass__ implementation? (I might be using __init_subclass__ wrong.) Does anyone have a workaround?

like image 881
So8res Avatar asked Feb 16 '17 18:02

So8res


1 Answers

It's a bug in abc.ABCMeta, due to a wart in the design of __init_subclass__. I recommend reporting it.

Pretty much every metaclass in existence is now supposed to pass unexpected keyword arguments through to super().__new__ so type.__new__ can pass them to __init_subclass__, but ABCMeta and probably tons of other metaclasses don't do that yet. abc.ABCMeta.__new__ chokes on the x keyword argument instead of passing it through, causing the exception you see.

Trying to use __init_subclass__ keyword arguments with a metaclass that hasn't been updated for the new design isn't going to work. You'll have to wait for the metaclasses you use to be patched.

like image 168
user2357112 supports Monica Avatar answered Sep 28 '22 08:09

user2357112 supports Monica