bpo-41905: Add abc.update_abstractmethods() (GH-22485)

This function recomputes `cls.__abstractmethods__`.
Also update `@dataclass` to use it.
diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py
index 7e9c47b..3d603e7 100644
--- a/Lib/test/test_abc.py
+++ b/Lib/test/test_abc.py
@@ -488,6 +488,155 @@
                 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 with 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 with 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 with 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 with 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):