docs: def load_func_from_module(modname, funcname, verbose=True, moddir=None, modpath=None):
      r"""
      Args:
          modname (str):  module name
          funcname (str):  function name
          verbose (bool):  verbosity flag(Defaults to True)
          moddir (None): (Defaults to None)
  
      CommandLine:
          python -m utool.util_autogen load_func_from_module
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> # UNSTABLE_DOCTEST
          >>> from utool.util_autogen import *  # NOQA
          >>> import utool as ut
          >>> #modname = 'plottool.plots'
          >>> #funcname = 'multi_plot'
          >>> modname = 'utool.util_path'
          >>> funcname = 'checkpath'
          >>> verbose = True
          >>> moddir = None
          >>> func, module, error_str = load_func_from_module(modname, funcname, verbose, moddir)
          >>> source = ut.get_func_sourcecode(func, strip_docstr=True, strip_comments=True)
          >>> keyname = ut.named_field('keyname', ut.REGEX_VARNAME)
          >>> default = ut.named_field('default', '[\'\"A-Za-z_][A-Za-z0-9_\'\"]*')
          >>> pattern = re.escape('kwargs.get(\'') + keyname + re.escape('\',')
          >>> kwarg_keys = [match.groupdict()['keyname'] for match in re.finditer(pattern, source)]
      """
      import utool as ut
      from os.path import join
      import imp
      func = None
      module = None
      error_str = None
      print('modname = %r' % (modname,))
      print('funcname = %r' % (funcname,))
      print('moddir = %r' % (moddir,))
  
      try:
          from xdoctest import static_analysis as static
          from xdoctest import utils
          print('modpath = {!r}'.format(modpath))
      except ImportError:
          modpath = None
      else:
          if modpath is None:
              modpath = static.modname_to_modpath(modname)
              if modpath is None:
                  modname = modname.split('.')[-1]
                  if moddir is not None:
                      modpath = join(moddir, modname + '.py')
                      if not exists(modpath):
                          modpath = None
                  if modpath is None:
                      raise Exception('Cannot find modname={} in moddir={}'.format(modname, moddir))
          print('modpath = {!r}'.format(modpath))
          module = utils.import_module_from_path(modpath)
          print('module = {!r}'.format(module))
          try:
              func = eval('module.{}'.format(funcname))
          except AttributeError:
              imp.reload(module)
              func = eval('module.{}'.format(funcname))
          print('func = {!r}'.format(func))
          return func, module, error_str
  
      if not isinstance(modname, six.string_types):
          error_str = 'modname=%r is not a string. bad input' % (modname,)
      else:
          if False:
              # TODO: static analysis
              import jedi  # NOQA
              modpath = ut.util_import.get_modpath_from_modname(modname)
              script = jedi.Script(path=modpath)
              mod = script._get_module()
              # monkeypatch
              func.script = script
              func = None
              for name in mod.names_dict[funcname]:
                  if name.parent.type == 'funcdef':
                      func = name.parent
                      break
              return func, mod, error_str
              # ut.get_modpath_from_modname(modname)
          if module is None:
              try:
                  module = __import__(modname)
              except ImportError:
                  if moddir is not None:
                      #parts =
                      # There can be a weird double import error thing happening here
                      # Rectify the dots in the filename
                      module = ut.import_module_from_fpath(join(moddir, modname.split('.')[-1] + '.py'))
                  else:
                      raise
              #import inspect
              # try:
              #     imp.reload(module)
              # except Exception as ex:
              #     pass
          # if False:
          #     # Try removing pyc if it exists
          #     if module.__file__.endswith('.pyc'):
          #         ut.delete(module.__file__, verbose=False)
          #         try:
          #             module = __import__(modname)
          #         except ImportError:
          #             if moddir is not None:
          #                 module = ut.import_module_from_fpath(join(moddir, modname.split('.')[-1] + '.py'))
          #             else:
          #                 raise
          try:
              imp.reload(module)
          except Exception as ex:
              pass
          try:
              # FIXME: PYTHON 3
              execstr = ut.codeblock(
                  '''
                  try:
                      import {modname}
                      module = {modname}
                      #print('Trying to reload module=%r' % (module,))
                      imp.reload(module)
                  except Exception:
                      # If it fails maybe the module is not in the path
                      if moddir is not None:
                          try:
                              import imp
                              import os
                              orig_dir = os.getcwd()
                              os.chdir(moddir)
                              modname_str = '{modname}'
                              modinfo = imp.find_module(modname_str, [moddir])
                              module = imp.load_module(modname_str, *modinfo)
                              #print('loaded module=%r' % (module,))
                          except Exception as ex:
                              ut.printex(ex, 'failed to imp.load_module')
                              pass
                          finally:
                              os.chdir(orig_dir)
                  import imp
                  import utool as ut
                  imp.reload(ut.util_autogen)
                  imp.reload(ut.util_inspect)
                  try:
                      func = module.{funcname}
                  except AttributeError:
                      docstr = 'Could not find attribute funcname={funcname} in modname={modname} This might be a reloading issue'
                      imp.reload(module)
                  '''
              ).format(**locals())
              exec_locals = locals()
              exec_globals = globals()
              exec(execstr, exec_globals, exec_locals)
              func = exec_locals.get('func', None)
              module = exec_locals.get('module', None)
          except Exception as ex2:
              docstr = 'error ' + str(ex2)
              if verbose:
                  import utool as ut
                  #ut.printex(ex1, 'ex1')
                  ut.printex(ex2, 'ex2', tb=True)
              testcmd = 'python -c "import utool; print(utool.auto_docstr(\'%s\', \'%s\'))"' % (modname, funcname)
              error_str = ut.formatex(ex2, 'ex2', tb=True, keys=['modname', 'funcname', 'testcmd'])
              error_str += '---' + execstr
      return func, module, error_str