@@ -31,6 +31,7 @@ |
|
|
31 |
31 |
__author__ = ('Ka-Ping Yee ping@lfw.org', |
32 |
32 |
'Yury Selivanov yselivanov@sprymix.com') |
33 |
33 |
|
|
34 |
+import abc |
34 |
35 |
import ast |
35 |
36 |
import dis |
36 |
37 |
import collections.abc |
@@ -291,7 +292,27 @@ def isroutine(object): |
|
|
291 |
292 |
|
292 |
293 |
def isabstract(object): |
293 |
294 |
"""Return true if the object is an abstract base class (ABC).""" |
294 |
|
-return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT) |
|
295 |
+if not isinstance(object, type): |
|
296 |
+return False |
|
297 |
+if object.__flags__ & TPFLAGS_IS_ABSTRACT: |
|
298 |
+return True |
|
299 |
+if not issubclass(type(object), abc.ABCMeta): |
|
300 |
+return False |
|
301 |
+if hasattr(object, '__abstractmethods__'): |
|
302 |
+# It looks like ABCMeta.__new__ has finished running; |
|
303 |
+# TPFLAGS_IS_ABSTRACT should have been accurate. |
|
304 |
+return False |
|
305 |
+# It looks like ABCMeta.__new__ has not finished running yet; we're |
|
306 |
+# probably in __init_subclass__. We'll look for abstractmethods manually. |
|
307 |
+for name, value in object.__dict__.items(): |
|
308 |
+if getattr(value, "__isabstractmethod__", False): |
|
309 |
+return True |
|
310 |
+for base in object.__bases__: |
|
311 |
+for name in getattr(base, "__abstractmethods__", ()): |
|
312 |
+value = getattr(object, name, None) |
|
313 |
+if getattr(value, "__isabstractmethod__", False): |
|
314 |
+return True |
|
315 |
+return False |
295 |
316 |
|
296 |
317 |
def getmembers(object, predicate=None): |
297 |
318 |
"""Return all members of an object as (name, value) pairs sorted by name. |