summaryrefslogtreecommitdiffstats
path: root/Lib/abc.py
diff options
context:
space:
mode:
authorBen Avrahami <avrahami.ben@gmail.com>2020-10-06 17:40:50 (GMT)
committerGitHub <noreply@github.com>2020-10-06 17:40:50 (GMT)
commitbef7d299eb911086ea5a7ccf7a9da337e38a8491 (patch)
tree25508f320dada76441df02c0ce5b756608524b39 /Lib/abc.py
parenta8bf44d04915f7366d9f8dfbf84822ac37a4bab3 (diff)
downloadcpython-bef7d299eb911086ea5a7ccf7a9da337e38a8491.zip
cpython-bef7d299eb911086ea5a7ccf7a9da337e38a8491.tar.gz
cpython-bef7d299eb911086ea5a7ccf7a9da337e38a8491.tar.bz2
bpo-41905: Add abc.update_abstractmethods() (GH-22485)
This function recomputes `cls.__abstractmethods__`. Also update `@dataclass` to use it.
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 431b640..276ef9a 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.