Set up global configuration for command-line tools.

    `modules` is an iterable of
    :class:`yakonfig.Configurable` objects, or anything
    equivalently typed.  This function iterates through those objects
    and calls
    :meth:`~yakonfig.Configurable.add_arguments` on
    each to build up a complete list of command-line arguments, then
    calls :meth:`argparse.ArgumentParser.parse_args` to actually
    process the command line.  This produces a configuration that is a
    combination of all default values declared by all modules;
    configuration specified in ``--config`` arguments; and overriding
    configuration values specified in command-line arguments.

    This returns the :class:`argparse.Namespace` object, in case the
    application has defined its own command-line parameters and
    needs to process them.  The new global configuration can be
    obtained via :func:`yakonfig.get_global_config`.

    :param argparse.ArgumentParser parser: application-provided
      argument parser
    :param modules: modules or Configurable instances to use
    :type modules: iterable of :class:`~yakonfig.Configurable`
    :param args: command-line options, or `None` to use `sys.argv`
    :return: the new global configuration

def parse_args(parser, modules, args=None):
    """Set up global configuration for command-line tools.

    `modules` is an iterable of
    :class:`yakonfig.Configurable` objects, or anything
    equivalently typed.  This function iterates through those objects
    and calls
    :meth:`~yakonfig.Configurable.add_arguments` on
    each to build up a complete list of command-line arguments, then
    calls :meth:`argparse.ArgumentParser.parse_args` to actually
    process the command line.  This produces a configuration that is a
    combination of all default values declared by all modules;
    configuration specified in ``--config`` arguments; and overriding
    configuration values specified in command-line arguments.

    This returns the :class:`argparse.Namespace` object, in case the
    application has defined its own command-line parameters and
    needs to process them.  The new global configuration can be
    obtained via :func:`yakonfig.get_global_config`.

    :param argparse.ArgumentParser parser: application-provided
      argument parser
    :param modules: modules or Configurable instances to use
    :type modules: iterable of :class:`~yakonfig.Configurable`
    :param args: command-line options, or `None` to use `sys.argv`
    :return: the new global configuration

    """
    collect_add_argparse(parser, modules)
    namespace = parser.parse_args(args)
    try:
        do_dump_config = getattr(namespace, 'dump_config', None)
        set_default_config(modules, params=vars(namespace),
                           validate=not do_dump_config)
        if do_dump_config:
            if namespace.dump_config == 'full':
                to_dump = get_global_config()
            elif namespace.dump_config == 'default':
                to_dump = assemble_default_config(modules)
            else:  # 'effective'
                to_dump = diff_config(assemble_default_config(modules),
                                      get_global_config())
            yaml_mod.dump(to_dump, sys.stdout)
            parser.exit()
    except ConfigurationError as e:
        parser.error(e)
    return namespace