commit 57542fa3d5c0f76c5004930ff281f44f70693248 Author: Gregory M. Turner Date: Wed Dec 3 04:01:43 2014 -0800 Lib/test/test_types.py: virtual metaclass tests Test that virtual inheritance relationships don't confuse new_class or its dependencies in Lib/types.py. Issue #22968. Signed-off-by: Gregory M. Turner diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 11d9546..d800195 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -864,6 +864,38 @@ class ClassCreationTests(unittest.TestCase): ns['BMeta_was_here'] = True return ns + # metaclass which is virtually a subclass of CMeta + class VirtCMeta(type): + def __new__(mcls, name, bases, ns): + new_calls.append('VirtCMeta') + return super().__new__(mcls, name, bases, ns) + class CMetaMeta(type): + def __subclasscheck__(meta, C): + if meta is CMeta and issubclass(C, VirtCMeta): + return True + if meta is CMeta and meta is C: + return True + if meta is CMeta: + return False + return super().__subclasscheck__(C) + def __instancecheck__(meta, O): + if meta is CMeta and isinstance(O, VirtCMeta): + return True + if meta is CMeta and meta is type(O): + return True + if meta is CMeta: + return False + return super().__instancecheck__(O) + class CMeta(type, metaclass=CMetaMeta): + def __new__(mcls, name, bases, ns): + new_calls.append('CMeta') + return super().__new__(mcls, name, bases, ns) + # metaclass which is virtually not a subclass of CMeta + class DMeta(CMeta): + def __new__(mcls, name, bases, ns): + new_calls.append('DMeta') + return super().__new__(mcls, name, bases, ns) + A = types.new_class("A", (), {"metaclass": AMeta}) self.assertEqual(new_calls, ['AMeta']) new_calls.clear() @@ -897,6 +929,23 @@ class ClassCreationTests(unittest.TestCase): new_calls.clear() self.assertIn('BMeta_was_here', E.__dict__) + # Virtual metaclass sub-class won't resolve metaclass conflict: + F = types.new_class("F", (), {"metaclass": CMeta}) + self.assertEqual(new_calls, ['CMeta']) + new_calls.clear() + with self.assertRaises(TypeError): + types.new_class("NotG", (F,), {"metaclass": VirtCMeta}) + self.assertEqual(new_calls, []) + new_calls.clear() + + # Virtual metaclass conflict won't cause a real conflict: + G = types.new_class("G", (), {"metaclass": DMeta}) + self.assertEqual(new_calls, ['DMeta', 'CMeta']) + new_calls.clear() + I = types.new_class("H", (G, F)) + self.assertEqual(new_calls, ['DMeta', 'CMeta']) + new_calls.clear() + def test_metaclass_override_function(self): # Special case: the given metaclass isn't a class, # so there is no metaclass calculation.