codekingpro/portable-devtools
114k
1"""2Routines for obtaining the class names3of an object and its parent classes.4"""5 6from __future__ import annotations7 8from typing import TYPE_CHECKING, cast9 10from more_itertools import unique_everseen11 12if TYPE_CHECKING:13 from collections.abc import Iterator14 from typing import Any15 16 17def all_bases(c: type[object]) -> list[type[Any]]:18 """19 return a tuple of all base classes the class c has as a parent.20 >>> object in all_bases(list)21 True22 """23 return c.mro()[1:]24 25 26def all_classes(c: type[object]) -> list[type[Any]]:27 """28 return a tuple of all classes to which c belongs29 >>> list in all_classes(list)30 True31 """32 return c.mro()33 34 35# borrowed from36# http://code.activestate.com/recipes/576949-find-all-subclasses-of-a-given-class/37 38 39def iter_subclasses(cls: type[object]) -> Iterator[type[Any]]:40 """41 Generator over all subclasses of a given class, in depth-first order.42 43 >>> bool in list(iter_subclasses(int))44 True45 >>> class A(object): pass46 >>> class B(A): pass47 >>> class C(A): pass48 >>> class D(B,C): pass49 >>> class E(D): pass50 >>>51 >>> for cls in iter_subclasses(A):52 ... print(cls.__name__)53 B54 D55 E56 C57 >>> # get ALL classes currently defined58 >>> res = [cls.__name__ for cls in iter_subclasses(object)]59 >>> 'type' in res60 True61 >>> 'tuple' in res62 True63 >>> len(res) > 10064 True65 """66 return unique_everseen(_iter_all_subclasses(cls))67 68 69def _iter_all_subclasses(cls: type[object]) -> Iterator[type[Any]]:70 try:71 subs = cls.__subclasses__()72 except TypeError: # fails only when cls is type73 subs = cast('type[type]', cls).__subclasses__(cls)74 for sub in subs:75 yield sub76 yield from iter_subclasses(sub)77 