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 ncoghlan
Recipients NeilGirdhar, docs@python, ncoghlan
Date 2016-10-15.07:49:00
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1476517741.09.0.266317624806.issue28437@psf.upfronthosting.co.za>
In-reply-to
Content
I'm not clear on what discrepancy you're referring to, as I get the same (expected) exception for both the class statement and the dynamic type creation:

>>> class MyDerived(MyClass, metaclass=metaclass_callable):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in metaclass_callable
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

>>> MyDerivedDynamic = new_class("MyDerivedDynamic", (MyClass,), dict(metaclass=metaclass_callable))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.5/types.py", line 57, in new_class
    return meta(name, bases, ns, **kwds)
  File "<stdin>", line 2, in metaclass_callable
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

This is due to the fact that your custom metaclass function returns an instance of a subclass of type, so we end up in type_new to actually create the type, which fails the metaclass consistency check.

One of the subtle intricacies here is that, for class statements, the logic that corresponds to types.prepare_class in the Python implementation is actually in the __build_class__ builtin for the C implementation - when there's a custom metaclass that *doesn't* return a subclass of type, we don't end up running type_new at all.

As a result of this, *both* implementations include a conditional check for a more derived metaclass in their namespace preparation logic, as well as an unconditional call to that metaclass derivation logic from type_new if the calculated metaclass is either type itself, or a subclass that calls up to super().__new__.

Most relevant issues and commit history:

- last update to C implementation
  - http://bugs.python.org/issue1294232
  - https://hg.python.org/cpython/rev/c2a89b509be4
- addition of pure Python implementation
  - http://bugs.python.org/issue14588
  - https://hg.python.org/cpython/rev/befd56673c80

The test cases in those commits (particularly the first one) should help make it clear what is and isn't supported behaviour.
History
Date User Action Args
2016-10-15 07:49:01ncoghlansetrecipients: + ncoghlan, docs@python, NeilGirdhar
2016-10-15 07:49:01ncoghlansetmessageid: <1476517741.09.0.266317624806.issue28437@psf.upfronthosting.co.za>
2016-10-15 07:49:01ncoghlanlinkissue28437 messages
2016-10-15 07:49:00ncoghlancreate