def _recurse_config(parent_config, modules, f, prefix='<STR_LIT>'):
for module in modules:<EOL><INDENT>config_name = getattr(module, '<STR_LIT>', None)<EOL>if config_name is None:<EOL><INDENT>raise ProgrammerError('<STR_LIT>'<EOL>.format(module))<EOL><DEDENT>new_name = prefix + config_name<EOL>f(parent_config, config_name, new_name, module)<EOL>try:<EOL><INDENT>_recurse_config((parent_config or {}).get(config_name, None),<EOL>getattr(module, '<STR_LIT>', []),<EOL>f,<EOL>new_name + '<STR_LIT:.>')<EOL><DEDENT>except:<EOL><INDENT>logger.error('<STR_LIT>', module)<EOL>raise<EOL><DEDENT><DEDENT>return parent_config<EOL>
Walk through the module tree.

    This is a helper function for :func:`create_config_tree` and
    :func:`_walk_config`.  It calls `f` once for each module in the
    configuration tree with parameters `parent_config`, `config_name`,
    `prefix`, and `module`.  `parent_config[config_name]` may or may
    not exist (but could be populated, as :func:`create_config_tree`).
    If even the parent configuration doesn't exist, `parent_config`
    could be :const:`None`.

    :param dict parent_config: configuration dictionary holding
      configuration for `modules`, or maybe :const:`None`
    :param modules: modules or Configurable instances to use
    :type modules: iterable of :class:`~yakonfig.configurable.Configurable`
    :param f: callable to call on each module
    :param str prefix: prefix name of `parent_config`
    :return: `parent_config`