2007 google inc licensed to psf under a contributor agreement note each test is run with python and c versions of abcmeta except for testabchelper which assures that abc abc is an instance of abc abcmeta unit tests for abc py import unittest import abc import pyabc from inspect import isabstract def testfactoryabcabcmeta abcgetcachetoken class testlegacyapiunittest testcase def testabstractpropertybasicsself abc abstractproperty def fooself pass self asserttruefoo isabstractmethod def barself pass self assertfalsehasattrbar isabstractmethod class cmetaclassabcabcmeta abc abstractproperty def fooself return 3 self assertraisestypeerror c class dc property def fooself return super foo self assertequald foo 3 self assertfalsegetattrd foo isabstractmethod false def testabstractclassmethodbasicsself abc abstractclassmethod def foocls pass self asserttruefoo isabstractmethod classmethod def barcls pass self assertfalsegetattrbar isabstractmethod false class cmetaclassabcabcmeta abc abstractclassmethod def foocls return cls name self assertraisestypeerror c class dc classmethod def foocls return super foo self assertequald foo d self assertequald foo d def testabstractstaticmethodbasicsself abc abstractstaticmethod def foo pass self asserttruefoo isabstractmethod staticmethod def bar pass self assertfalsegetattrbar isabstractmethod false class cmetaclassabcabcmeta abc abstractstaticmethod def foo return 3 self assertraisestypeerror c class dc staticmethod def foo return 4 self assertequald foo 4 self assertequald foo 4 class testabcunittest testcase def testabchelperself create an abc using the helper class and perform basic checks class cabc abc classmethod abc abstractmethod def foocls return cls name self assertequaltypec abc abcmeta self assertraisestypeerror c class dc classmethod def foocls return super foo self assertequald foo d def testabstractmethodbasicsself abc abstractmethod def fooself pass self asserttruefoo isabstractmethod def barself pass self assertfalsehasattrbar isabstractmethod def testabstractpropertybasicsself property abc abstractmethod def fooself pass self asserttruefoo isabstractmethod def barself pass self assertfalsegetattrbar isabstractmethod false class cmetaclassabcabcmeta property abc abstractmethod def fooself return 3 self assertraisestypeerror c class dc c foo getter def fooself return super foo self assertequald foo 3 def testabstractclassmethodbasicsself classmethod abc abstractmethod def foocls pass self asserttruefoo isabstractmethod classmethod def barcls pass self assertfalsegetattrbar isabstractmethod false class cmetaclassabcabcmeta classmethod abc abstractmethod def foocls return cls name self assertraisestypeerror c class dc classmethod def foocls return super foo self assertequald foo d self assertequald foo d def testabstractstaticmethodbasicsself staticmethod abc abstractmethod def foo pass self asserttruefoo isabstractmethod staticmethod def bar pass self assertfalsegetattrbar isabstractmethod false class cmetaclassabcabcmeta staticmethod abc abstractmethod def foo return 3 self assertraisestypeerror c class dc staticmethod def foo return 4 self assertequald foo 4 self assertequald foo 4 def testobjectnewwithoneabstractmethodself class cmetaclassabcabcmeta abc abstractmethod def methodoneself pass msg rclass c without an implementation for abstract method methodone self assertraisesregextypeerror msg c def testobjectnewwithmanyabstractmethodsself class cmetaclassabcabcmeta abc abstractmethod def methodoneself pass abc abstractmethod def methodtwoself pass msg rclass c without an implementation for abstract methods methodone methodtwo self assertraisesregextypeerror msg c def testabstractmethodintegrationself for abstractthing in abc abstractmethod abc abstractproperty abc abstractclassmethod abc abstractstaticmethod class cmetaclassabcabcmeta abstractthing def fooself pass abstract def barself pass concrete self assertequalc abstractmethods foo self assertraisestypeerror c because foo is abstract self asserttrueisabstractc class dc def barself pass concrete override of concrete self assertequald abstractmethods foo self assertraisestypeerror d because foo is still abstract self asserttrueisabstractd class ed def fooself pass self assertequale abstractmethods set e now foo is concrete too self assertfalseisabstracte class fe abstractthing def barself pass abstract override of concrete self assertequalf abstractmethods bar self assertraisestypeerror f because bar is abstract now self asserttrueisabstractf def testdescriptorswithabstractmethodself class cmetaclassabcabcmeta property abc abstractmethod def fooself return 3 foo setter abc abstractmethod def fooself val pass self assertraisestypeerror c class dc c foo getter def fooself return super foo self assertraisestypeerror d class ed d foo setter def fooself val pass self assertequale foo 3 check that the property s isabstractmethod descriptor does the right thing when presented with a value that fails truth testing class notboolobject def boolself raise valueerror len bool with self assertraisesvalueerror class fc def barself pass bar isabstractmethod notbool foo propertybar def testcustomdescriptorswithabstractmethodself class descriptor def initself fget fsetnone self fget fget self fset fset def getterself callable return descriptorcallable self fget def setterself callable return descriptorself fget callable property def isabstractmethodself return getattrself fget isabstractmethod false or getattrself fset isabstractmethod false class cmetaclassabcabcmeta descriptor abc abstractmethod def fooself return 3 foo setter abc abstractmethod def fooself val pass self assertraisestypeerror c class dc c foo getter def fooself return super foo self assertraisestypeerror d class ed d foo setter def fooself val pass self assertfalsee foo isabstractmethod def testmetaclassabcself metaclasses can be abcs too class ametaclassabcabcmeta abc abstractmethod def xself pass self assertequala abstractmethods x class metatype a def xself return 1 class cmetaclassmeta pass def testregistrationbasicsself class ametaclassabcabcmeta pass class bobject pass b b self assertfalseissubclassb a self assertfalseissubclassb a self assertnotisinstanceb a self assertnotisinstanceb a b1 a registerb self asserttrueissubclassb a self asserttrueissubclassb a self assertisinstanceb a self assertisinstanceb a self assertisb1 b class cb pass c c self asserttrueissubclassc a self asserttrueissubclassc a self assertisinstancec a self assertisinstancec a def testregisterasclassdecoself class ametaclassabcabcmeta pass a register class bobject pass b b self asserttrueissubclassb a self asserttrueissubclassb a self assertisinstanceb a self assertisinstanceb a a register class cb pass c c self asserttrueissubclassc a self asserttrueissubclassc a self assertisinstancec a self assertisinstancec a self assertisc a registerc def testisinstanceinvalidationself class ametaclassabcabcmeta pass class b pass b b self assertfalseisinstanceb a self assertfalseisinstanceb a tokenold abcgetcachetoken a registerb tokennew abcgetcachetoken self assertgreatertokennew tokenold self asserttrueisinstanceb a self asserttrueisinstanceb a def testregistrationbuiltinsself class ametaclassabcabcmeta pass a registerint self assertisinstance42 a self assertisinstance42 a self asserttrueissubclassint a self asserttrueissubclassint a class ba pass b registerstr class cstr pass self assertisinstance a self assertisinstance a self asserttrueissubclassstr a self asserttrueissubclassstr a self asserttrueissubclassc a self asserttrueissubclassc a def testregistrationedgecasesself class ametaclassabcabcmeta pass a registera should pass silently class a1a pass self assertraisesruntimeerror a1 register a cycles not allowed class bobject pass a1 registerb ok a1 registerb should pass silently class ca pass a registerc should pass silently self assertraisesruntimeerror c register a cycles not allowed c registerb ok def testregisternonclassself class ametaclassabcabcmeta pass self assertraisesregextypeerror can only register classes a register 4 def testregistrationtransitivenessself class ametaclassabcabcmeta pass self asserttrueissubclassa a self asserttrueissubclassa a class bmetaclassabcabcmeta pass self assertfalseissubclassa b self assertfalseissubclassa b self assertfalseissubclassb a self assertfalseissubclassb a class cmetaclassabcabcmeta pass a registerb class b1b pass self asserttrueissubclassb1 a self asserttrueissubclassb1 a class c1c pass b1 registerc1 self assertfalseissubclassc b self assertfalseissubclassc b self assertfalseissubclassc b1 self assertfalseissubclassc b1 self asserttrueissubclassc1 a self asserttrueissubclassc1 a self asserttrueissubclassc1 b self asserttrueissubclassc1 b self asserttrueissubclassc1 b1 self asserttrueissubclassc1 b1 c1 registerint class myintint pass self asserttrueissubclassmyint a self asserttrueissubclassmyint a self assertisinstance42 a self assertisinstance42 a def testissubclassbadargumentsself class ametaclassabcabcmeta pass with self assertraisestypeerror issubclass a unhashable with self assertraisestypeerror issubclass42 a no mro python version supports any iterable as mro but it s implementation detail and don t emulate it in c version class c mro 42 mro is not tuple with self assertraisestypeerror issubclassc a bpo34441 check that issubclass doesn t crash on bogus classes bogussubclasses none lambda x lambda 42 lambda 42 for i func in enumeratebogussubclasses class smetaclassabcabcmeta subclasses func with self subtestii with self assertraisestypeerror issubclassint s also check that issubclass propagates exceptions raised by subclasses class customerrorexception excmsg exception from subclasses def raiseexc raise customerrorexcmsg class smetaclassabcabcmeta subclasses raiseexc with self assertraisesregexcustomerror excmsg issubclassint s def testsubclasshookself class ametaclassabc abcmeta classmethod def subclasshookcls c if cls is a return foo in c dict return notimplemented self assertfalseissubclassa a self assertfalseissubclassa a class b foo 42 self asserttrueissubclassb a self asserttrueissubclassb a class c spam 42 self assertfalseissubclassc a self assertfalseissubclassc a def testallnewmethodsarecalledself class ametaclassabcabcmeta pass class bobject counter 0 def newcls b counter 1 return super newcls class ca b pass self assertequalb counter 0 c self assertequalb counter 1 def testabchasslotsself self asserttruehasattrabc abc slots def testtrickynewworksself def withmetaclassmeta bases class metaclasstype def newcls name thisbases d return metaname bases d return type newmetaclass temporaryclass class a class b class cwithmetaclassabcabcmeta a b pass self assertequalc class abcabcmeta def testupdatedelself class ametaclassabcabcmeta abc abstractmethod def fooself pass del a foo self assertequala abstractmethods foo self assertfalsehasattra foo abc updateabstractmethodsa self assertequala abstractmethods set a def testupdatenewabstractmethodsself class ametaclassabcabcmeta abc abstractmethod def barself pass abc abstractmethod def updatedfooself pass a foo updatedfoo abc updateabstractmethodsa self assertequala abstractmethods foo bar msg class a without an implementation for abstract methods bar foo self assertraisesregextypeerror msg a def testupdateimplementationself class ametaclassabcabcmeta abc abstractmethod def fooself pass class ba pass msg class b without an implementation for abstract method foo self assertraisesregextypeerror msg b self assertequalb abstractmethods foo b foo lambda self none abc updateabstractmethodsb b self assertequalb abstractmethods set def testupdateasdecoratorself class ametaclassabcabcmeta abc abstractmethod def fooself pass def classdecoratorcls cls foo lambda self none return cls abc updateabstractmethods classdecorator class ba pass b self assertequalb abstractmethods set def testupdatenonabcself class a pass abc abstractmethod def updatedfooself pass a foo updatedfoo abc updateabstractmethodsa a self assertfalsehasattra abstractmethods def testupdatedelimplementationself class ametaclassabcabcmeta abc abstractmethod def fooself pass class ba def fooself pass b del b foo abc updateabstractmethodsb msg class b without an implementation for abstract method foo self assertraisesregextypeerror msg b def testupdatelayeredimplementationself class ametaclassabcabcmeta abc abstractmethod def fooself pass class ba pass class cb def fooself pass c del c foo abc updateabstractmethodsc msg class c without an implementation for abstract method foo self assertraisesregextypeerror msg c def testupdatemultiinheritanceself class ametaclassabcabcmeta abc abstractmethod def fooself pass class bmetaclassabcabcmeta def fooself pass class cb a abc abstractmethod def fooself pass self assertequalc abstractmethods foo del c foo abc updateabstractmethodsc self assertequalc abstractmethods set c class testabcwithinitsubclassunittest testcase def testworkswithinitsubclassself class abcabcmetaclassabcabcmeta slots savedkwargs class receivesclasskwargs def initsubclasscls kwargs super initsubclass savedkwargs updatekwargs class receiverreceivesclasskwargs abcabc x1 y2 z3 pass self assertequalsavedkwargs dictx1 y2 z3 def testpositionalonlyandkwonlyargswithinitsubclassself savedkwargs class a def initsubclasscls kwargs super initsubclass savedkwargs updatekwargs class ba metaclassabcabcmeta nametest pass self assertequalsavedkwargs dictnametest return testlegacyapi testabc testabcwithinitsubclass testlegacyapipy testabcpy testabcwithinitsubclasspy testfactoryabc abcmeta abc getcachetoken testlegacyapic testabcc testabcwithinitsubclassc testfactorypyabc abcmeta pyabc getcachetoken if name main unittest main 2007 google inc licensed to psf under a contributor agreement note each test is run with python and c versions of abcmeta except for test_abc_helper which assures that abc abc is an instance of abc abcmeta unit tests for abc py create an abc using the helper class and perform basic checks abstract concrete because foo is abstract concrete override of concrete because foo is still abstract now foo is concrete too abstract override of concrete because bar is abstract now check that the property s __isabstractmethod__ descriptor does the right thing when presented with a value that fails truth testing metaclasses can be abcs too should pass silently cycles not allowed ok should pass silently should pass silently cycles not allowed ok unhashable no __mro__ python version supports any iterable as __mro__ but it s implementation detail and don t emulate it in c version __mro__ is not tuple bpo 34441 check that issubclass doesn t crash on bogus classes also check that issubclass propagates exceptions raised by __subclasses__
import unittest

import abc
import _py_abc
from inspect import isabstract

def test_factory(abc_ABCMeta, abc_get_cache_token):
    class TestLegacyAPI(unittest.TestCase):

        def test_abstractproperty_basics(self):
            @abc.abstractproperty
            def foo(self): pass
            self.assertTrue(foo.__isabstractmethod__)
            def bar(self): pass
            self.assertFalse(hasattr(bar, "__isabstractmethod__"))

            class C(metaclass=abc_ABCMeta):
                @abc.abstractproperty
                def foo(self): return 3
            self.assertRaises(TypeError, C)
            class D(C):
                @property
                def foo(self): return super().foo
            self.assertEqual(D().foo, 3)
            self.assertFalse(getattr(D.foo, "__isabstractmethod__", False))

        def test_abstractclassmethod_basics(self):
            @abc.abstractclassmethod
            def foo(cls): pass
            self.assertTrue(foo.__isabstractmethod__)
            @classmethod
            def bar(cls): pass
            self.assertFalse(getattr(bar, "__isabstractmethod__", False))

            class C(metaclass=abc_ABCMeta):
                @abc.abstractclassmethod
                def foo(cls): return cls.__name__
            self.assertRaises(TypeError, C)
            class D(C):
                @classmethod
                def foo(cls): return super().foo()
            self.assertEqual(D.foo(), 'D')
            self.assertEqual(D().foo(), 'D')

        def test_abstractstaticmethod_basics(self):
            @abc.abstractstaticmethod
            def foo(): pass
            self.assertTrue(foo.__isabstractmethod__)
            @staticmethod
            def bar(): pass
            self.assertFalse(getattr(bar, "__isabstractmethod__", False))

            class C(metaclass=abc_ABCMeta):
                @abc.abstractstaticmethod
                def foo(): return 3
            self.assertRaises(TypeError, C)
            class D(C):
                @staticmethod
                def foo(): return 4
            self.assertEqual(D.foo(), 4)
            self.assertEqual(D().foo(), 4)


    class TestABC(unittest.TestCase):

        def test_ABC_helper(self):
            
            class C(abc.ABC):
                @classmethod
                @abc.abstractmethod
                def foo(cls): return cls.__name__
            self.assertEqual(type(C), abc.ABCMeta)
            self.assertRaises(TypeError, C)
            class D(C):
                @classmethod
                def foo(cls): return super().foo()
            self.assertEqual(D.foo(), 'D')

        def test_abstractmethod_basics(self):
            @abc.abstractmethod
            def foo(self): pass
            self.assertTrue(foo.__isabstractmethod__)
            def bar(self): pass
            self.assertFalse(hasattr(bar, "__isabstractmethod__"))

        def test_abstractproperty_basics(self):
            @property
            @abc.abstractmethod
            def foo(self): pass
            self.assertTrue(foo.__isabstractmethod__)
            def bar(self): pass
            self.assertFalse(getattr(bar, "__isabstractmethod__", False))

            class C(metaclass=abc_ABCMeta):
                @property
                @abc.abstractmethod
                def foo(self): return 3
            self.assertRaises(TypeError, C)
            class D(C):
                @C.foo.getter
                def foo(self): return super().foo
            self.assertEqual(D().foo, 3)

        def test_abstractclassmethod_basics(self):
            @classmethod
            @abc.abstractmethod
            def foo(cls): pass
            self.assertTrue(foo.__isabstractmethod__)
            @classmethod
            def bar(cls): pass
            self.assertFalse(getattr(bar, "__isabstractmethod__", False))

            class C(metaclass=abc_ABCMeta):
                @classmethod
                @abc.abstractmethod
                def foo(cls): return cls.__name__
            self.assertRaises(TypeError, C)
            class D(C):
                @classmethod
                def foo(cls): return super().foo()
            self.assertEqual(D.foo(), 'D')
            self.assertEqual(D().foo(), 'D')

        def test_abstractstaticmethod_basics(self):
            @staticmethod
            @abc.abstractmethod
            def foo(): pass
            self.assertTrue(foo.__isabstractmethod__)
            @staticmethod
            def bar(): pass
            self.assertFalse(getattr(bar, "__isabstractmethod__", False))

            class C(metaclass=abc_ABCMeta):
                @staticmethod
                @abc.abstractmethod
                def foo(): return 3
            self.assertRaises(TypeError, C)
            class D(C):
                @staticmethod
                def foo(): return 4
            self.assertEqual(D.foo(), 4)
            self.assertEqual(D().foo(), 4)

        def test_object_new_with_one_abstractmethod(self):
            class C(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def method_one(self):
                    pass
            msg = r"class C without an implementation for abstract method 'method_one'"
            self.assertRaisesRegex(TypeError, msg, C)

        def test_object_new_with_many_abstractmethods(self):
            class C(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def method_one(self):
                    pass
                @abc.abstractmethod
                def method_two(self):
                    pass
            msg = r"class C without an implementation for abstract methods 'method_one', 'method_two'"
            self.assertRaisesRegex(TypeError, msg, C)

        def test_abstractmethod_integration(self):
            for abstractthing in [abc.abstractmethod, abc.abstractproperty,
                                  abc.abstractclassmethod,
                                  abc.abstractstaticmethod]:
                class C(metaclass=abc_ABCMeta):
                    @abstractthing
                    def foo(self): pass  
                    def bar(self): pass  
                self.assertEqual(C.__abstractmethods__, {"foo"})
                self.assertRaises(TypeError, C)  
                self.assertTrue(isabstract(C))
                class D(C):
                    def bar(self): pass  
                self.assertEqual(D.__abstractmethods__, {"foo"})
                self.assertRaises(TypeError, D)  
                self.assertTrue(isabstract(D))
                class E(D):
                    def foo(self): pass
                self.assertEqual(E.__abstractmethods__, set())
                E()  
                self.assertFalse(isabstract(E))
                class F(E):
                    @abstractthing
                    def bar(self): pass  
                self.assertEqual(F.__abstractmethods__, {"bar"})
                self.assertRaises(TypeError, F)  
                self.assertTrue(isabstract(F))

        def test_descriptors_with_abstractmethod(self):
            class C(metaclass=abc_ABCMeta):
                @property
                @abc.abstractmethod
                def foo(self): return 3
                @foo.setter
                @abc.abstractmethod
                def foo(self, val): pass
            self.assertRaises(TypeError, C)
            class D(C):
                @C.foo.getter
                def foo(self): return super().foo
            self.assertRaises(TypeError, D)
            class E(D):
                @D.foo.setter
                def foo(self, val): pass
            self.assertEqual(E().foo, 3)
            
            
            class NotBool(object):
                def __bool__(self):
                    raise ValueError()
                __len__ = __bool__
            with self.assertRaises(ValueError):
                class F(C):
                    def bar(self):
                        pass
                    bar.__isabstractmethod__ = NotBool()
                    foo = property(bar)


        def test_customdescriptors_with_abstractmethod(self):
            class Descriptor:
                def __init__(self, fget, fset=None):
                    self._fget = fget
                    self._fset = fset
                def getter(self, callable):
                    return Descriptor(callable, self._fget)
                def setter(self, callable):
                    return Descriptor(self._fget, callable)
                @property
                def __isabstractmethod__(self):
                    return (getattr(self._fget, '__isabstractmethod__', False)
                            or getattr(self._fset, '__isabstractmethod__', False))
            class C(metaclass=abc_ABCMeta):
                @Descriptor
                @abc.abstractmethod
                def foo(self): return 3
                @foo.setter
                @abc.abstractmethod
                def foo(self, val): pass
            self.assertRaises(TypeError, C)
            class D(C):
                @C.foo.getter
                def foo(self): return super().foo
            self.assertRaises(TypeError, D)
            class E(D):
                @D.foo.setter
                def foo(self, val): pass
            self.assertFalse(E.foo.__isabstractmethod__)

        def test_metaclass_abc(self):
            
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def x(self):
                    pass
            self.assertEqual(A.__abstractmethods__, {"x"})
            class meta(type, A):
                def x(self):
                    return 1
            class C(metaclass=meta):
                pass

        def test_registration_basics(self):
            class A(metaclass=abc_ABCMeta):
                pass
            class B(object):
                pass
            b = B()
            self.assertFalse(issubclass(B, A))
            self.assertFalse(issubclass(B, (A,)))
            self.assertNotIsInstance(b, A)
            self.assertNotIsInstance(b, (A,))
            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)
            class C(B):
                pass
            c = C()
            self.assertTrue(issubclass(C, A))
            self.assertTrue(issubclass(C, (A,)))
            self.assertIsInstance(c, A)
            self.assertIsInstance(c, (A,))

        def test_register_as_class_deco(self):
            class A(metaclass=abc_ABCMeta):
                pass
            @A.register
            class B(object):
                pass
            b = B()
            self.assertTrue(issubclass(B, A))
            self.assertTrue(issubclass(B, (A,)))
            self.assertIsInstance(b, A)
            self.assertIsInstance(b, (A,))
            @A.register
            class C(B):
                pass
            c = C()
            self.assertTrue(issubclass(C, A))
            self.assertTrue(issubclass(C, (A,)))
            self.assertIsInstance(c, A)
            self.assertIsInstance(c, (A,))
            self.assertIs(C, A.register(C))

        def test_isinstance_invalidation(self):
            class A(metaclass=abc_ABCMeta):
                pass
            class B:
                pass
            b = B()
            self.assertFalse(isinstance(b, A))
            self.assertFalse(isinstance(b, (A,)))
            token_old = abc_get_cache_token()
            A.register(B)
            token_new = abc_get_cache_token()
            self.assertGreater(token_new, token_old)
            self.assertTrue(isinstance(b, A))
            self.assertTrue(isinstance(b, (A,)))

        def test_registration_builtins(self):
            class A(metaclass=abc_ABCMeta):
                pass
            A.register(int)
            self.assertIsInstance(42, A)
            self.assertIsInstance(42, (A,))
            self.assertTrue(issubclass(int, A))
            self.assertTrue(issubclass(int, (A,)))
            class B(A):
                pass
            B.register(str)
            class C(str): pass
            self.assertIsInstance("", A)
            self.assertIsInstance("", (A,))
            self.assertTrue(issubclass(str, A))
            self.assertTrue(issubclass(str, (A,)))
            self.assertTrue(issubclass(C, A))
            self.assertTrue(issubclass(C, (A,)))

        def test_registration_edge_cases(self):
            class A(metaclass=abc_ABCMeta):
                pass
            A.register(A)  
            class A1(A):
                pass
            self.assertRaises(RuntimeError, A1.register, A)  
            class B(object):
                pass
            A1.register(B)  
            A1.register(B)  
            class C(A):
                pass
            A.register(C)  
            self.assertRaises(RuntimeError, C.register, A)  
            C.register(B)  

        def test_register_non_class(self):
            class A(metaclass=abc_ABCMeta):
                pass
            self.assertRaisesRegex(TypeError, "Can only register classes",
                                   A.register, 4)

        def test_registration_transitiveness(self):
            class A(metaclass=abc_ABCMeta):
                pass
            self.assertTrue(issubclass(A, A))
            self.assertTrue(issubclass(A, (A,)))
            class B(metaclass=abc_ABCMeta):
                pass
            self.assertFalse(issubclass(A, B))
            self.assertFalse(issubclass(A, (B,)))
            self.assertFalse(issubclass(B, A))
            self.assertFalse(issubclass(B, (A,)))
            class C(metaclass=abc_ABCMeta):
                pass
            A.register(B)
            class B1(B):
                pass
            self.assertTrue(issubclass(B1, A))
            self.assertTrue(issubclass(B1, (A,)))
            class C1(C):
                pass
            B1.register(C1)
            self.assertFalse(issubclass(C, B))
            self.assertFalse(issubclass(C, (B,)))
            self.assertFalse(issubclass(C, B1))
            self.assertFalse(issubclass(C, (B1,)))
            self.assertTrue(issubclass(C1, A))
            self.assertTrue(issubclass(C1, (A,)))
            self.assertTrue(issubclass(C1, B))
            self.assertTrue(issubclass(C1, (B,)))
            self.assertTrue(issubclass(C1, B1))
            self.assertTrue(issubclass(C1, (B1,)))
            C1.register(int)
            class MyInt(int):
                pass
            self.assertTrue(issubclass(MyInt, A))
            self.assertTrue(issubclass(MyInt, (A,)))
            self.assertIsInstance(42, A)
            self.assertIsInstance(42, (A,))

        def test_issubclass_bad_arguments(self):
            class A(metaclass=abc_ABCMeta):
                pass

            with self.assertRaises(TypeError):
                issubclass({}, A)  

            with self.assertRaises(TypeError):
                issubclass(42, A)  

            
            
            class C:
                __mro__ = 42  

            with self.assertRaises(TypeError):
                issubclass(C(), A)

            
            
            bogus_subclasses = [
                None,
                lambda x: [],
                lambda: 42,
                lambda: [42],
            ]

            for i, func in enumerate(bogus_subclasses):
                class S(metaclass=abc_ABCMeta):
                    __subclasses__ = func

                with self.subTest(i=i):
                    with self.assertRaises(TypeError):
                        issubclass(int, S)

            
            
            class CustomError(Exception): ...
            exc_msg = "exception from __subclasses__"

            def raise_exc():
                raise CustomError(exc_msg)

            class S(metaclass=abc_ABCMeta):
                __subclasses__ = raise_exc

            with self.assertRaisesRegex(CustomError, exc_msg):
                issubclass(int, S)

        def test_subclasshook(self):
            class A(metaclass=abc.ABCMeta):
                @classmethod
                def __subclasshook__(cls, C):
                    if cls is A:
                        return 'foo' in C.__dict__
                    return NotImplemented
            self.assertFalse(issubclass(A, A))
            self.assertFalse(issubclass(A, (A,)))
            class B:
                foo = 42
            self.assertTrue(issubclass(B, A))
            self.assertTrue(issubclass(B, (A,)))
            class C:
                spam = 42
            self.assertFalse(issubclass(C, A))
            self.assertFalse(issubclass(C, (A,)))

        def test_all_new_methods_are_called(self):
            class A(metaclass=abc_ABCMeta):
                pass
            class B(object):
                counter = 0
                def __new__(cls):
                    B.counter += 1
                    return super().__new__(cls)
            class C(A, B):
                pass
            self.assertEqual(B.counter, 0)
            C()
            self.assertEqual(B.counter, 1)

        def test_ABC_has___slots__(self):
            self.assertTrue(hasattr(abc.ABC, '__slots__'))

        def test_tricky_new_works(self):
            def with_metaclass(meta, *bases):
                class metaclass(type):
                    def __new__(cls, name, this_bases, d):
                        return meta(name, bases, d)
                return type.__new__(metaclass, 'temporary_class', (), {})
            class A: ...
            class B: ...
            class C(with_metaclass(abc_ABCMeta, A, B)):
                pass
            self.assertEqual(C.__class__, abc_ABCMeta)

        def test_update_del(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            del A.foo
            self.assertEqual(A.__abstractmethods__, {'foo'})
            self.assertFalse(hasattr(A, 'foo'))

            abc.update_abstractmethods(A)

            self.assertEqual(A.__abstractmethods__, set())
            A()


        def test_update_new_abstractmethods(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def bar(self):
                    pass

            @abc.abstractmethod
            def updated_foo(self):
                pass

            A.foo = updated_foo
            abc.update_abstractmethods(A)
            self.assertEqual(A.__abstractmethods__, {'foo', 'bar'})
            msg = "class A without an implementation for abstract methods 'bar', 'foo'"
            self.assertRaisesRegex(TypeError, msg, A)

        def test_update_implementation(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            class B(A):
                pass

            msg = "class B without an implementation for abstract method 'foo'"
            self.assertRaisesRegex(TypeError, msg, B)
            self.assertEqual(B.__abstractmethods__, {'foo'})

            B.foo = lambda self: None

            abc.update_abstractmethods(B)

            B()
            self.assertEqual(B.__abstractmethods__, set())

        def test_update_as_decorator(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            def class_decorator(cls):
                cls.foo = lambda self: None
                return cls

            @abc.update_abstractmethods
            @class_decorator
            class B(A):
                pass

            B()
            self.assertEqual(B.__abstractmethods__, set())

        def test_update_non_abc(self):
            class A:
                pass

            @abc.abstractmethod
            def updated_foo(self):
                pass

            A.foo = updated_foo
            abc.update_abstractmethods(A)
            A()
            self.assertFalse(hasattr(A, '__abstractmethods__'))

        def test_update_del_implementation(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            class B(A):
                def foo(self):
                    pass

            B()

            del B.foo

            abc.update_abstractmethods(B)

            msg = "class B without an implementation for abstract method 'foo'"
            self.assertRaisesRegex(TypeError, msg, B)

        def test_update_layered_implementation(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            class B(A):
                pass

            class C(B):
                def foo(self):
                    pass

            C()

            del C.foo

            abc.update_abstractmethods(C)

            msg = "class C without an implementation for abstract method 'foo'"
            self.assertRaisesRegex(TypeError, msg, C)

        def test_update_multi_inheritance(self):
            class A(metaclass=abc_ABCMeta):
                @abc.abstractmethod
                def foo(self):
                    pass

            class B(metaclass=abc_ABCMeta):
                def foo(self):
                    pass

            class C(B, A):
                @abc.abstractmethod
                def foo(self):
                    pass

            self.assertEqual(C.__abstractmethods__, {'foo'})

            del C.foo

            abc.update_abstractmethods(C)

            self.assertEqual(C.__abstractmethods__, set())

            C()


    class TestABCWithInitSubclass(unittest.TestCase):
        def test_works_with_init_subclass(self):
            class abc_ABC(metaclass=abc_ABCMeta):
                __slots__ = ()
            saved_kwargs = {}
            class ReceivesClassKwargs:
                def __init_subclass__(cls, **kwargs):
                    super().__init_subclass__()
                    saved_kwargs.update(kwargs)
            class Receiver(ReceivesClassKwargs, abc_ABC, x=1, y=2, z=3):
                pass
            self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3))

        def test_positional_only_and_kwonlyargs_with_init_subclass(self):
            saved_kwargs = {}

            class A:
                def __init_subclass__(cls, **kwargs):
                    super().__init_subclass__()
                    saved_kwargs.update(kwargs)

            class B(A, metaclass=abc_ABCMeta, name="test"):
                pass
            self.assertEqual(saved_kwargs, dict(name="test"))

    return TestLegacyAPI, TestABC, TestABCWithInitSubclass

TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta,
                                                                        abc.get_cache_token)
TestLegacyAPI_C, TestABC_C, TestABCWithInitSubclass_C = test_factory(_py_abc.ABCMeta,
                                                                     _py_abc.get_cache_token)

if __name__ == "__main__":
    unittest.main()