docs: def parse_import_names(sourcecode, top_level=True, fpath=None, branch=False):
      """
      Finds all function names in a file without importing it
  
      Args:
          sourcecode (str):
  
      Returns:
          list: func_names
  
      CommandLine:
          python -m utool.util_inspect parse_import_names
  
      References:
          https://stackoverflow.com/questions/20445733/how-to-tell-which-modules-have-been-imported-in-some-source-code
  
      Example:
          >>> # ENABLE_DOCTEST
          >>> from utool.util_inspect import *  # NOQA
          >>> import utool as ut
          >>> fpath = ut.util_inspect.__file__.replace('.pyc', '.py')
          >>> #fpath = ut.truepath('~/code/bintrees/bintrees/avltree.py')
          >>> sourcecode = ut.readfrom(fpath)
          >>> func_names = parse_import_names(sourcecode)
          >>> result = ('func_names = %s' % (ut.repr2(func_names),))
          >>> print(result)
      """
      import ast
      import_names = []
      if six.PY2:
          import utool as ut
          sourcecode = ut.ensure_unicode(sourcecode)
          encoded = sourcecode.encode('utf8')
          pt = ast.parse(encoded)
      else:
          pt = ast.parse(sourcecode)
  
      modules = []
  
      class ImportVisitor(ast.NodeVisitor):
  
          def _parse_alias_list(self, aliases):
              for alias in aliases:
                  if alias.asname is not None:
                      import_names.append(alias.asname)
                  else:
                      if '.' not in alias.name:
                          import_names.append(alias.name)
  
          def visit_Import(self, node):
              self._parse_alias_list(node.names)
              self.generic_visit(node)
  
              for alias in node.names:
                  modules.append(alias.name)
  
          def visit_ImportFrom(self, node):
              self._parse_alias_list(node.names)
              self.generic_visit(node)
  
              for alias in node.names:
                  prefix = ''
                  if node.level:
                      if fpath is not None:
                          from xdoctest import static_analysis as static
                          modparts = static.split_modpath(os.path.abspath(fpath))[1].replace('\\', '/').split('/')
                          parts = modparts[:-node.level]
                          # parts = os.path.split(static.split_modpath(os.path.abspath(fpath))[1])[:-node.level]
                          prefix = '.'.join(parts) + '.'
                          # prefix = '.'.join(os.path.split(fpath)[-node.level:]) + '.'
                      else:
                          prefix = '.' * node.level
                  # modules.append(node.level * '.' + node.module + '.' + alias.name)
                  # modules.append(prefix + node.module + '.' + alias.name)
                  modules.append(prefix + node.module)
  
          def visit_FunctionDef(self, node):
              # Ignore modules imported in functions
              if not top_level:
                  self.generic_visit(node)
                  # ast.NodeVisitor.generic_visit(self, node)
  
          def visit_ClassDef(self, node):
              if not top_level:
                  self.generic_visit(node)
                  # ast.NodeVisitor.generic_visit(self, node)
  
          def visit_If(self, node):
              if not branch:
                  # TODO: determine how to figure out if a name is in all branches
                  if not _node_is_main_if(node):
                      # Ignore the main statement
                      self.generic_visit(node)
      try:
          ImportVisitor().visit(pt)
      except Exception:
          pass
      return import_names, modules