def descend_classes_and_funcs(mod: ModuleType, root: str, encountered=None):
    if (encountered is None):
        encountered = WeakSet()
    for obj in vars(mod).values():
        if (not _one_of_ours(obj, root)):
            continue
        if (callable(obj) and (not isinstance(obj, MethodType))):
            (yield obj)
            if isinstance(obj, type):
                for m in vars(obj).values():
                    if (callable(m) and _one_of_ours(m, root)):
                        (yield m)
        elif (isinstance(obj, ModuleType) and (obj not in encountered)):
            if obj.__name__.startswith('scanpy.tests'):
                continue
            encountered.add(obj)
            (yield from descend_classes_and_funcs(obj, root, encountered))
def descend_classes_and_funcs(mod: ModuleType, root: str, encountered=None):
    if (encountered is None):
        encountered = WeakSet()
    for obj in vars(mod).values():
        if (not _one_of_ours(obj, root)):
            continue
        if (callable(obj) and (not isinstance(obj, MethodType))):
            (yield obj)
            if isinstance(obj, type):
                for m in vars(obj).values():
                    if (callable(m) and _one_of_ours(m, root)):
                        (yield m)
        elif (isinstance(obj, ModuleType) and (obj not in encountered)):
            if obj.__name__.startswith('scanpy.tests'):
                continue
            encountered.add(obj)
            (yield from descend_classes_and_funcs(obj, root, encountered))