docs: def find_module(self, module_name):
      """
      Attempts to find the module specified by *module_name* in the
      ModuleFinder's search path and returns a #ModuleInfo object.
  
      For builtin modules, the #ModuleInfo.filename will be None. Note that
      the #ModuleInfo.imported_from is not filled by this method. It is used
      with #ModuleFinder.iter_modules().
      """
  
      if not module_name:
        raise ValueError('empty module name')
      if module_name in sys.builtin_module_names:
        return ModuleInfo(module_name, None, 'builtin', [])
      if module_name in self.modules:
        return self.modules[module_name]
  
      parts = module_name.split('.')
      result = None
      for dirname in self.path:
        # TODO: Configurable behaviour for Python 2 where __init__.py is
        #       required and namespace packages are not automatically
        #       supported.
        script_file = os.path.join(dirname, os.sep.join(parts)) + '.py'
        if os.path.isfile(script_file):
          result = ModuleInfo(module_name, script_file, ModuleInfo.SRC)
          break
        package_file = os.path.join(dirname, os.sep.join(parts), '__init__.py')
        if os.path.isfile(package_file):
          result = ModuleInfo(module_name, package_file, ModuleInfo.SRC)
          break
  
        for suffix in self.native_suffixes:
          native_file = os.path.join(dirname, os.sep.join(parts)) + suffix
          if os.path.isfile(native_file):
            result = ModuleInfo(module_name, native_file, ModuleInfo.NATIVE)
            break
        if result:
          break
      else:
        return ModuleInfo(module_name, None, ModuleInfo.NOTFOUND)
  
      self.modules[module_name] = result
      return result