diff -r b0cc8c9ab912 Lib/abc.py --- a/Lib/abc.py Tue Aug 13 19:51:29 2013 -0400 +++ b/Lib/abc.py Wed Aug 14 15:12:54 2013 +0200 @@ -166,6 +166,26 @@ ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache return subclass + def get_virtual_subclasses(cls, recursive=False): + """Get registered virtual subclasses of an ABC.""" + if not recursive: + return set(cls._abc_registry) + subclasses = set() + def recurse_abc(c): + # recurse into ABC's subclasses + subclasses.update(c._abc_registry) + for sc in c.__subclasses__(): + recurse_abc(sc) + def recurse_subclasses(c): + # recurse into registered virtual classes + subclasses.add(c) + for sc in c.__subclasses__(): + recurse_subclasses(sc) + recurse_abc(cls) + for c in subclasses.copy(): + recurse_subclasses(c) + return subclasses + def _dump_registry(cls, file=None): """Debug helper to print the ABC registry.""" print("Class: %s.%s" % (cls.__module__, cls.__name__), file=file) diff -r b0cc8c9ab912 Lib/test/test_abc.py --- a/Lib/test/test_abc.py Tue Aug 13 19:51:29 2013 -0400 +++ b/Lib/test/test_abc.py Wed Aug 14 15:12:54 2013 +0200 @@ -258,12 +258,16 @@ self.assertFalse(issubclass(B, (A,))) self.assertNotIsInstance(b, A) self.assertNotIsInstance(b, (A,)) + self.assertEqual(A.get_virtual_classes(), set()) + self.assertEqual(A.get_virtual_classes(1), set()) B1 = A.register(B) self.assertTrue(issubclass(B, A)) self.assertTrue(issubclass(B, (A,))) self.assertIsInstance(b, A) self.assertIsInstance(b, (A,)) self.assertIs(B1, B) + self.assertEqual(A.get_virtual_classes(), {B}) + self.assertEqual(A.get_virtual_classes(1), {B}) class C(B): pass c = C() @@ -271,6 +275,27 @@ self.assertTrue(issubclass(C, (A,))) self.assertIsInstance(c, A) self.assertIsInstance(c, (A,)) + self.assertEqual(A.get_virtual_classes(), {B}) + self.assertEqual(A.get_virtual_classes(1), {B, C}) + class A2(A): + pass + class D: + pass + self.assertEqual(A.get_virtual_classes(), {B}) + self.assertEqual(A.get_virtual_classes(1), {B, C}) + self.assertEqual(A2.get_virtual_classes(), set()) + self.assertEqual(A2.get_virtual_classes(1), set()) + A2.register(D) + self.assertEqual(A.get_virtual_classes(), {B}) + self.assertEqual(A.get_virtual_classes(1), {B, C, D}) + self.assertEqual(A2.get_virtual_classes(), {D}) + self.assertEqual(A2.get_virtual_classes(1), {D}) + class E(D): + pass + self.assertEqual(A.get_virtual_classes(), {B}) + self.assertEqual(A.get_virtual_classes(1), {B, C, D, E}) + self.assertEqual(A2.get_virtual_classes(), {D}) + self.assertEqual(A2.get_virtual_classes(1), {D, E}) def test_register_as_class_deco(self): class A(metaclass=abc.ABCMeta):