def iter_module_doctestable(module, include_funcs=True, include_classes=True,
                            include_methods=True,
                            include_builtin=True,
                            include_inherited=False,
                            debug_key=None):
    r"""
    Yeilds doctestable live object form a modules

    TODO: change name to iter_module_members
    Replace with iter_module_doctesable (but change that name to be something
    better)

    Args:
        module (module): live python module
        include_funcs (bool):
        include_classes (bool):
        include_methods (bool):
        include_builtin (bool): (default = True)
        include_inherited (bool): (default = False)

    Yeilds:
        tuple (str, callable): (funcname, func) doctestable

    CommandLine:
        python -m utool --tf iter_module_doctestable \
            --modname=ibeis.algo.hots.chip_match
            --modname=ibeis.control.IBEISControl
            --modname=ibeis.control.SQLDatabaseControl
            --modname=ibeis.control.manual_annot_funcs
            --modname=ibeis.control.manual_annot_funcs
            --modname=ibeis.expt.test_result
            --modname=utool.util_progress --debug-key=build_msg_fmtstr_time2
            --modname=utool.util_progress --debug-key=ProgressIter

    Debug:
       # fix profile with doctest
       utprof.py -m utool --tf iter_module_doctestable --modname=utool.util_inspect --debugkey=zzz_profiled_is_yes
       utprof.py -m utool --tf iter_module_doctestable --modname=ibeis.algo.hots.chip_match --debugkey=to_json

    Example1:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_inspect import *   # NOQA
        >>> import utool as ut
        >>> modname = ut.get_argval('--modname', type_=str, default=None)
        >>> kwargs = ut.argparse_funckw(iter_module_doctestable)
        >>> module = ut.util_tests if modname is None else ut.import_modname(modname)
        >>> debug_key = ut.get_argval('--debugkey', type_=str, default=None)
        >>> kwargs['debug_key'] = debug_key
        >>> kwargs['include_inherited'] = True
        >>> doctestable_list = list(iter_module_doctestable(module, **kwargs))
        >>> func_names = sorted(ut.take_column(doctestable_list, 0))
        >>> print(ut.repr4(func_names))
    """
    import ctypes

    types.BuiltinFunctionType
    valid_func_types = [
        types.FunctionType, types.BuiltinFunctionType, classmethod,
        staticmethod,
        types.MethodType,  # handles classmethod
        # types.BuiltinMethodType,
    ]
    if include_builtin:
        valid_func_types += [
            types.BuiltinFunctionType
        ]

    if six.PY2:
        valid_class_types = (types.ClassType,  types.TypeType,)
    else:
        valid_class_types = six.class_types

    scalar_types = ([dict, list, tuple, set, frozenset, bool, float, int] +
                    list(six.string_types))
    scalar_types += list(six.string_types)
    other_types = [functools.partial, types.ModuleType,
                   ctypes.CDLL]
    if six.PY2:
        other_types += [types.InstanceType]

    invalid_types = tuple(scalar_types + other_types)
    valid_func_types = tuple(valid_func_types)

    #modpath = ut.get_modname_from_modpath(module.__file__)

    for key, val in six.iteritems(module.__dict__):
        # <DEBUG>
        if debug_key is not None and key == debug_key:
            print('DEBUG')
            print('debug_key = %r' % (debug_key,))
            exec('item = val')
            # import utool as ut
            # ut.embed()
        # </DEBUG>
        if hasattr(val, '__module__'):
            # HACK: todo. figure out true parent module
            if val.__module__ == 'numpy':
                continue
        if val is None:
            pass
        elif isinstance(val, valid_func_types):
            if include_funcs:
                if not include_inherited and not is_defined_by_module(val, module):
                    continue
                yield key, val
        elif isinstance(val, valid_class_types):
            class_ = val
            if not include_inherited and not is_defined_by_module(class_, module):
                continue
            if include_classes:
                # Yield the class itself
                yield key, val
            if include_methods:
                # Yield methods of the class
                for subkey, subval in six.iteritems(class_.__dict__):
                    if isinstance(subval, property):
                        subval = subval.fget
                    # <DEBUG>
                    if debug_key is not None and subkey == debug_key:
                        import utool as ut
                        ut.embed()
                    # </DEBUG>
                    # Unbound methods are still typed as functions
                    if isinstance(subval, valid_func_types):
                        if not include_inherited and not is_defined_by_module(subval, module, parent=val):
                            continue
                        if isinstance(subval, (staticmethod)):
                            subval.__func__.__ut_parent_class__ = class_
                        if not isinstance(subval, types.BuiltinFunctionType) and not isinstance(subval, (classmethod, staticmethod)):
                            # HACK: __ut_parent_class__ lets util_test have
                            # more info on the func should return extra info
                            # instead
                            subval.__ut_parent_class__ = class_
                        yield subkey, subval
                    elif isinstance(val, invalid_types):
                        pass
                    else:
                        if util_arg.VERBOSE:
                            print('[util_inspect] WARNING module %r class %r:' % (module, class_,))
                            print(' * Unknown if testable val=%r' % (val))
                            print(' * Unknown if testable type(val)=%r' % type(val))
        elif isinstance(val, invalid_types):
            pass
        else:
            #import utool as ut
            if util_arg.VERBOSE:
                print('[util_inspect] WARNING in module %r:' % (module,))
                print(' * Unknown if testable val=%r' % (val))
                print(' * Unknown if testable type(val)=%r' % type(val))
def iter_module_doctestable ( module , include_funcs = True , include_classes = True , include_methods = True , include_builtin = True , include_inherited = False , debug_key = None ) : import ctypes types . BuiltinFunctionType valid_func_types = [ types . FunctionType , types . BuiltinFunctionType , classmethod , staticmethod , types . MethodType , ] if include_builtin : valid_func_types += [ types . BuiltinFunctionType ] if six . PY2 : valid_class_types = ( types . ClassType , types . TypeType , ) else : valid_class_types = six . class_types scalar_types = ( [ dict , list , tuple , set , frozenset , bool , float , int ] + list ( six . string_types ) ) scalar_types += list ( six . string_types ) other_types = [ functools . partial , types . ModuleType , ctypes . CDLL ] if six . PY2 : other_types += [ types . InstanceType ] invalid_types = tuple ( scalar_types + other_types ) valid_func_types = tuple ( valid_func_types ) for key , val in six . iteritems ( module . __dict__ ) : if debug_key is not None and key == debug_key : print ( 'DEBUG' ) print ( 'debug_key = %r' % ( debug_key , ) ) exec ( 'item = val' ) if hasattr ( val , '__module__' ) : if val . __module__ == 'numpy' : continue if val is None : pass elif isinstance ( val , valid_func_types ) : if include_funcs : if not include_inherited and not is_defined_by_module ( val , module ) : continue yield key , val elif isinstance ( val , valid_class_types ) : class_ = val if not include_inherited and not is_defined_by_module ( class_ , module ) : continue if include_classes : yield key , val if include_methods : for subkey , subval in six . iteritems ( class_ . __dict__ ) : if isinstance ( subval , property ) : subval = subval . fget if debug_key is not None and subkey == debug_key : import utool as ut ut . embed ( ) if isinstance ( subval , valid_func_types ) : if not include_inherited and not is_defined_by_module ( subval , module , parent = val ) : continue if isinstance ( subval , ( staticmethod ) ) : subval . __func__ . __ut_parent_class__ = class_ if not isinstance ( subval , types . BuiltinFunctionType ) and not isinstance ( subval , ( classmethod , staticmethod ) ) : subval . __ut_parent_class__ = class_ yield subkey , subval elif isinstance ( val , invalid_types ) : pass else : if util_arg . VERBOSE : print ( '[util_inspect] WARNING module %r class %r:' % ( module , class_ , ) ) print ( ' * Unknown if testable val=%r' % ( val ) ) print ( ' * Unknown if testable type(val)=%r' % type ( val ) ) elif isinstance ( val , invalid_types ) : pass else : if util_arg . VERBOSE : print ( '[util_inspect] WARNING in module %r:' % ( module , ) ) print ( ' * Unknown if testable val=%r' % ( val ) ) print ( ' * Unknown if testable type(val)=%r' % type ( val ) )
r"""
    Yeilds doctestable live object form a modules

    TODO: change name to iter_module_members
    Replace with iter_module_doctesable (but change that name to be something
    better)

    Args:
        module (module): live python module
        include_funcs (bool):
        include_classes (bool):
        include_methods (bool):
        include_builtin (bool): (default = True)
        include_inherited (bool): (default = False)

    Yeilds:
        tuple (str, callable): (funcname, func) doctestable

    CommandLine:
        python -m utool --tf iter_module_doctestable \
            --modname=ibeis.algo.hots.chip_match
            --modname=ibeis.control.IBEISControl
            --modname=ibeis.control.SQLDatabaseControl
            --modname=ibeis.control.manual_annot_funcs
            --modname=ibeis.control.manual_annot_funcs
            --modname=ibeis.expt.test_result
            --modname=utool.util_progress --debug-key=build_msg_fmtstr_time2
            --modname=utool.util_progress --debug-key=ProgressIter

    Debug:
       # fix profile with doctest
       utprof.py -m utool --tf iter_module_doctestable --modname=utool.util_inspect --debugkey=zzz_profiled_is_yes
       utprof.py -m utool --tf iter_module_doctestable --modname=ibeis.algo.hots.chip_match --debugkey=to_json

    Example1:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_inspect import *   # NOQA
        >>> import utool as ut
        >>> modname = ut.get_argval('--modname', type_=str, default=None)
        >>> kwargs = ut.argparse_funckw(iter_module_doctestable)
        >>> module = ut.util_tests if modname is None else ut.import_modname(modname)
        >>> debug_key = ut.get_argval('--debugkey', type_=str, default=None)
        >>> kwargs['debug_key'] = debug_key
        >>> kwargs['include_inherited'] = True
        >>> doctestable_list = list(iter_module_doctestable(module, **kwargs))
        >>> func_names = sorted(ut.take_column(doctestable_list, 0))
        >>> print(ut.repr4(func_names))