Creates skeleton code to build an example doctest

    Args:
        funcname (str):  function name
        modname (str):  module name
        argname_list (str):  list of argument names
        defaults (None):
        return_type (None):
        return_name (str):  return variable name
        ismethod (bool):

    Returns:
        str: examplecode

    CommandLine:
        python -m utool.util_autogen --test-make_example_docstr

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_autogen import *  # NOQA
        >>> funcname = 'make_example_docstr'
        >>> modname = 'utool.util_autogen'
        >>> argname_list = ['qaids', 'qreq_']
        >>> defaults = None
        >>> return_type = tuple
        >>> return_name = 'foo'
        >>> ismethod = False
        >>> examplecode = make_example_docstr(funcname, modname, argname_list, defaults, return_type, return_name, ismethod)
        >>> result = str(examplecode)
        >>> print(result)
        # DISABLE_DOCTEST
        from utool.util_autogen import *  # NOQA
        import utool as ut
        import ibeis
        species = ibeis.const.TEST_SPECIES.ZEB_PLAIN
        qaids = ibs.get_valid_aids(species=species)
        qreq_ = ibeis.testdata_qreq_()
        foo = make_example_docstr(qaids, qreq_)
        result = ('foo = %s' % (ut.repr2(foo),))
        print(result)

def make_example_docstr(funcname=None, modname=None, argname_list=None,
                        defaults=None, return_type=None, return_name=None,
                        ismethod=False):
    """
    Creates skeleton code to build an example doctest

    Args:
        funcname (str):  function name
        modname (str):  module name
        argname_list (str):  list of argument names
        defaults (None):
        return_type (None):
        return_name (str):  return variable name
        ismethod (bool):

    Returns:
        str: examplecode

    CommandLine:
        python -m utool.util_autogen --test-make_example_docstr

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_autogen import *  # NOQA
        >>> funcname = 'make_example_docstr'
        >>> modname = 'utool.util_autogen'
        >>> argname_list = ['qaids', 'qreq_']
        >>> defaults = None
        >>> return_type = tuple
        >>> return_name = 'foo'
        >>> ismethod = False
        >>> examplecode = make_example_docstr(funcname, modname, argname_list, defaults, return_type, return_name, ismethod)
        >>> result = str(examplecode)
        >>> print(result)
        # DISABLE_DOCTEST
        from utool.util_autogen import *  # NOQA
        import utool as ut
        import ibeis
        species = ibeis.const.TEST_SPECIES.ZEB_PLAIN
        qaids = ibs.get_valid_aids(species=species)
        qreq_ = ibeis.testdata_qreq_()
        foo = make_example_docstr(qaids, qreq_)
        result = ('foo = %s' % (ut.repr2(foo),))
        print(result)
    """
    import utool as ut

    examplecode_lines = []
    top_import_fmstr = 'from {modname} import *  # NOQA'
    top_import = top_import_fmstr.format(modname=modname)
    import_lines = [top_import]
    if modname.startswith('utool'):
        import_lines += ['import utool as ut']
    # is_show_func = not modname.startswith('utool') and not modname.startswith('mtgmonte')
    is_show_func = modname.startswith('plottool')

    # TODO: Externally register these
    default_argval_map = {
        'ibs'       : 'ibeis.opendb(defaultdb=\'testdb1\')',
        'testres'   : 'ibeis.testdata_expts(\'PZ_MTEST\')',
        'qreq_'     : 'ibeis.testdata_qreq_()',
        'cm_list'   : 'qreq_.execute()',
        'cm'        : 'qreq_.execute()[0]',
        'aid_list'  : 'ibs.get_valid_aids()',
        'nid_list'  : 'ibs._get_all_known_nids()',
        'qaids'     : 'ibs.get_valid_aids(species=species)',
        'daids'     : 'ibs.get_valid_aids(species=species)',
        'species'   : 'ibeis.const.TEST_SPECIES.ZEB_PLAIN',
        'kpts'      : 'vt.dummy.get_dummy_kpts()',
        'dodraw'    : 'ut.show_was_requested()',
        'img_fpath' : 'ut.grab_test_imgpath(\'carl.jpg\')',
        'gfpath'    : 'ut.grab_test_imgpath(\'carl.jpg\')',
        'img'       : 'vt.imread(img_fpath)',
        'img_in'    : 'vt.imread(img_fpath)',
        'bbox'      : '(10, 10, 50, 50)',
        'theta'     : '0.0',
        'rng'       : 'np.random.RandomState(0)',
    }
    import_depends_map = {
        'ibeis':    'import ibeis',
        'vt':       'import vtool as vt',
        #'img':      'import vtool as vt',  # TODO: remove. fix dependency
        #'species':  'import ibeis',
    }
    var_depends_map = {
        'species':   ['ibeis'],
        'ibs':       ['ibeis'],
        'testres': ['ibeis'],
        'kpts':      ['vt'],
        #'qreq_':     ['ibs', 'species', 'daids', 'qaids'],
        'qreq_':     ['ibeis'],
        'qaids':     ['ibs'],
        'daids':     ['ibs'],
        'qaids':     ['species'],
        'daids':     ['species'],
        'img':       ['img_fpath', 'vt'],
    }

    def find_arg_defaultrepr(argname, val):
        import types
        if val == '?':
            if argname in default_argval_map:
                val = ut.PythonStatement(default_argval_map[argname])
                if argname in import_depends_map:
                    import_lines.append(import_depends_map[argname])
        elif isinstance(val, types.ModuleType):
            return val.__name__
        return repr(val)

    # augment argname list with dependencies
    dependant_argnames = []  # deque()
    def append_dependant_argnames(argnames, dependant_argnames):
        """ use hints to add known dependencies for certain argument inputs """
        for argname in argnames:
            # Check if argname just implies an import
            if argname in import_depends_map:
                import_lines.append(import_depends_map[argname])
            # Check if argname was already added as dependency
            if (argname not in dependant_argnames and argname not in
                 argname_list and argname not in import_depends_map):
                dependant_argnames.append(argname)
            # Check if argname has dependants
            if argname in var_depends_map:
                argdeps = var_depends_map[argname]
                # RECURSIVE CALL
                append_dependant_argnames(argdeps, dependant_argnames)
    append_dependant_argnames(argname_list, dependant_argnames)

    # Define argnames and dependencies in example code
    # argnames prefixed with dependeancies
    argname_list_ = list(dependant_argnames) + argname_list

    # Default example values
    defaults_ = [] if defaults is None else defaults
    num_unknown = (len(argname_list_) - len(defaults_))
    default_vals = ['?'] * num_unknown + list(defaults_)
    arg_val_iter = zip(argname_list_, default_vals)
    inferred_defaults = [find_arg_defaultrepr(argname, val)
                         for argname, val in arg_val_iter]
    argdef_lines = ['%s = %s' % (argname, inferrepr)
                    for argname, inferrepr in
                    zip(argname_list_, inferred_defaults)]
    import_lines = ut.unique_ordered(import_lines)

    if any([inferrepr == repr('?') for inferrepr in inferred_defaults]):
        examplecode_lines.append('# DISABLE_DOCTEST')
    else:
        # Enable the test if it can be run immediately
        examplecode_lines.append('# DISABLE_DOCTEST')

    examplecode_lines.extend(import_lines)
    examplecode_lines.extend(argdef_lines)
    # Default example result assignment
    result_assign = ''
    result_print = None
    if 'return_name' in vars():
        if return_type is not None:
            if return_name is None:
                return_name = 'result'
            result_assign = return_name + ' = '
            result_print = 'print(result)'  # + return_name + ')'
    # Default example call
    if ismethod:
        selfname = argname_list[0]
        methodargs = ', '.join(argname_list[1:])
        tup = (selfname, '.', funcname, '(', methodargs, ')')
        example_call = ''.join(tup)
    else:
        funcargs = ', '.join(argname_list)
        tup = (funcname, '(', funcargs, ')')
        example_call = ''.join(tup)
    # Append call line
    examplecode_lines.append(result_assign + example_call)
    if result_print is not None:
        if return_name != 'result':
            #examplecode_lines.append('result = str(' + return_name + ')')
            result_line_fmt = 'result = (\'{return_name} = %s\' % (ut.repr2({return_name}),))'
            result_line = result_line_fmt.format(return_name=return_name)
            examplecode_lines.append(result_line)
        examplecode_lines.append(result_print)

    # TODO: infer this
    if is_show_func:
        examplecode_lines += [
            'ut.quit_if_noshow()',
            'import plottool as pt',
            'ut.show_if_requested()',
        ]

    examplecode = '\n'.join(examplecode_lines)
    return examplecode