This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ethan.furman
Recipients ethan.furman, serhiy.storchaka
Date 2020-12-29.03:06:49
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1609211209.61.0.873859112725.issue42775@roundup.psfhosted.org>
In-reply-to
Content
PEP 487 introduced __init_subclass__ and __set_name__, and both of those were wins for the common cases of metaclass usage.

Unfortunately, the implementation of PEP 487 with regards to __init_subclass__ has made the writing of correct metaclasses significantly harder, if not impossible.

The cause is that when a metaclass calls type.__new__ to actually create the class, type.__new__ calls the __init_subclass__ methods of the new class' parents, passing it the newly created, but incomplete, class.  In code:

```
class Meta(type):
    #
    def __new__(mcls, name, bases, namespace, **kwds):
        # create new class, which will call __init_subclass__ and __set_name__
        new_class = type.__new__(mcls, name, bases, namespace, **kwds)
        # finish setting up class
        new_class.some_attr = 9
```

As you can deduce, when the parent __init_subclass__ is called with the new class, `some_attr` has not been added yet -- the new class is incomplete.

For Enum, this means that __init_subclass__ doesn't have access to the new Enum's members (they haven't beet added yet).

For ABC, this means that __init_subclass__ doesn't have access to __abstract_methods__ (it hasn't been created yet).

Because Enum is pure Python code I was able to work around it:
- remove new __init_subclass__ (if it exists)
- insert dummy class with a no-op __init_subclass__
- call type.__new__
- save any actual __init_subclass__
- add back any new __init_subclass__
- rewrite the new class' __bases__, removing the no-op dummy class
- finish creating the class
- call the parent __init_subclass__ with the now complete Enum class

I have not been able to work around the problem for ABC.

The solution would seem to be to move the calls to __init_subclass__ and __set_names__ to type.__init__.
History
Date User Action Args
2020-12-29 03:06:49ethan.furmansetrecipients: + ethan.furman, serhiy.storchaka
2020-12-29 03:06:49ethan.furmansetmessageid: <1609211209.61.0.873859112725.issue42775@roundup.psfhosted.org>
2020-12-29 03:06:49ethan.furmanlinkissue42775 messages
2020-12-29 03:06:49ethan.furmancreate