Index: Doc/library/abc.rst =================================================================== --- Doc/library/abc.rst (revision 87899) +++ Doc/library/abc.rst (working copy) @@ -51,6 +51,9 @@ assert issubclass(tuple, MyABC) assert isinstance((), MyABC) + .. versionchanged:: 3.3 + Returns the registered subclass, to allow usage as a class decorator. + You can also override this method in an abstract base class: .. method:: __subclasshook__(subclass) Index: Lib/abc.py =================================================================== --- Lib/abc.py (revision 87899) +++ Lib/abc.py (working copy) @@ -133,11 +133,14 @@ return cls def register(cls, subclass): - """Register a virtual subclass of an ABC.""" + """Register a virtual subclass of an ABC. + + Return the subclass, to allow usage as a class decorator. + """ if not isinstance(subclass, type): raise TypeError("Can only register classes") if issubclass(subclass, cls): - return # Already a subclass + return subclass # Already a subclass # Subtle: test for cycles *after* testing for "already a subclass"; # this means we allow X.register(X) and interpret it as a no-op. if issubclass(cls, subclass): @@ -145,6 +148,7 @@ raise RuntimeError("Refusing to create an inheritance cycle") cls._abc_registry.add(subclass) ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache + return subclass def _dump_registry(cls, file=None): """Debug helper to print the ABC registry.""" Index: Lib/test/test_abc.py =================================================================== --- Lib/test/test_abc.py (revision 87899) +++ Lib/test/test_abc.py (working copy) @@ -128,11 +128,12 @@ self.assertFalse(issubclass(B, (A,))) self.assertNotIsInstance(b, A) self.assertNotIsInstance(b, (A,)) - A.register(B) + 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() @@ -141,6 +142,27 @@ 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.assertIsInstahce(c, (A,)) + self.assertIs(C, A.register(C)) + def test_isinstance_invalidation(self): class A(metaclass=abc.ABCMeta): pass