Here is an executable code which works in Python 2.7 but results in an error in Python 3.6:
import six
class AMeta(type):
def __new__(cls, name, bases, attrs):
module = attrs.pop('__module__')
new_attrs = {'__module__': module}
classcell = attrs.pop('__classcell__', None)
if classcell is not None:
new_attrs['__classcell__'] = classcell
new = super(AMeta, cls).__new__(
cls, name, bases, new_attrs)
new.duplicate = False
legacy = super(AMeta, cls).__new__(
cls, 'Legacy' + name, (new,), new_attrs)
legacy.duplicate = True
return new
@six.add_metaclass(AMeta)
class A():
def pr(cls):
print('a')
class B():
def pr(cls):
print('b')
class C(A,B):
def pr(cls):
super(C, cls).pr() # not shown with new_attrs
B.pr(cls)
print('c') # not shown with new_attrs
c = C()
c.pr()
# Expected result
# a
# b
# c
I get the following error:
Traceback (most recent call last):
File "test.py", line 28, in <module>
class C(A,B):
TypeError: __class__ set to <class '__main__.LegacyC'> defining 'C' as <class '__main__.C'>
C is inherit from A that is generated with the metaclass AMeta. They are tests classes and AMeta's goal is to execute all the tests with 2 different file folders: the default one and the legacy one.
I found a way to remove thise error by removing classcell from attrs, then returning new = super(AMeta, cls).new(cls, name, bases, attrs) (not new_attrs) but it doesn't seem right, and if it is, I'd like to know why.
The goal of new_attrs resulted from this SO question or from the documentation where it states basically the opposite: when modifying the attrs, make sure to keep classcell because it is deprecated in Python 3.6 and will result in an error in Python 3.8. Note that in this case, it removes the pr definition because they weren't passed to new_attrs, thus prints 'b' instead of 'abc', but is irrelevant for this problem.
Is there a way to call multiple super().new inside the new of a metaclass AMeta, and then call them from a class C inheriting from the class inheriting A ?
Without nesting inheritance, the error doesn't appear, like this:
import six
class AMeta(type):
def __new__(cls, name, bases, attrs):
new = super(AMeta, cls).__new__(
cls, name, bases, attrs)
new.duplicate = False
legacy = super(AMeta, cls).__new__(
cls, 'Duplicate' + name, (new,), attrs)
legacy.duplicate = True
return new
@six.add_metaclass(AMeta)
class A():
def pr(cls):
print('a')
a = A()
a.pr()
# Result
# a
Then maybe it is A's role to do something to fix it?
Thanks by advance,