def _load_config(self, path):
        '''
        Read the configuration under a specific path
        and return the object.
        '''
        config = {}
        log.debug('Reading configuration from %s', path)
        if not os.path.isdir(path):
            msg = (
                'Unable to read from {path}: '
                'the directory does not exist!'
            ).format(path=path)
            log.error(msg)
            raise IOError(msg)
        # The directory tree should look like the following:
        # .
        # ├── __init__.py
        # ├── eos
        # │   └── init.yml
        # ├── iosxr
        # │   └── __init__.py
        # ├── junos
        # │   └── init.yml
        # │   └── bgp_read_message.py
        # │   └── BGP_PREFIX_THRESH_EXCEEDED.py
        # └── nxos
        #     └── init.yml
        os_subdirs = [sdpath[0] for sdpath in os.walk(path)][1:]
        if not os_subdirs:
            log.error('%s does not contain any OS subdirectories', path)
        for os_dir in os_subdirs:
            os_name = os.path.split(os_dir)[1]  # the network OS name
            if os_name.startswith('__'):
                log.debug('Ignoring %s', os_name)
                continue
            if not self._whitelist_blacklist(os_name):
                log.debug('Not building config for %s (whitelist-blacklist logic)', os_name)
                # Ignore devices that are not in the whitelist (if defined),
                #   or those operating systems that are on the blacklist.
                # This way we can prevent starting unwanted sub-processes.
                continue
            log.debug('Building config for %s:', os_name)
            log.debug('='*40)
            if os_name not in config:
                config[os_name] = {}
            files = os.listdir(os_dir)
            # Read all files under the OS dir
            for file_ in files:
                log.debug('Inspecting %s', file_)
                file_name, file_extension = os.path.splitext(file_)
                file_extension = file_extension.replace('.', '')
                filepath = os.path.join(os_dir, file_)
                comment = ''
                if file_extension in ('yml', 'yaml'):
                    try:
                        log.debug('Loading %s as YAML', file_)
                        with open(filepath, 'r') as fstream:
                            cfg = yaml.load(fstream)
                            # Reposition at the top and read the comments.
                            if file_name not in CONFIG.OS_INIT_FILENAMES:
                                # If the file name is not a profile init.
                                fstream.seek(0)
                                comment = self._extract_yaml_docstring(fstream)
                                if 'messages' in cfg:
                                    for message in cfg['messages']:
                                        message['__doc__'] = comment
                            napalm_logs.utils.dictupdate(config[os_name], cfg)
                    except yaml.YAMLError as yamlexc:
                        log.error('Invalid YAML file: %s', filepath, exc_info=True)
                        if file_name in CONFIG.OS_INIT_FILENAMES:
                            # Raise exception and break only when the init file is borked
                            #   otherwise, it will try loading best efforts.
                            raise IOError(yamlexc)
                elif file_extension == 'py':
                    log.debug('Lazy loading Python module %s', file_)
                    mod_fp, mod_file, mod_data = imp.find_module(file_name, [os_dir])
                    mod = imp.load_module(file_name, mod_fp, mod_file, mod_data)
                    if file_name in CONFIG.OS_INIT_FILENAMES:
                        # Init file defined as Python module
                        log.debug('%s seems to be a Python profiler', filepath)
                        # Init files require to define the `extract` function.
                        # Sample init file:
                        # def extract(message):
                        #     return {'tag': 'A_TAG', 'host': 'hostname'}
                        if hasattr(mod, CONFIG.INIT_RUN_FUN) and\
                           hasattr(getattr(mod, CONFIG.INIT_RUN_FUN), '__call__'):
                            # if extract is defined and is callable
                            if 'prefixes' not in config[os_name]:
                                config[os_name]['prefixes'] = []
                            config[os_name]['prefixes'].append({
                                'values': {'tag': ''},
                                'line': '',
                                '__python_fun__': getattr(mod, CONFIG.INIT_RUN_FUN),
                                '__python_mod__': filepath  # Will be used for debugging
                            })
                            log.info('Adding the prefix function defined under %s to %s',
                                     filepath, os_name)
                        elif file_name != '__init__':
                            # If __init__.py does not have the extractor function, no problem.
                            log.warning('%s does not have the "%s" function defined. Ignoring.',
                                        filepath, CONFIG.INIT_RUN_FUN)
                    else:
                        # Other python files require the `emit` function.
                        if hasattr(mod, '__tag__'):
                            mod_tag = getattr(mod, '__tag__')
                        else:
                            log.info('%s does not have __tag__, defaulting the tag to %s', filepath, file_name)
                            mod_tag = file_name
                        if hasattr(mod, '__error__'):
                            mod_err = getattr(mod, '__error__')
                        else:
                            log.info('%s does not have __error__, defaulting the error to %s', filepath, file_name)
                            mod_err = file_name
                        if hasattr(mod, '__match_on__'):
                            err_match = getattr(mod, '__match_on__')
                        else:
                            err_match = 'tag'
                        model = CONFIG.OPEN_CONFIG_NO_MODEL
                        if hasattr(mod, '__yang_model__'):
                            model = getattr(mod, '__yang_model__')
                        log.debug('Mathing on %s', err_match)
                        if hasattr(mod, CONFIG.CONFIG_RUN_FUN) and\
                           hasattr(getattr(mod, CONFIG.CONFIG_RUN_FUN), '__call__'):
                            log.debug('Adding %s with tag:%s, error:%s, matching on:%s',
                                      file_, mod_tag, mod_err, err_match)
                            # the structure below must correspond to the VALID_CONFIG structure enforcement
                            if 'messages' not in config[os_name]:
                                config[os_name]['messages'] = []
                            config[os_name]['messages'].append({
                                'tag': mod_tag,
                                'error': mod_err,
                                'match_on': err_match,
                                '__doc__': mod.__doc__,
                                '__python_fun__': getattr(mod, CONFIG.CONFIG_RUN_FUN),
                                '__python_mod__': filepath,  # Will be used for debugging
                                'line': '',
                                'model': model,
                                'values': {},
                                'mapping': {'variables': {}, 'static': {}}
                            })
                        else:
                            log.warning('%s does not have the "%s" function defined. Ignoring.',
                                        filepath, CONFIG.CONFIG_RUN_FUN)
                else:
                    log.info('Ignoring %s (extension not allowed)', filepath)
            log.debug('-'*40)
        if not config:
            msg = 'Could not find proper configuration files under {path}'.format(path=path)
            log.error(msg)
            raise IOError(msg)
        log.debug('Complete config:')
        log.debug(config)
        log.debug('ConfigParserg size in bytes: %d', sys.getsizeof(config))
        return config
Read the configuration under a specific path
        and return the object.