diff --git a/documentation/index.rst b/documentation/index.rst index 99192a21e..d31d4e33d 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -359,6 +359,12 @@ Python 2 and 3. pass MyClass = add_metaclass(Meta)(MyClass) + This technique works by re-building MyClass from the indicated metaclass, + but in the rare case where the parent has a metaclass that is a + superclass of the metaclass used with the decorator, this approach will + fail with a TypeError. See `issue 127 + `_ for details. + Binary and text data >>>>>>>>>>>>>>>>>>>> diff --git a/test_six.py b/test_six.py index 897e2322f..70f67ed1b 100644 --- a/test_six.py +++ b/test_six.py @@ -895,6 +895,30 @@ class B: pass assert A.B.__qualname__ == expected +def test_add_metaclass_child_meta(): + """ + Capture the known failure in the rare case where the parent + has a metaclass that is a superclass of the metaclass used + with the decorator (#127). + """ + class MetaA(type): pass + class MetaB(type): pass + + class A(object): pass + A = six.add_metaclass(MetaA)(A) + + class B(object): pass + B = six.add_metaclass(MetaB)(B) + + class MetaC(MetaA, MetaB): pass + + with py.test.raises(TypeError) as exc: + class C(A, B): pass + C = six.add_metaclass(MetaC)(C) + + assert 'metaclass conflict' in str(exc.value) + + @py.test.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))") def test_assertCountEqual(): class TestAssertCountEqual(unittest.TestCase):