summaryrefslogtreecommitdiff
path: root/Lib/abc.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/abc.py')
-rw-r--r--Lib/abc.py38
1 files changed, 38 insertions, 0 deletions
diff --git a/Lib/abc.py b/Lib/abc.py
index 431b64040a..276ef9a2cd 100644
--- a/Lib/abc.py
+++ b/Lib/abc.py
@@ -122,6 +122,44 @@ else:
_reset_caches(cls)
+def update_abstractmethods(cls):
+ """Recalculate the set of abstract methods of an abstract class.
+
+ If a class has had one of its abstract methods implemented after the
+ class was created, the method will not be considered implemented until
+ this function is called. Alternatively, if a new abstract method has been
+ added to the class, it will only be considered an abstract method of the
+ class after this function is called.
+
+ This function should be called before any use is made of the class,
+ usually in class decorators that add methods to the subject class.
+
+ Returns cls, to allow usage as a class decorator.
+
+ If cls is not an instance of ABCMeta, does nothing.
+ """
+ if not hasattr(cls, '__abstractmethods__'):
+ # We check for __abstractmethods__ here because cls might by a C
+ # implementation or a python implementation (especially during
+ # testing), and we want to handle both cases.
+ return cls
+
+ abstracts = set()
+ # Check the existing abstract methods of the parents, keep only the ones
+ # that are not implemented.
+ for scls in cls.__bases__:
+ for name in getattr(scls, '__abstractmethods__', ()):
+ value = getattr(cls, name, None)
+ if getattr(value, "__isabstractmethod__", False):
+ abstracts.add(name)
+ # Also add any other newly added abstract methods.
+ for name, value in cls.__dict__.items():
+ if getattr(value, "__isabstractmethod__", False):
+ abstracts.add(name)
+ cls.__abstractmethods__ = frozenset(abstracts)
+ return cls
+
+
class ABC(metaclass=ABCMeta):
"""Helper class that provides a standard way to create an ABC using
inheritance.